/** 
 * Kendo UI v2019.2.619 (http://www.telerik.com/kendo-ui)                                                                                                                                               
 * Copyright 2019 Progress Software Corporation and/or one of its subsidiaries or affiliates. All rights reserved.                                                                                      
 *                                                                                                                                                                                                      
 * Kendo UI commercial licenses may be obtained at                                                                                                                                                      
 * http://www.telerik.com/purchase/license-agreement/kendo-ui-complete                                                                                                                                  
 * If you do not own a commercial license, this file shall be governed by the trial license terms.                                                                                                      
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       

*/
(function (f, define) {
    define('kendo.core', ['jquery'], f);
}(function () {
    var __meta__ = {
        id: 'core',
        name: 'Core',
        category: 'framework',
        description: 'The core of the Kendo framework.'
    };
    (function ($, window, undefined) {
        var kendo = window.kendo = window.kendo || { cultures: {} }, extend = $.extend, each = $.each, isArray = $.isArray, proxy = $.proxy, noop = $.noop, math = Math, Template, JSON = window.JSON || {}, support = {}, percentRegExp = /%/, formatRegExp = /\{(\d+)(:[^\}]+)?\}/g, boxShadowRegExp = /(\d+(?:\.?)\d*)px\s*(\d+(?:\.?)\d*)px\s*(\d+(?:\.?)\d*)px\s*(\d+)?/i, numberRegExp = /^(\+|-?)\d+(\.?)\d*$/, FUNCTION = 'function', STRING = 'string', NUMBER = 'number', OBJECT = 'object', NULL = 'null', BOOLEAN = 'boolean', UNDEFINED = 'undefined', getterCache = {}, setterCache = {}, slice = [].slice, noDepricateExtend = function () {
                var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false;
                if (typeof target === 'boolean') {
                    deep = target;
                    target = arguments[i] || {};
                    i++;
                }
                if (typeof target !== 'object' && !jQuery.isFunction(target)) {
                    target = {};
                }
                if (i === length) {
                    target = this;
                    i--;
                }
                for (; i < length; i++) {
                    if ((options = arguments[i]) != null) {
                        for (name in options) {
                            if (name == 'filters' || name == 'concat' || name == ':') {
                                continue;
                            }
                            src = target[name];
                            copy = options[name];
                            if (target === copy) {
                                continue;
                            }
                            if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
                                if (copyIsArray) {
                                    copyIsArray = false;
                                    clone = src && jQuery.isArray(src) ? src : [];
                                } else {
                                    clone = src && jQuery.isPlainObject(src) ? src : {};
                                }
                                target[name] = noDepricateExtend(deep, clone, copy);
                            } else if (copy !== undefined) {
                                target[name] = copy;
                            }
                        }
                    }
                }
                return target;
            };
        kendo.version = '2019.2.619'.replace(/^\s+|\s+$/g, '');
        function Class() {
        }
        Class.extend = function (proto) {
            var base = function () {
                }, member, that = this, subclass = proto && proto.init ? proto.init : function () {
                    that.apply(this, arguments);
                }, fn;
            base.prototype = that.prototype;
            fn = subclass.fn = subclass.prototype = new base();
            for (member in proto) {
                if (proto[member] != null && proto[member].constructor === Object) {
                    fn[member] = extend(true, {}, base.prototype[member], proto[member]);
                } else {
                    fn[member] = proto[member];
                }
            }
            fn.constructor = subclass;
            subclass.extend = that.extend;
            return subclass;
        };
        Class.prototype._initOptions = function (options) {
            this.options = deepExtend({}, this.options, options);
        };
        var isFunction = kendo.isFunction = function (fn) {
            return typeof fn === 'function';
        };
        var preventDefault = function () {
            this._defaultPrevented = true;
        };
        var isDefaultPrevented = function () {
            return this._defaultPrevented === true;
        };
        var Observable = Class.extend({
            init: function () {
                this._events = {};
            },
            bind: function (eventName, handlers, one) {
                var that = this, idx, eventNames = typeof eventName === STRING ? [eventName] : eventName, length, original, handler, handlersIsFunction = typeof handlers === FUNCTION, events;
                if (handlers === undefined) {
                    for (idx in eventName) {
                        that.bind(idx, eventName[idx]);
                    }
                    return that;
                }
                for (idx = 0, length = eventNames.length; idx < length; idx++) {
                    eventName = eventNames[idx];
                    handler = handlersIsFunction ? handlers : handlers[eventName];
                    if (handler) {
                        if (one) {
                            original = handler;
                            handler = function () {
                                that.unbind(eventName, handler);
                                original.apply(that, arguments);
                            };
                            handler.original = original;
                        }
                        events = that._events[eventName] = that._events[eventName] || [];
                        events.push(handler);
                    }
                }
                return that;
            },
            one: function (eventNames, handlers) {
                return this.bind(eventNames, handlers, true);
            },
            first: function (eventName, handlers) {
                var that = this, idx, eventNames = typeof eventName === STRING ? [eventName] : eventName, length, handler, handlersIsFunction = typeof handlers === FUNCTION, events;
                for (idx = 0, length = eventNames.length; idx < length; idx++) {
                    eventName = eventNames[idx];
                    handler = handlersIsFunction ? handlers : handlers[eventName];
                    if (handler) {
                        events = that._events[eventName] = that._events[eventName] || [];
                        events.unshift(handler);
                    }
                }
                return that;
            },
            trigger: function (eventName, e) {
                var that = this, events = that._events[eventName], idx, length;
                if (events) {
                    e = e || {};
                    e.sender = that;
                    e._defaultPrevented = false;
                    e.preventDefault = preventDefault;
                    e.isDefaultPrevented = isDefaultPrevented;
                    events = events.slice();
                    for (idx = 0, length = events.length; idx < length; idx++) {
                        events[idx].call(that, e);
                    }
                    return e._defaultPrevented === true;
                }
                return false;
            },
            unbind: function (eventName, handler) {
                var that = this, events = that._events[eventName], idx;
                if (eventName === undefined) {
                    that._events = {};
                } else if (events) {
                    if (handler) {
                        for (idx = events.length - 1; idx >= 0; idx--) {
                            if (events[idx] === handler || events[idx].original === handler) {
                                events.splice(idx, 1);
                            }
                        }
                    } else {
                        that._events[eventName] = [];
                    }
                }
                return that;
            }
        });
        function compilePart(part, stringPart) {
            if (stringPart) {
                return '\'' + part.split('\'').join('\\\'').split('\\"').join('\\\\\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t') + '\'';
            } else {
                var first = part.charAt(0), rest = part.substring(1);
                if (first === '=') {
                    return '+(' + rest + ')+';
                } else if (first === ':') {
                    return '+$kendoHtmlEncode(' + rest + ')+';
                } else {
                    return ';' + part + ';$kendoOutput+=';
                }
            }
        }
        var argumentNameRegExp = /^\w+/, encodeRegExp = /\$\{([^}]*)\}/g, escapedCurlyRegExp = /\\\}/g, curlyRegExp = /__CURLY__/g, escapedSharpRegExp = /\\#/g, sharpRegExp = /__SHARP__/g, zeros = [
                '',
                '0',
                '00',
                '000',
                '0000'
            ];
        Template = {
            paramName: 'data',
            useWithBlock: true,
            render: function (template, data) {
                var idx, length, html = '';
                for (idx = 0, length = data.length; idx < length; idx++) {
                    html += template(data[idx]);
                }
                return html;
            },
            compile: function (template, options) {
                var settings = extend({}, this, options), paramName = settings.paramName, argumentName = paramName.match(argumentNameRegExp)[0], useWithBlock = settings.useWithBlock, functionBody = 'var $kendoOutput, $kendoHtmlEncode = kendo.htmlEncode;', fn, parts, idx;
                if (isFunction(template)) {
                    return template;
                }
                functionBody += useWithBlock ? 'with(' + paramName + '){' : '';
                functionBody += '$kendoOutput=';
                parts = template.replace(escapedCurlyRegExp, '__CURLY__').replace(encodeRegExp, '#=$kendoHtmlEncode($1)#').replace(curlyRegExp, '}').replace(escapedSharpRegExp, '__SHARP__').split('#');
                for (idx = 0; idx < parts.length; idx++) {
                    functionBody += compilePart(parts[idx], idx % 2 === 0);
                }
                functionBody += useWithBlock ? ';}' : ';';
                functionBody += 'return $kendoOutput;';
                functionBody = functionBody.replace(sharpRegExp, '#');
                try {
                    fn = new Function(argumentName, functionBody);
                    fn._slotCount = Math.floor(parts.length / 2);
                    return fn;
                } catch (e) {
                    throw new Error(kendo.format('Invalid template:\'{0}\' Generated code:\'{1}\'', template, functionBody));
                }
            }
        };
        function pad(number, digits, end) {
            number = number + '';
            digits = digits || 2;
            end = digits - number.length;
            if (end) {
                return zeros[digits].substring(0, end) + number;
            }
            return number;
        }
        (function () {
            var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = {
                    '\b': '\\b',
                    '\t': '\\t',
                    '\n': '\\n',
                    '\f': '\\f',
                    '\r': '\\r',
                    '"': '\\"',
                    '\\': '\\\\'
                }, rep, toString = {}.toString;
            if (typeof Date.prototype.toJSON !== FUNCTION) {
                Date.prototype.toJSON = function () {
                    var that = this;
                    return isFinite(that.valueOf()) ? pad(that.getUTCFullYear(), 4) + '-' + pad(that.getUTCMonth() + 1) + '-' + pad(that.getUTCDate()) + 'T' + pad(that.getUTCHours()) + ':' + pad(that.getUTCMinutes()) + ':' + pad(that.getUTCSeconds()) + 'Z' : null;
                };
                String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function () {
                    return this.valueOf();
                };
            }
            function quote(string) {
                escapable.lastIndex = 0;
                return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
                    var c = meta[a];
                    return typeof c === STRING ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                }) + '"' : '"' + string + '"';
            }
            function str(key, holder) {
                var i, k, v, length, mind = gap, partial, value = holder[key], type;
                if (value && typeof value === OBJECT && typeof value.toJSON === FUNCTION) {
                    value = value.toJSON(key);
                }
                if (typeof rep === FUNCTION) {
                    value = rep.call(holder, key, value);
                }
                type = typeof value;
                if (type === STRING) {
                    return quote(value);
                } else if (type === NUMBER) {
                    return isFinite(value) ? String(value) : NULL;
                } else if (type === BOOLEAN || type === NULL) {
                    return String(value);
                } else if (type === OBJECT) {
                    if (!value) {
                        return NULL;
                    }
                    gap += indent;
                    partial = [];
                    if (toString.apply(value) === '[object Array]') {
                        length = value.length;
                        for (i = 0; i < length; i++) {
                            partial[i] = str(i, value) || NULL;
                        }
                        v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']';
                        gap = mind;
                        return v;
                    }
                    if (rep && typeof rep === OBJECT) {
                        length = rep.length;
                        for (i = 0; i < length; i++) {
                            if (typeof rep[i] === STRING) {
                                k = rep[i];
                                v = str(k, value);
                                if (v) {
                                    partial.push(quote(k) + (gap ? ': ' : ':') + v);
                                }
                            }
                        }
                    } else {
                        for (k in value) {
                            if (Object.hasOwnProperty.call(value, k)) {
                                v = str(k, value);
                                if (v) {
                                    partial.push(quote(k) + (gap ? ': ' : ':') + v);
                                }
                            }
                        }
                    }
                    v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}';
                    gap = mind;
                    return v;
                }
            }
            if (typeof JSON.stringify !== FUNCTION) {
                JSON.stringify = function (value, replacer, space) {
                    var i;
                    gap = '';
                    indent = '';
                    if (typeof space === NUMBER) {
                        for (i = 0; i < space; i += 1) {
                            indent += ' ';
                        }
                    } else if (typeof space === STRING) {
                        indent = space;
                    }
                    rep = replacer;
                    if (replacer && typeof replacer !== FUNCTION && (typeof replacer !== OBJECT || typeof replacer.length !== NUMBER)) {
                        throw new Error('JSON.stringify');
                    }
                    return str('', { '': value });
                };
            }
        }());
        (function () {
            var dateFormatRegExp = /dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|HH|H|hh|h|mm|m|fff|ff|f|tt|ss|s|zzz|zz|z|"[^"]*"|'[^']*'/g, standardFormatRegExp = /^(n|c|p|e)(\d*)$/i, literalRegExp = /(\\.)|(['][^']*[']?)|(["][^"]*["]?)/g, commaRegExp = /\,/g, EMPTY = '', POINT = '.', COMMA = ',', SHARP = '#', ZERO = '0', PLACEHOLDER = '??', EN = 'en-US', objectToString = {}.toString;
            kendo.cultures['en-US'] = {
                name: EN,
                numberFormat: {
                    pattern: ['-n'],
                    decimals: 2,
                    ',': ',',
                    '.': '.',
                    groupSize: [3],
                    percent: {
                        pattern: [
                            '-n %',
                            'n %'
                        ],
                        decimals: 2,
                        ',': ',',
                        '.': '.',
                        groupSize: [3],
                        symbol: '%'
                    },
                    currency: {
                        name: 'US Dollar',
                        abbr: 'USD',
                        pattern: [
                            '($n)',
                            '$n'
                        ],
                        decimals: 2,
                        ',': ',',
                        '.': '.',
                        groupSize: [3],
                        symbol: '$'
                    }
                },
                calendars: {
                    standard: {
                        days: {
                            names: [
                                'Sunday',
                                'Monday',
                                'Tuesday',
                                'Wednesday',
                                'Thursday',
                                'Friday',
                                'Saturday'
                            ],
                            namesAbbr: [
                                'Sun',
                                'Mon',
                                'Tue',
                                'Wed',
                                'Thu',
                                'Fri',
                                'Sat'
                            ],
                            namesShort: [
                                'Su',
                                'Mo',
                                'Tu',
                                'We',
                                'Th',
                                'Fr',
                                'Sa'
                            ]
                        },
                        months: {
                            names: [
                                'January',
                                'February',
                                'March',
                                'April',
                                'May',
                                'June',
                                'July',
                                'August',
                                'September',
                                'October',
                                'November',
                                'December'
                            ],
                            namesAbbr: [
                                'Jan',
                                'Feb',
                                'Mar',
                                'Apr',
                                'May',
                                'Jun',
                                'Jul',
                                'Aug',
                                'Sep',
                                'Oct',
                                'Nov',
                                'Dec'
                            ]
                        },
                        AM: [
                            'AM',
                            'am',
                            'AM'
                        ],
                        PM: [
                            'PM',
                            'pm',
                            'PM'
                        ],
                        patterns: {
                            d: 'M/d/yyyy',
                            D: 'dddd, MMMM dd, yyyy',
                            F: 'dddd, MMMM dd, yyyy h:mm:ss tt',
                            g: 'M/d/yyyy h:mm tt',
                            G: 'M/d/yyyy h:mm:ss tt',
                            m: 'MMMM dd',
                            M: 'MMMM dd',
                            s: 'yyyy\'-\'MM\'-\'ddTHH\':\'mm\':\'ss',
                            t: 'h:mm tt',
                            T: 'h:mm:ss tt',
                            u: 'yyyy\'-\'MM\'-\'dd HH\':\'mm\':\'ss\'Z\'',
                            y: 'MMMM, yyyy',
                            Y: 'MMMM, yyyy'
                        },
                        '/': '/',
                        ':': ':',
                        firstDay: 0,
                        twoDigitYearMax: 2029
                    }
                }
            };
            function findCulture(culture) {
                if (culture) {
                    if (culture.numberFormat) {
                        return culture;
                    }
                    if (typeof culture === STRING) {
                        var cultures = kendo.cultures;
                        return cultures[culture] || cultures[culture.split('-')[0]] || null;
                    }
                    return null;
                }
                return null;
            }
            function getCulture(culture) {
                if (culture) {
                    culture = findCulture(culture);
                }
                return culture || kendo.cultures.current;
            }
            kendo.culture = function (cultureName) {
                var cultures = kendo.cultures, culture;
                if (cultureName !== undefined) {
                    culture = findCulture(cultureName) || cultures[EN];
                    culture.calendar = culture.calendars.standard;
                    cultures.current = culture;
                } else {
                    return cultures.current;
                }
            };
            kendo.findCulture = findCulture;
            kendo.getCulture = getCulture;
            kendo.culture(EN);
            function formatDate(date, format, culture) {
                culture = getCulture(culture);
                var calendar = culture.calendars.standard, days = calendar.days, months = calendar.months;
                format = calendar.patterns[format] || format;
                return format.replace(dateFormatRegExp, function (match) {
                    var minutes;
                    var result;
                    var sign;
                    if (match === 'd') {
                        result = date.getDate();
                    } else if (match === 'dd') {
                        result = pad(date.getDate());
                    } else if (match === 'ddd') {
                        result = days.namesAbbr[date.getDay()];
                    } else if (match === 'dddd') {
                        result = days.names[date.getDay()];
                    } else if (match === 'M') {
                        result = date.getMonth() + 1;
                    } else if (match === 'MM') {
                        result = pad(date.getMonth() + 1);
                    } else if (match === 'MMM') {
                        result = months.namesAbbr[date.getMonth()];
                    } else if (match === 'MMMM') {
                        result = months.names[date.getMonth()];
                    } else if (match === 'yy') {
                        result = pad(date.getFullYear() % 100);
                    } else if (match === 'yyyy') {
                        result = pad(date.getFullYear(), 4);
                    } else if (match === 'h') {
                        result = date.getHours() % 12 || 12;
                    } else if (match === 'hh') {
                        result = pad(date.getHours() % 12 || 12);
                    } else if (match === 'H') {
                        result = date.getHours();
                    } else if (match === 'HH') {
                        result = pad(date.getHours());
                    } else if (match === 'm') {
                        result = date.getMinutes();
                    } else if (match === 'mm') {
                        result = pad(date.getMinutes());
                    } else if (match === 's') {
                        result = date.getSeconds();
                    } else if (match === 'ss') {
                        result = pad(date.getSeconds());
                    } else if (match === 'f') {
                        result = math.floor(date.getMilliseconds() / 100);
                    } else if (match === 'ff') {
                        result = date.getMilliseconds();
                        if (result > 99) {
                            result = math.floor(result / 10);
                        }
                        result = pad(result);
                    } else if (match === 'fff') {
                        result = pad(date.getMilliseconds(), 3);
                    } else if (match === 'tt') {
                        result = date.getHours() < 12 ? calendar.AM[0] : calendar.PM[0];
                    } else if (match === 'zzz') {
                        minutes = date.getTimezoneOffset();
                        sign = minutes < 0;
                        result = math.abs(minutes / 60).toString().split('.')[0];
                        minutes = math.abs(minutes) - result * 60;
                        result = (sign ? '+' : '-') + pad(result);
                        result += ':' + pad(minutes);
                    } else if (match === 'zz' || match === 'z') {
                        result = date.getTimezoneOffset() / 60;
                        sign = result < 0;
                        result = math.abs(result).toString().split('.')[0];
                        result = (sign ? '+' : '-') + (match === 'zz' ? pad(result) : result);
                    }
                    return result !== undefined ? result : match.slice(1, match.length - 1);
                });
            }
            function formatNumber(number, format, culture) {
                culture = getCulture(culture);
                var numberFormat = culture.numberFormat, decimal = numberFormat[POINT], precision = numberFormat.decimals, pattern = numberFormat.pattern[0], literals = [], symbol, isCurrency, isPercent, customPrecision, formatAndPrecision, negative = number < 0, integer, fraction, integerLength, fractionLength, replacement = EMPTY, value = EMPTY, idx, length, ch, hasGroup, hasNegativeFormat, decimalIndex, sharpIndex, zeroIndex, hasZero, hasSharp, percentIndex, currencyIndex, startZeroIndex, start = -1, end;
                if (number === undefined) {
                    return EMPTY;
                }
                if (!isFinite(number)) {
                    return number;
                }
                if (!format) {
                    return culture.name.length ? number.toLocaleString() : number.toString();
                }
                formatAndPrecision = standardFormatRegExp.exec(format);
                if (formatAndPrecision) {
                    format = formatAndPrecision[1].toLowerCase();
                    isCurrency = format === 'c';
                    isPercent = format === 'p';
                    if (isCurrency || isPercent) {
                        numberFormat = isCurrency ? numberFormat.currency : numberFormat.percent;
                        decimal = numberFormat[POINT];
                        precision = numberFormat.decimals;
                        symbol = numberFormat.symbol;
                        pattern = numberFormat.pattern[negative ? 0 : 1];
                    }
                    customPrecision = formatAndPrecision[2];
                    if (customPrecision) {
                        precision = +customPrecision;
                    }
                    if (format === 'e') {
                        var exp = customPrecision ? number.toExponential(precision) : number.toExponential();
                        return exp.replace(POINT, numberFormat[POINT]);
                    }
                    if (isPercent) {
                        number *= 100;
                    }
                    number = round(number, precision);
                    negative = number < 0;
                    number = number.split(POINT);
                    integer = number[0];
                    fraction = number[1];
                    if (negative) {
                        integer = integer.substring(1);
                    }
                    value = groupInteger(integer, 0, integer.length, numberFormat);
                    if (fraction) {
                        value += decimal + fraction;
                    }
                    if (format === 'n' && !negative) {
                        return value;
                    }
                    number = EMPTY;
                    for (idx = 0, length = pattern.length; idx < length; idx++) {
                        ch = pattern.charAt(idx);
                        if (ch === 'n') {
                            number += value;
                        } else if (ch === '$' || ch === '%') {
                            number += symbol;
                        } else {
                            number += ch;
                        }
                    }
                    return number;
                }
                if (format.indexOf('\'') > -1 || format.indexOf('"') > -1 || format.indexOf('\\') > -1) {
                    format = format.replace(literalRegExp, function (match) {
                        var quoteChar = match.charAt(0).replace('\\', ''), literal = match.slice(1).replace(quoteChar, '');
                        literals.push(literal);
                        return PLACEHOLDER;
                    });
                }
                format = format.split(';');
                if (negative && format[1]) {
                    format = format[1];
                    hasNegativeFormat = true;
                } else if (number === 0 && format[2]) {
                    format = format[2];
                    if (format.indexOf(SHARP) == -1 && format.indexOf(ZERO) == -1) {
                        return format;
                    }
                } else {
                    format = format[0];
                }
                percentIndex = format.indexOf('%');
                currencyIndex = format.indexOf('$');
                isPercent = percentIndex != -1;
                isCurrency = currencyIndex != -1;
                if (isPercent) {
                    number *= 100;
                }
                if (isCurrency && format[currencyIndex - 1] === '\\') {
                    format = format.split('\\').join('');
                    isCurrency = false;
                }
                if (isCurrency || isPercent) {
                    numberFormat = isCurrency ? numberFormat.currency : numberFormat.percent;
                    decimal = numberFormat[POINT];
                    precision = numberFormat.decimals;
                    symbol = numberFormat.symbol;
                }
                hasGroup = format.indexOf(COMMA) > -1;
                if (hasGroup) {
                    format = format.replace(commaRegExp, EMPTY);
                }
                decimalIndex = format.indexOf(POINT);
                length = format.length;
                if (decimalIndex != -1) {
                    fraction = number.toString().split('e');
                    if (fraction[1]) {
                        fraction = round(number, Math.abs(fraction[1]));
                    } else {
                        fraction = fraction[0];
                    }
                    fraction = fraction.split(POINT)[1] || EMPTY;
                    zeroIndex = format.lastIndexOf(ZERO) - decimalIndex;
                    sharpIndex = format.lastIndexOf(SHARP) - decimalIndex;
                    hasZero = zeroIndex > -1;
                    hasSharp = sharpIndex > -1;
                    idx = fraction.length;
                    if (!hasZero && !hasSharp) {
                        format = format.substring(0, decimalIndex) + format.substring(decimalIndex + 1);
                        length = format.length;
                        decimalIndex = -1;
                        idx = 0;
                    }
                    if (hasZero && zeroIndex > sharpIndex) {
                        idx = zeroIndex;
                    } else if (sharpIndex > zeroIndex) {
                        if (hasSharp && idx > sharpIndex) {
                            var rounded = round(number, sharpIndex, negative);
                            while (rounded.charAt(rounded.length - 1) === ZERO && sharpIndex > 0 && sharpIndex > zeroIndex) {
                                sharpIndex--;
                                rounded = round(number, sharpIndex, negative);
                            }
                            idx = sharpIndex;
                        } else if (hasZero && idx < zeroIndex) {
                            idx = zeroIndex;
                        }
                    }
                }
                number = round(number, idx, negative);
                sharpIndex = format.indexOf(SHARP);
                startZeroIndex = zeroIndex = format.indexOf(ZERO);
                if (sharpIndex == -1 && zeroIndex != -1) {
                    start = zeroIndex;
                } else if (sharpIndex != -1 && zeroIndex == -1) {
                    start = sharpIndex;
                } else {
                    start = sharpIndex > zeroIndex ? zeroIndex : sharpIndex;
                }
                sharpIndex = format.lastIndexOf(SHARP);
                zeroIndex = format.lastIndexOf(ZERO);
                if (sharpIndex == -1 && zeroIndex != -1) {
                    end = zeroIndex;
                } else if (sharpIndex != -1 && zeroIndex == -1) {
                    end = sharpIndex;
                } else {
                    end = sharpIndex > zeroIndex ? sharpIndex : zeroIndex;
                }
                if (start == length) {
                    end = start;
                }
                if (start != -1) {
                    value = number.toString().split(POINT);
                    integer = value[0];
                    fraction = value[1] || EMPTY;
                    integerLength = integer.length;
                    fractionLength = fraction.length;
                    if (negative && number * -1 >= 0) {
                        negative = false;
                    }
                    number = format.substring(0, start);
                    if (negative && !hasNegativeFormat) {
                        number += '-';
                    }
                    for (idx = start; idx < length; idx++) {
                        ch = format.charAt(idx);
                        if (decimalIndex == -1) {
                            if (end - idx < integerLength) {
                                number += integer;
                                break;
                            }
                        } else {
                            if (zeroIndex != -1 && zeroIndex < idx) {
                                replacement = EMPTY;
                            }
                            if (decimalIndex - idx <= integerLength && decimalIndex - idx > -1) {
                                number += integer;
                                idx = decimalIndex;
                            }
                            if (decimalIndex === idx) {
                                number += (fraction ? decimal : EMPTY) + fraction;
                                idx += end - decimalIndex + 1;
                                continue;
                            }
                        }
                        if (ch === ZERO) {
                            number += ch;
                            replacement = ch;
                        } else if (ch === SHARP) {
                            number += replacement;
                        }
                    }
                    if (hasGroup) {
                        number = groupInteger(number, start + (negative && !hasNegativeFormat ? 1 : 0), Math.max(end, integerLength + start), numberFormat);
                    }
                    if (end >= start) {
                        number += format.substring(end + 1);
                    }
                    if (isCurrency || isPercent) {
                        value = EMPTY;
                        for (idx = 0, length = number.length; idx < length; idx++) {
                            ch = number.charAt(idx);
                            value += ch === '$' || ch === '%' ? symbol : ch;
                        }
                        number = value;
                    }
                    length = literals.length;
                    if (length) {
                        for (idx = 0; idx < length; idx++) {
                            number = number.replace(PLACEHOLDER, literals[idx]);
                        }
                    }
                }
                return number;
            }
            var groupInteger = function (number, start, end, numberFormat) {
                var decimalIndex = number.indexOf(numberFormat[POINT]);
                var groupSizes = numberFormat.groupSize.slice();
                var groupSize = groupSizes.shift();
                var integer, integerLength;
                var idx, parts, value;
                var newGroupSize;
                end = decimalIndex !== -1 ? decimalIndex : end + 1;
                integer = number.substring(start, end);
                integerLength = integer.length;
                if (integerLength >= groupSize) {
                    idx = integerLength;
                    parts = [];
                    while (idx > -1) {
                        value = integer.substring(idx - groupSize, idx);
                        if (value) {
                            parts.push(value);
                        }
                        idx -= groupSize;
                        newGroupSize = groupSizes.shift();
                        groupSize = newGroupSize !== undefined ? newGroupSize : groupSize;
                        if (groupSize === 0) {
                            if (idx > 0) {
                                parts.push(integer.substring(0, idx));
                            }
                            break;
                        }
                    }
                    integer = parts.reverse().join(numberFormat[COMMA]);
                    number = number.substring(0, start) + integer + number.substring(end);
                }
                return number;
            };
            var round = function (value, precision, negative) {
                precision = precision || 0;
                value = value.toString().split('e');
                value = Math.round(+(value[0] + 'e' + (value[1] ? +value[1] + precision : precision)));
                if (negative) {
                    value = -value;
                }
                value = value.toString().split('e');
                value = +(value[0] + 'e' + (value[1] ? +value[1] - precision : -precision));
                return value.toFixed(Math.min(precision, 20));
            };
            var toString = function (value, fmt, culture) {
                if (fmt) {
                    if (objectToString.call(value) === '[object Date]') {
                        return formatDate(value, fmt, culture);
                    } else if (typeof value === NUMBER) {
                        return formatNumber(value, fmt, culture);
                    }
                }
                return value !== undefined ? value : '';
            };
            kendo.format = function (fmt) {
                var values = arguments;
                return fmt.replace(formatRegExp, function (match, index, placeholderFormat) {
                    var value = values[parseInt(index, 10) + 1];
                    return toString(value, placeholderFormat ? placeholderFormat.substring(1) : '');
                });
            };
            kendo._extractFormat = function (format) {
                if (format.slice(0, 3) === '{0:') {
                    format = format.slice(3, format.length - 1);
                }
                return format;
            };
            kendo._activeElement = function () {
                try {
                    return document.activeElement;
                } catch (e) {
                    return document.documentElement.activeElement;
                }
            };
            kendo._round = round;
            kendo._outerWidth = function (element, includeMargin) {
                return $(element).outerWidth(includeMargin || false) || 0;
            };
            kendo._outerHeight = function (element, includeMargin) {
                return $(element).outerHeight(includeMargin || false) || 0;
            };
            kendo.toString = toString;
        }());
        (function () {
            var nonBreakingSpaceRegExp = /\u00A0/g, exponentRegExp = /[eE][\-+]?[0-9]+/, shortTimeZoneRegExp = /[+|\-]\d{1,2}/, longTimeZoneRegExp = /[+|\-]\d{1,2}:?\d{2}/, dateRegExp = /^\/Date\((.*?)\)\/$/, offsetRegExp = /[+-]\d*/, FORMATS_SEQUENCE = [
                    [],
                    [
                        'G',
                        'g',
                        'F'
                    ],
                    [
                        'D',
                        'd',
                        'y',
                        'm',
                        'T',
                        't'
                    ]
                ], STANDARD_FORMATS = [
                    [
                        'yyyy-MM-ddTHH:mm:ss.fffffffzzz',
                        'yyyy-MM-ddTHH:mm:ss.fffffff',
                        'yyyy-MM-ddTHH:mm:ss.fffzzz',
                        'yyyy-MM-ddTHH:mm:ss.fff',
                        'ddd MMM dd yyyy HH:mm:ss',
                        'yyyy-MM-ddTHH:mm:sszzz',
                        'yyyy-MM-ddTHH:mmzzz',
                        'yyyy-MM-ddTHH:mmzz',
                        'yyyy-MM-ddTHH:mm:ss',
                        'yyyy-MM-dd HH:mm:ss',
                        'yyyy/MM/dd HH:mm:ss'
                    ],
                    [
                        'yyyy-MM-ddTHH:mm',
                        'yyyy-MM-dd HH:mm',
                        'yyyy/MM/dd HH:mm'
                    ],
                    [
                        'yyyy/MM/dd',
                        'yyyy-MM-dd',
                        'HH:mm:ss',
                        'HH:mm'
                    ]
                ], numberRegExp = {
                    2: /^\d{1,2}/,
                    3: /^\d{1,3}/,
                    4: /^\d{4}/
                }, objectToString = {}.toString;
            function outOfRange(value, start, end) {
                return !(value >= start && value <= end);
            }
            function designatorPredicate(designator) {
                return designator.charAt(0);
            }
            function mapDesignators(designators) {
                return $.map(designators, designatorPredicate);
            }
            function adjustDST(date, hours) {
                if (!hours && date.getHours() === 23) {
                    date.setHours(date.getHours() + 2);
                }
            }
            function lowerArray(data) {
                var idx = 0, length = data.length, array = [];
                for (; idx < length; idx++) {
                    array[idx] = (data[idx] + '').toLowerCase();
                }
                return array;
            }
            function lowerLocalInfo(localInfo) {
                var newLocalInfo = {}, property;
                for (property in localInfo) {
                    newLocalInfo[property] = lowerArray(localInfo[property]);
                }
                return newLocalInfo;
            }
            function parseExact(value, format, culture, strict) {
                if (!value) {
                    return null;
                }
                var lookAhead = function (match) {
                        var i = 0;
                        while (format[idx] === match) {
                            i++;
                            idx++;
                        }
                        if (i > 0) {
                            idx -= 1;
                        }
                        return i;
                    }, getNumber = function (size) {
                        var rg = numberRegExp[size] || new RegExp('^\\d{1,' + size + '}'), match = value.substr(valueIdx, size).match(rg);
                        if (match) {
                            match = match[0];
                            valueIdx += match.length;
                            return parseInt(match, 10);
                        }
                        return null;
                    }, getIndexByName = function (names, lower) {
                        var i = 0, length = names.length, name, nameLength, matchLength = 0, matchIdx = 0, subValue;
                        for (; i < length; i++) {
                            name = names[i];
                            nameLength = name.length;
                            subValue = value.substr(valueIdx, nameLength);
                            if (lower) {
                                subValue = subValue.toLowerCase();
                            }
                            if (subValue == name && nameLength > matchLength) {
                                matchLength = nameLength;
                                matchIdx = i;
                            }
                        }
                        if (matchLength) {
                            valueIdx += matchLength;
                            return matchIdx + 1;
                        }
                        return null;
                    }, checkLiteral = function () {
                        var result = false;
                        if (value.charAt(valueIdx) === format[idx]) {
                            valueIdx++;
                            result = true;
                        }
                        return result;
                    }, calendar = culture.calendars.standard, year = null, month = null, day = null, hours = null, minutes = null, seconds = null, milliseconds = null, idx = 0, valueIdx = 0, literal = false, date = new Date(), twoDigitYearMax = calendar.twoDigitYearMax || 2029, defaultYear = date.getFullYear(), ch, count, length, pattern, pmHour, UTC, matches, amDesignators, pmDesignators, hoursOffset, minutesOffset, hasTime, match;
                if (!format) {
                    format = 'd';
                }
                pattern = calendar.patterns[format];
                if (pattern) {
                    format = pattern;
                }
                format = format.split('');
                length = format.length;
                for (; idx < length; idx++) {
                    ch = format[idx];
                    if (literal) {
                        if (ch === '\'') {
                            literal = false;
                        } else {
                            checkLiteral();
                        }
                    } else {
                        if (ch === 'd') {
                            count = lookAhead('d');
                            if (!calendar._lowerDays) {
                                calendar._lowerDays = lowerLocalInfo(calendar.days);
                            }
                            if (day !== null && count > 2) {
                                continue;
                            }
                            day = count < 3 ? getNumber(2) : getIndexByName(calendar._lowerDays[count == 3 ? 'namesAbbr' : 'names'], true);
                            if (day === null || outOfRange(day, 1, 31)) {
                                return null;
                            }
                        } else if (ch === 'M') {
                            count = lookAhead('M');
                            if (!calendar._lowerMonths) {
                                calendar._lowerMonths = lowerLocalInfo(calendar.months);
                            }
                            month = count < 3 ? getNumber(2) : getIndexByName(calendar._lowerMonths[count == 3 ? 'namesAbbr' : 'names'], true);
                            if (month === null || outOfRange(month, 1, 12)) {
                                return null;
                            }
                            month -= 1;
                        } else if (ch === 'y') {
                            count = lookAhead('y');
                            year = getNumber(count);
                            if (year === null) {
                                return null;
                            }
                            if (count == 2) {
                                if (typeof twoDigitYearMax === 'string') {
                                    twoDigitYearMax = defaultYear + parseInt(twoDigitYearMax, 10);
                                }
                                year = defaultYear - defaultYear % 100 + year;
                                if (year > twoDigitYearMax) {
                                    year -= 100;
                                }
                            }
                        } else if (ch === 'h') {
                            lookAhead('h');
                            hours = getNumber(2);
                            if (hours == 12) {
                                hours = 0;
                            }
                            if (hours === null || outOfRange(hours, 0, 11)) {
                                return null;
                            }
                        } else if (ch === 'H') {
                            lookAhead('H');
                            hours = getNumber(2);
                            if (hours === null || outOfRange(hours, 0, 23)) {
                                return null;
                            }
                        } else if (ch === 'm') {
                            lookAhead('m');
                            minutes = getNumber(2);
                            if (minutes === null || outOfRange(minutes, 0, 59)) {
                                return null;
                            }
                        } else if (ch === 's') {
                            lookAhead('s');
                            seconds = getNumber(2);
                            if (seconds === null || outOfRange(seconds, 0, 59)) {
                                return null;
                            }
                        } else if (ch === 'f') {
                            count = lookAhead('f');
                            match = value.substr(valueIdx, count).match(numberRegExp[3]);
                            milliseconds = getNumber(count);
                            if (milliseconds !== null) {
                                milliseconds = parseFloat('0.' + match[0], 10);
                                milliseconds = kendo._round(milliseconds, 3);
                                milliseconds *= 1000;
                            }
                            if (milliseconds === null || outOfRange(milliseconds, 0, 999)) {
                                return null;
                            }
                        } else if (ch === 't') {
                            count = lookAhead('t');
                            amDesignators = calendar.AM;
                            pmDesignators = calendar.PM;
                            if (count === 1) {
                                amDesignators = mapDesignators(amDesignators);
                                pmDesignators = mapDesignators(pmDesignators);
                            }
                            pmHour = getIndexByName(pmDesignators);
                            if (!pmHour && !getIndexByName(amDesignators)) {
                                return null;
                            }
                        } else if (ch === 'z') {
                            UTC = true;
                            count = lookAhead('z');
                            if (value.substr(valueIdx, 1) === 'Z') {
                                checkLiteral();
                                continue;
                            }
                            matches = value.substr(valueIdx, 6).match(count > 2 ? longTimeZoneRegExp : shortTimeZoneRegExp);
                            if (!matches) {
                                return null;
                            }
                            matches = matches[0].split(':');
                            hoursOffset = matches[0];
                            minutesOffset = matches[1];
                            if (!minutesOffset && hoursOffset.length > 3) {
                                valueIdx = hoursOffset.length - 2;
                                minutesOffset = hoursOffset.substring(valueIdx);
                                hoursOffset = hoursOffset.substring(0, valueIdx);
                            }
                            hoursOffset = parseInt(hoursOffset, 10);
                            if (outOfRange(hoursOffset, -12, 13)) {
                                return null;
                            }
                            if (count > 2) {
                                minutesOffset = matches[0][0] + minutesOffset;
                                minutesOffset = parseInt(minutesOffset, 10);
                                if (isNaN(minutesOffset) || outOfRange(minutesOffset, -59, 59)) {
                                    return null;
                                }
                            }
                        } else if (ch === '\'') {
                            literal = true;
                            checkLiteral();
                        } else if (!checkLiteral()) {
                            return null;
                        }
                    }
                }
                if (strict && !/^\s*$/.test(value.substr(valueIdx))) {
                    return null;
                }
                hasTime = hours !== null || minutes !== null || seconds || null;
                if (year === null && month === null && day === null && hasTime) {
                    year = defaultYear;
                    month = date.getMonth();
                    day = date.getDate();
                } else {
                    if (year === null) {
                        year = defaultYear;
                    }
                    if (day === null) {
                        day = 1;
                    }
                }
                if (pmHour && hours < 12) {
                    hours += 12;
                }
                if (UTC) {
                    if (hoursOffset) {
                        hours += -hoursOffset;
                    }
                    if (minutesOffset) {
                        minutes += -minutesOffset;
                    }
                    value = new Date(Date.UTC(year, month, day, hours, minutes, seconds, milliseconds));
                } else {
                    value = new Date(year, month, day, hours, minutes, seconds, milliseconds);
                    adjustDST(value, hours);
                }
                if (year < 100) {
                    value.setFullYear(year);
                }
                if (value.getDate() !== day && UTC === undefined) {
                    return null;
                }
                return value;
            }
            function parseMicrosoftFormatOffset(offset) {
                var sign = offset.substr(0, 1) === '-' ? -1 : 1;
                offset = offset.substring(1);
                offset = parseInt(offset.substr(0, 2), 10) * 60 + parseInt(offset.substring(2), 10);
                return sign * offset;
            }
            function getDefaultFormats(culture) {
                var length = math.max(FORMATS_SEQUENCE.length, STANDARD_FORMATS.length);
                var calendar = culture.calendar || culture.calendars.standard;
                var patterns = calendar.patterns;
                var cultureFormats, formatIdx, idx;
                var formats = [];
                for (idx = 0; idx < length; idx++) {
                    cultureFormats = FORMATS_SEQUENCE[idx];
                    for (formatIdx = 0; formatIdx < cultureFormats.length; formatIdx++) {
                        formats.push(patterns[cultureFormats[formatIdx]]);
                    }
                    formats = formats.concat(STANDARD_FORMATS[idx]);
                }
                return formats;
            }
            function internalParseDate(value, formats, culture, strict) {
                if (objectToString.call(value) === '[object Date]') {
                    return value;
                }
                var idx = 0;
                var date = null;
                var length;
                var tzoffset;
                if (value && value.indexOf('/D') === 0) {
                    date = dateRegExp.exec(value);
                    if (date) {
                        date = date[1];
                        tzoffset = offsetRegExp.exec(date.substring(1));
                        date = new Date(parseInt(date, 10));
                        if (tzoffset) {
                            tzoffset = parseMicrosoftFormatOffset(tzoffset[0]);
                            date = kendo.timezone.apply(date, 0);
                            date = kendo.timezone.convert(date, 0, -1 * tzoffset);
                        }
                        return date;
                    }
                }
                culture = kendo.getCulture(culture);
                if (!formats) {
                    formats = getDefaultFormats(culture);
                }
                formats = isArray(formats) ? formats : [formats];
                length = formats.length;
                for (; idx < length; idx++) {
                    date = parseExact(value, formats[idx], culture, strict);
                    if (date) {
                        return date;
                    }
                }
                return date;
            }
            kendo.parseDate = function (value, formats, culture) {
                return internalParseDate(value, formats, culture, false);
            };
            kendo.parseExactDate = function (value, formats, culture) {
                return internalParseDate(value, formats, culture, true);
            };
            kendo.parseInt = function (value, culture) {
                var result = kendo.parseFloat(value, culture);
                if (result) {
                    result = result | 0;
                }
                return result;
            };
            kendo.parseFloat = function (value, culture, format) {
                if (!value && value !== 0) {
                    return null;
                }
                if (typeof value === NUMBER) {
                    return value;
                }
                value = value.toString();
                culture = kendo.getCulture(culture);
                var number = culture.numberFormat, percent = number.percent, currency = number.currency, symbol = currency.symbol, percentSymbol = percent.symbol, negative = value.indexOf('-'), parts, isPercent;
                if (exponentRegExp.test(value)) {
                    value = parseFloat(value.replace(number['.'], '.'));
                    if (isNaN(value)) {
                        value = null;
                    }
                    return value;
                }
                if (negative > 0) {
                    return null;
                } else {
                    negative = negative > -1;
                }
                if (value.indexOf(symbol) > -1 || format && format.toLowerCase().indexOf('c') > -1) {
                    number = currency;
                    parts = number.pattern[0].replace('$', symbol).split('n');
                    if (value.indexOf(parts[0]) > -1 && value.indexOf(parts[1]) > -1) {
                        value = value.replace(parts[0], '').replace(parts[1], '');
                        negative = true;
                    }
                } else if (value.indexOf(percentSymbol) > -1) {
                    isPercent = true;
                    number = percent;
                    symbol = percentSymbol;
                }
                value = value.replace('-', '').replace(symbol, '').replace(nonBreakingSpaceRegExp, ' ').split(number[','].replace(nonBreakingSpaceRegExp, ' ')).join('').replace(number['.'], '.');
                value = parseFloat(value);
                if (isNaN(value)) {
                    value = null;
                } else if (negative) {
                    value *= -1;
                }
                if (value && isPercent) {
                    value /= 100;
                }
                return value;
            };
        }());
        function getShadows(element) {
            var shadow = element.css(kendo.support.transitions.css + 'box-shadow') || element.css('box-shadow'), radius = shadow ? shadow.match(boxShadowRegExp) || [
                    0,
                    0,
                    0,
                    0,
                    0
                ] : [
                    0,
                    0,
                    0,
                    0,
                    0
                ], blur = math.max(+radius[3], +(radius[4] || 0));
            return {
                left: -radius[1] + blur,
                right: +radius[1] + blur,
                bottom: +radius[2] + blur
            };
        }
        function wrap(element, autosize) {
            var browser = support.browser, percentage, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, parent = element.parent(), windowOuterWidth = outerWidth(window);
            parent.removeClass('k-animation-container-sm');
            if (!parent.hasClass('k-animation-container')) {
                var width = element[0].style.width, height = element[0].style.height, percentWidth = percentRegExp.test(width), percentHeight = percentRegExp.test(height), forceWidth = element.hasClass('k-tooltip') || element.is('.k-menu-horizontal.k-context-menu');
                percentage = percentWidth || percentHeight;
                if (!percentWidth && (!autosize || autosize && width || forceWidth)) {
                    width = autosize ? outerWidth(element) + 1 : outerWidth(element);
                }
                if (!percentHeight && (!autosize || autosize && height) || element.is('.k-menu-horizontal.k-context-menu')) {
                    height = outerHeight(element);
                }
                element.wrap($('<div/>').addClass('k-animation-container').css({
                    width: width,
                    height: height
                }));
                parent = element.parent();
                if (percentage) {
                    element.css({
                        width: '100%',
                        height: '100%',
                        boxSizing: 'border-box',
                        mozBoxSizing: 'border-box',
                        webkitBoxSizing: 'border-box'
                    });
                }
            } else {
                wrapResize(element, autosize);
            }
            if (windowOuterWidth < outerWidth(parent)) {
                parent.addClass('k-animation-container-sm');
                wrapResize(element, autosize);
            }
            if (browser.msie && math.floor(browser.version) <= 7) {
                element.css({ zoom: 1 });
                element.children('.k-menu').width(element.width());
            }
            return parent;
        }
        function wrapResize(element, autosize) {
            var percentage, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, wrapper = element.parent('.k-animation-container'), wrapperStyle = wrapper[0].style;
            if (wrapper.is(':hidden')) {
                wrapper.css({
                    display: '',
                    position: ''
                });
            }
            percentage = percentRegExp.test(wrapperStyle.width) || percentRegExp.test(wrapperStyle.height);
            if (!percentage) {
                wrapper.css({
                    width: autosize ? outerWidth(element) + 1 : outerWidth(element),
                    height: outerHeight(element),
                    boxSizing: 'content-box',
                    mozBoxSizing: 'content-box',
                    webkitBoxSizing: 'content-box'
                });
            }
        }
        function deepExtend(destination) {
            var i = 1, length = arguments.length;
            for (i = 1; i < length; i++) {
                deepExtendOne(destination, arguments[i]);
            }
            return destination;
        }
        function deepExtendOne(destination, source) {
            var ObservableArray = kendo.data.ObservableArray, LazyObservableArray = kendo.data.LazyObservableArray, DataSource = kendo.data.DataSource, HierarchicalDataSource = kendo.data.HierarchicalDataSource, property, propValue, propType, propInit, destProp;
            for (property in source) {
                propValue = source[property];
                propType = typeof propValue;
                if (propType === OBJECT && propValue !== null) {
                    propInit = propValue.constructor;
                } else {
                    propInit = null;
                }
                if (propInit && propInit !== Array && propInit !== ObservableArray && propInit !== LazyObservableArray && propInit !== DataSource && propInit !== HierarchicalDataSource && propInit !== RegExp) {
                    if (propValue instanceof Date) {
                        destination[property] = new Date(propValue.getTime());
                    } else if (isFunction(propValue.clone)) {
                        destination[property] = propValue.clone();
                    } else {
                        destProp = destination[property];
                        if (typeof destProp === OBJECT) {
                            destination[property] = destProp || {};
                        } else {
                            destination[property] = {};
                        }
                        deepExtendOne(destination[property], propValue);
                    }
                } else if (propType !== UNDEFINED) {
                    destination[property] = propValue;
                }
            }
            return destination;
        }
        function testRx(agent, rxs, dflt) {
            for (var rx in rxs) {
                if (rxs.hasOwnProperty(rx) && rxs[rx].test(agent)) {
                    return rx;
                }
            }
            return dflt !== undefined ? dflt : agent;
        }
        function toHyphens(str) {
            return str.replace(/([a-z][A-Z])/g, function (g) {
                return g.charAt(0) + '-' + g.charAt(1).toLowerCase();
            });
        }
        function toCamelCase(str) {
            return str.replace(/\-(\w)/g, function (strMatch, g1) {
                return g1.toUpperCase();
            });
        }
        function getComputedStyles(element, properties) {
            var styles = {}, computedStyle;
            if (document.defaultView && document.defaultView.getComputedStyle) {
                computedStyle = document.defaultView.getComputedStyle(element, '');
                if (properties) {
                    $.each(properties, function (idx, value) {
                        styles[value] = computedStyle.getPropertyValue(value);
                    });
                }
            } else {
                computedStyle = element.currentStyle;
                if (properties) {
                    $.each(properties, function (idx, value) {
                        styles[value] = computedStyle[toCamelCase(value)];
                    });
                }
            }
            if (!kendo.size(styles)) {
                styles = computedStyle;
            }
            return styles;
        }
        function isScrollable(element) {
            if (element && element.className && typeof element.className === 'string' && element.className.indexOf('k-auto-scrollable') > -1) {
                return true;
            }
            var overflow = getComputedStyles(element, ['overflow']).overflow;
            return overflow == 'auto' || overflow == 'scroll';
        }
        function scrollLeft(element, value) {
            var webkit = support.browser.webkit;
            var mozila = support.browser.mozilla;
            var el = element instanceof $ ? element[0] : element;
            var isRtl;
            if (!element) {
                return;
            }
            isRtl = support.isRtl(element);
            if (value !== undefined) {
                if (isRtl && webkit) {
                    el.scrollLeft = el.scrollWidth - el.clientWidth - value;
                } else if (isRtl && mozila) {
                    el.scrollLeft = -value;
                } else {
                    el.scrollLeft = value;
                }
            } else {
                if (isRtl && webkit) {
                    return el.scrollWidth - el.clientWidth - el.scrollLeft;
                } else {
                    return Math.abs(el.scrollLeft);
                }
            }
        }
        (function () {
            support._scrollbar = undefined;
            support.scrollbar = function (refresh) {
                if (!isNaN(support._scrollbar) && !refresh) {
                    return support._scrollbar;
                } else {
                    var div = document.createElement('div'), result;
                    div.style.cssText = 'overflow:scroll;overflow-x:hidden;zoom:1;clear:both;display:block';
                    div.innerHTML = '&nbsp;';
                    document.body.appendChild(div);
                    support._scrollbar = result = div.offsetWidth - div.scrollWidth;
                    document.body.removeChild(div);
                    return result;
                }
            };
            support.isRtl = function (element) {
                return $(element).closest('.k-rtl').length > 0;
            };
            var table = document.createElement('table');
            try {
                table.innerHTML = '<tr><td></td></tr>';
                support.tbodyInnerHtml = true;
            } catch (e) {
                support.tbodyInnerHtml = false;
            }
            support.touch = 'ontouchstart' in window;
            var docStyle = document.documentElement.style;
            var transitions = support.transitions = false, transforms = support.transforms = false, elementProto = 'HTMLElement' in window ? HTMLElement.prototype : [];
            support.hasHW3D = 'WebKitCSSMatrix' in window && 'm11' in new window.WebKitCSSMatrix() || 'MozPerspective' in docStyle || 'msPerspective' in docStyle;
            support.cssFlexbox = 'flexWrap' in docStyle || 'WebkitFlexWrap' in docStyle || 'msFlexWrap' in docStyle;
            each([
                'Moz',
                'webkit',
                'O',
                'ms'
            ], function () {
                var prefix = this.toString(), hasTransitions = typeof table.style[prefix + 'Transition'] === STRING;
                if (hasTransitions || typeof table.style[prefix + 'Transform'] === STRING) {
                    var lowPrefix = prefix.toLowerCase();
                    transforms = {
                        css: lowPrefix != 'ms' ? '-' + lowPrefix + '-' : '',
                        prefix: prefix,
                        event: lowPrefix === 'o' || lowPrefix === 'webkit' ? lowPrefix : ''
                    };
                    if (hasTransitions) {
                        transitions = transforms;
                        transitions.event = transitions.event ? transitions.event + 'TransitionEnd' : 'transitionend';
                    }
                    return false;
                }
            });
            table = null;
            support.transforms = transforms;
            support.transitions = transitions;
            support.devicePixelRatio = window.devicePixelRatio === undefined ? 1 : window.devicePixelRatio;
            try {
                support.screenWidth = window.outerWidth || window.screen ? window.screen.availWidth : window.innerWidth;
                support.screenHeight = window.outerHeight || window.screen ? window.screen.availHeight : window.innerHeight;
            } catch (e) {
                support.screenWidth = window.screen.availWidth;
                support.screenHeight = window.screen.availHeight;
            }
            support.detectOS = function (ua) {
                var os = false, minorVersion, match = [], notAndroidPhone = !/mobile safari/i.test(ua), agentRxs = {
                        wp: /(Windows Phone(?: OS)?)\s(\d+)\.(\d+(\.\d+)?)/,
                        fire: /(Silk)\/(\d+)\.(\d+(\.\d+)?)/,
                        android: /(Android|Android.*(?:Opera|Firefox).*?\/)\s*(\d+)\.?(\d+(\.\d+)?)?/,
                        iphone: /(iPhone|iPod).*OS\s+(\d+)[\._]([\d\._]+)/,
                        ipad: /(iPad).*OS\s+(\d+)[\._]([\d_]+)/,
                        meego: /(MeeGo).+NokiaBrowser\/(\d+)\.([\d\._]+)/,
                        webos: /(webOS)\/(\d+)\.(\d+(\.\d+)?)/,
                        blackberry: /(BlackBerry|BB10).*?Version\/(\d+)\.(\d+(\.\d+)?)/,
                        playbook: /(PlayBook).*?Tablet\s*OS\s*(\d+)\.(\d+(\.\d+)?)/,
                        windows: /(MSIE)\s+(\d+)\.(\d+(\.\d+)?)/,
                        tizen: /(tizen).*?Version\/(\d+)\.(\d+(\.\d+)?)/i,
                        sailfish: /(sailfish).*rv:(\d+)\.(\d+(\.\d+)?).*firefox/i,
                        ffos: /(Mobile).*rv:(\d+)\.(\d+(\.\d+)?).*Firefox/
                    }, osRxs = {
                        ios: /^i(phone|pad|pod)$/i,
                        android: /^android|fire$/i,
                        blackberry: /^blackberry|playbook/i,
                        windows: /windows/,
                        wp: /wp/,
                        flat: /sailfish|ffos|tizen/i,
                        meego: /meego/
                    }, formFactorRxs = { tablet: /playbook|ipad|fire/i }, browserRxs = {
                        omini: /Opera\sMini/i,
                        omobile: /Opera\sMobi/i,
                        firefox: /Firefox|Fennec/i,
                        mobilesafari: /version\/.*safari/i,
                        ie: /MSIE|Windows\sPhone/i,
                        chrome: /chrome|crios/i,
                        webkit: /webkit/i
                    };
                for (var agent in agentRxs) {
                    if (agentRxs.hasOwnProperty(agent)) {
                        match = ua.match(agentRxs[agent]);
                        if (match) {
                            if (agent == 'windows' && 'plugins' in navigator) {
                                return false;
                            }
                            os = {};
                            os.device = agent;
                            os.tablet = testRx(agent, formFactorRxs, false);
                            os.browser = testRx(ua, browserRxs, 'default');
                            os.name = testRx(agent, osRxs);
                            os[os.name] = true;
                            os.majorVersion = match[2];
                            os.minorVersion = (match[3] || '0').replace('_', '.');
                            minorVersion = os.minorVersion.replace('.', '').substr(0, 2);
                            os.flatVersion = os.majorVersion + minorVersion + new Array(3 - (minorVersion.length < 3 ? minorVersion.length : 2)).join('0');
                            os.cordova = typeof window.PhoneGap !== UNDEFINED || typeof window.cordova !== UNDEFINED;
                            os.appMode = window.navigator.standalone || /file|local|wmapp/.test(window.location.protocol) || os.cordova;
                            if (os.android && (support.devicePixelRatio < 1.5 && os.flatVersion < 400 || notAndroidPhone) && (support.screenWidth > 800 || support.screenHeight > 800)) {
                                os.tablet = agent;
                            }
                            break;
                        }
                    }
                }
                return os;
            };
            var mobileOS = support.mobileOS = support.detectOS(navigator.userAgent);
            support.wpDevicePixelRatio = mobileOS.wp ? screen.width / 320 : 0;
            support.hasNativeScrolling = false;
            if (mobileOS.ios || mobileOS.android && mobileOS.majorVersion > 2 || mobileOS.wp) {
                support.hasNativeScrolling = mobileOS;
            }
            support.delayedClick = function () {
                if (support.touch) {
                    if (mobileOS.ios) {
                        return true;
                    }
                    if (mobileOS.android) {
                        if (!support.browser.chrome) {
                            return true;
                        }
                        if (support.browser.version < 32) {
                            return false;
                        }
                        return !($('meta[name=viewport]').attr('content') || '').match(/user-scalable=no/i);
                    }
                }
                return false;
            };
            support.mouseAndTouchPresent = support.touch && !(support.mobileOS.ios || support.mobileOS.android);
            support.detectBrowser = function (ua) {
                var browser = false, match = [], browserRxs = {
                        edge: /(edge)[ \/]([\w.]+)/i,
                        webkit: /(chrome|crios)[ \/]([\w.]+)/i,
                        safari: /(webkit)[ \/]([\w.]+)/i,
                        opera: /(opera)(?:.*version|)[ \/]([\w.]+)/i,
                        msie: /(msie\s|trident.*? rv:)([\w.]+)/i,
                        mozilla: /(mozilla)(?:.*? rv:([\w.]+)|)/i
                    };
                for (var agent in browserRxs) {
                    if (browserRxs.hasOwnProperty(agent)) {
                        match = ua.match(browserRxs[agent]);
                        if (match) {
                            browser = {};
                            browser[agent] = true;
                            browser[match[1].toLowerCase().split(' ')[0].split('/')[0]] = true;
                            browser.version = parseInt(document.documentMode || match[2], 10);
                            break;
                        }
                    }
                }
                return browser;
            };
            support.browser = support.detectBrowser(navigator.userAgent);
            support.detectClipboardAccess = function () {
                var commands = {
                    copy: document.queryCommandSupported ? document.queryCommandSupported('copy') : false,
                    cut: document.queryCommandSupported ? document.queryCommandSupported('cut') : false,
                    paste: document.queryCommandSupported ? document.queryCommandSupported('paste') : false
                };
                if (support.browser.chrome) {
                    commands.paste = false;
                    if (support.browser.version >= 43) {
                        commands.copy = true;
                        commands.cut = true;
                    }
                }
                return commands;
            };
            support.clipboard = support.detectClipboardAccess();
            support.zoomLevel = function () {
                try {
                    var browser = support.browser;
                    var ie11WidthCorrection = 0;
                    var docEl = document.documentElement;
                    if (browser.msie && browser.version == 11 && docEl.scrollHeight > docEl.clientHeight && !support.touch) {
                        ie11WidthCorrection = support.scrollbar();
                    }
                    return support.touch ? docEl.clientWidth / window.innerWidth : browser.msie && browser.version >= 10 ? ((top || window).document.documentElement.offsetWidth + ie11WidthCorrection) / (top || window).innerWidth : 1;
                } catch (e) {
                    return 1;
                }
            };
            support.cssBorderSpacing = typeof docStyle.borderSpacing != 'undefined' && !(support.browser.msie && support.browser.version < 8);
            (function (browser) {
                var cssClass = '', docElement = $(document.documentElement), majorVersion = parseInt(browser.version, 10);
                if (browser.msie) {
                    cssClass = 'ie';
                } else if (browser.mozilla) {
                    cssClass = 'ff';
                } else if (browser.safari) {
                    cssClass = 'safari';
                } else if (browser.webkit) {
                    cssClass = 'webkit';
                } else if (browser.opera) {
                    cssClass = 'opera';
                } else if (browser.edge) {
                    cssClass = 'edge';
                }
                if (cssClass) {
                    cssClass = 'k-' + cssClass + ' k-' + cssClass + majorVersion;
                }
                if (support.mobileOS) {
                    cssClass += ' k-mobile';
                }
                if (!support.cssFlexbox) {
                    cssClass += ' k-no-flexbox';
                }
                docElement.addClass(cssClass);
            }(support.browser));
            support.eventCapture = document.documentElement.addEventListener;
            var input = document.createElement('input');
            support.placeholder = 'placeholder' in input;
            support.propertyChangeEvent = 'onpropertychange' in input;
            support.input = function () {
                var types = [
                    'number',
                    'date',
                    'time',
                    'month',
                    'week',
                    'datetime',
                    'datetime-local'
                ];
                var length = types.length;
                var value = 'test';
                var result = {};
                var idx = 0;
                var type;
                for (; idx < length; idx++) {
                    type = types[idx];
                    input.setAttribute('type', type);
                    input.value = value;
                    result[type.replace('-', '')] = input.type !== 'text' && input.value !== value;
                }
                return result;
            }();
            input.style.cssText = 'float:left;';
            support.cssFloat = !!input.style.cssFloat;
            input = null;
            support.stableSort = function () {
                var threshold = 513;
                var sorted = [{
                        index: 0,
                        field: 'b'
                    }];
                for (var i = 1; i < threshold; i++) {
                    sorted.push({
                        index: i,
                        field: 'a'
                    });
                }
                sorted.sort(function (a, b) {
                    return a.field > b.field ? 1 : a.field < b.field ? -1 : 0;
                });
                return sorted[0].index === 1;
            }();
            support.matchesSelector = elementProto.webkitMatchesSelector || elementProto.mozMatchesSelector || elementProto.msMatchesSelector || elementProto.oMatchesSelector || elementProto.matchesSelector || elementProto.matches || function (selector) {
                var nodeList = document.querySelectorAll ? (this.parentNode || document).querySelectorAll(selector) || [] : $(selector), i = nodeList.length;
                while (i--) {
                    if (nodeList[i] == this) {
                        return true;
                    }
                }
                return false;
            };
            support.matchMedia = 'matchMedia' in window;
            support.pushState = window.history && window.history.pushState;
            var documentMode = document.documentMode;
            support.hashChange = 'onhashchange' in window && !(support.browser.msie && (!documentMode || documentMode <= 8));
            support.customElements = 'registerElement' in window.document;
            var chrome = support.browser.chrome, mozilla = support.browser.mozilla;
            support.msPointers = !chrome && window.MSPointerEvent;
            support.pointers = !chrome && !mozilla && window.PointerEvent;
            support.kineticScrollNeeded = mobileOS && (support.touch || support.msPointers || support.pointers);
        }());
        function size(obj) {
            var result = 0, key;
            for (key in obj) {
                if (obj.hasOwnProperty(key) && key != 'toJSON') {
                    result++;
                }
            }
            return result;
        }
        function getOffset(element, type, positioned) {
            if (!type) {
                type = 'offset';
            }
            var offset = element[type]();
            var result = {
                top: offset.top,
                right: offset.right,
                bottom: offset.bottom,
                left: offset.left
            };
            if (support.browser.msie && (support.pointers || support.msPointers) && !positioned) {
                var sign = support.isRtl(element) ? 1 : -1;
                result.top -= window.pageYOffset - document.documentElement.scrollTop;
                result.left -= window.pageXOffset + sign * document.documentElement.scrollLeft;
            }
            return result;
        }
        var directions = {
            left: { reverse: 'right' },
            right: { reverse: 'left' },
            down: { reverse: 'up' },
            up: { reverse: 'down' },
            top: { reverse: 'bottom' },
            bottom: { reverse: 'top' },
            'in': { reverse: 'out' },
            out: { reverse: 'in' }
        };
        function parseEffects(input) {
            var effects = {};
            each(typeof input === 'string' ? input.split(' ') : input, function (idx) {
                effects[idx] = this;
            });
            return effects;
        }
        function fx(element) {
            return new kendo.effects.Element(element);
        }
        var effects = {};
        $.extend(effects, {
            enabled: true,
            Element: function (element) {
                this.element = $(element);
            },
            promise: function (element, options) {
                if (!element.is(':visible')) {
                    element.css({ display: element.data('olddisplay') || 'block' }).css('display');
                }
                if (options.hide) {
                    element.data('olddisplay', element.css('display')).hide();
                }
                if (options.init) {
                    options.init();
                }
                if (options.completeCallback) {
                    options.completeCallback(element);
                }
                element.dequeue();
            },
            disable: function () {
                this.enabled = false;
                this.promise = this.promiseShim;
            },
            enable: function () {
                this.enabled = true;
                this.promise = this.animatedPromise;
            }
        });
        effects.promiseShim = effects.promise;
        function prepareAnimationOptions(options, duration, reverse, complete) {
            if (typeof options === STRING) {
                if (isFunction(duration)) {
                    complete = duration;
                    duration = 400;
                    reverse = false;
                }
                if (isFunction(reverse)) {
                    complete = reverse;
                    reverse = false;
                }
                if (typeof duration === BOOLEAN) {
                    reverse = duration;
                    duration = 400;
                }
                options = {
                    effects: options,
                    duration: duration,
                    reverse: reverse,
                    complete: complete
                };
            }
            return extend({
                effects: {},
                duration: 400,
                reverse: false,
                init: noop,
                teardown: noop,
                hide: false
            }, options, {
                completeCallback: options.complete,
                complete: noop
            });
        }
        function animate(element, options, duration, reverse, complete) {
            var idx = 0, length = element.length, instance;
            for (; idx < length; idx++) {
                instance = $(element[idx]);
                instance.queue(function () {
                    effects.promise(instance, prepareAnimationOptions(options, duration, reverse, complete));
                });
            }
            return element;
        }
        function toggleClass(element, classes, options, add) {
            if (classes) {
                classes = classes.split(' ');
                each(classes, function (idx, value) {
                    element.toggleClass(value, add);
                });
            }
            return element;
        }
        if (!('kendoAnimate' in $.fn)) {
            extend($.fn, {
                kendoStop: function (clearQueue, gotoEnd) {
                    return this.stop(clearQueue, gotoEnd);
                },
                kendoAnimate: function (options, duration, reverse, complete) {
                    return animate(this, options, duration, reverse, complete);
                },
                kendoAddClass: function (classes, options) {
                    return kendo.toggleClass(this, classes, options, true);
                },
                kendoRemoveClass: function (classes, options) {
                    return kendo.toggleClass(this, classes, options, false);
                },
                kendoToggleClass: function (classes, options, toggle) {
                    return kendo.toggleClass(this, classes, options, toggle);
                }
            });
        }
        var ampRegExp = /&/g, ltRegExp = /</g, quoteRegExp = /"/g, aposRegExp = /'/g, gtRegExp = />/g;
        function htmlEncode(value) {
            return ('' + value).replace(ampRegExp, '&amp;').replace(ltRegExp, '&lt;').replace(gtRegExp, '&gt;').replace(quoteRegExp, '&quot;').replace(aposRegExp, '&#39;');
        }
        var eventTarget = function (e) {
            return e.target;
        };
        if (support.touch) {
            eventTarget = function (e) {
                var touches = 'originalEvent' in e ? e.originalEvent.changedTouches : 'changedTouches' in e ? e.changedTouches : null;
                return touches ? document.elementFromPoint(touches[0].clientX, touches[0].clientY) : e.target;
            };
            each([
                'swipe',
                'swipeLeft',
                'swipeRight',
                'swipeUp',
                'swipeDown',
                'doubleTap',
                'tap'
            ], function (m, value) {
                $.fn[value] = function (callback) {
                    return this.bind(value, callback);
                };
            });
        }
        if (support.touch) {
            if (!support.mobileOS) {
                support.mousedown = 'mousedown touchstart';
                support.mouseup = 'mouseup touchend';
                support.mousemove = 'mousemove touchmove';
                support.mousecancel = 'mouseleave touchcancel';
                support.click = 'click';
                support.resize = 'resize';
            } else {
                support.mousedown = 'touchstart';
                support.mouseup = 'touchend';
                support.mousemove = 'touchmove';
                support.mousecancel = 'touchcancel';
                support.click = 'touchend';
                support.resize = 'orientationchange';
            }
        } else if (support.pointers) {
            support.mousemove = 'pointermove';
            support.mousedown = 'pointerdown';
            support.mouseup = 'pointerup';
            support.mousecancel = 'pointercancel';
            support.click = 'pointerup';
            support.resize = 'orientationchange resize';
        } else if (support.msPointers) {
            support.mousemove = 'MSPointerMove';
            support.mousedown = 'MSPointerDown';
            support.mouseup = 'MSPointerUp';
            support.mousecancel = 'MSPointerCancel';
            support.click = 'MSPointerUp';
            support.resize = 'orientationchange resize';
        } else {
            support.mousemove = 'mousemove';
            support.mousedown = 'mousedown';
            support.mouseup = 'mouseup';
            support.mousecancel = 'mouseleave';
            support.click = 'click';
            support.resize = 'resize';
        }
        var wrapExpression = function (members, paramName) {
                var result = paramName || 'd', index, idx, length, member, count = 1;
                for (idx = 0, length = members.length; idx < length; idx++) {
                    member = members[idx];
                    if (member !== '') {
                        index = member.indexOf('[');
                        if (index !== 0) {
                            if (index == -1) {
                                member = '.' + member;
                            } else {
                                count++;
                                member = '.' + member.substring(0, index) + ' || {})' + member.substring(index);
                            }
                        }
                        count++;
                        result += member + (idx < length - 1 ? ' || {})' : ')');
                    }
                }
                return new Array(count).join('(') + result;
            }, localUrlRe = /^([a-z]+:)?\/\//i;
        extend(kendo, {
            widgets: [],
            _widgetRegisteredCallbacks: [],
            ui: kendo.ui || {},
            fx: kendo.fx || fx,
            effects: kendo.effects || effects,
            mobile: kendo.mobile || {},
            data: kendo.data || {},
            dataviz: kendo.dataviz || {},
            drawing: kendo.drawing || {},
            spreadsheet: { messages: {} },
            keys: {
                INSERT: 45,
                DELETE: 46,
                BACKSPACE: 8,
                TAB: 9,
                ENTER: 13,
                ESC: 27,
                LEFT: 37,
                UP: 38,
                RIGHT: 39,
                DOWN: 40,
                END: 35,
                HOME: 36,
                SPACEBAR: 32,
                PAGEUP: 33,
                PAGEDOWN: 34,
                F2: 113,
                F10: 121,
                F12: 123,
                NUMPAD_PLUS: 107,
                NUMPAD_MINUS: 109,
                NUMPAD_DOT: 110
            },
            support: kendo.support || support,
            animate: kendo.animate || animate,
            ns: '',
            attr: function (value) {
                return 'data-' + kendo.ns + value;
            },
            getShadows: getShadows,
            wrap: wrap,
            deepExtend: deepExtend,
            getComputedStyles: getComputedStyles,
            isScrollable: isScrollable,
            scrollLeft: scrollLeft,
            size: size,
            toCamelCase: toCamelCase,
            toHyphens: toHyphens,
            getOffset: kendo.getOffset || getOffset,
            parseEffects: kendo.parseEffects || parseEffects,
            toggleClass: kendo.toggleClass || toggleClass,
            directions: kendo.directions || directions,
            Observable: Observable,
            Class: Class,
            Template: Template,
            template: proxy(Template.compile, Template),
            render: proxy(Template.render, Template),
            stringify: proxy(JSON.stringify, JSON),
            eventTarget: eventTarget,
            htmlEncode: htmlEncode,
            isLocalUrl: function (url) {
                return url && !localUrlRe.test(url);
            },
            expr: function (expression, safe, paramName) {
                expression = expression || '';
                if (typeof safe == STRING) {
                    paramName = safe;
                    safe = false;
                }
                paramName = paramName || 'd';
                if (expression && expression.charAt(0) !== '[') {
                    expression = '.' + expression;
                }
                if (safe) {
                    expression = expression.replace(/"([^.]*)\.([^"]*)"/g, '"$1_$DOT$_$2"');
                    expression = expression.replace(/'([^.]*)\.([^']*)'/g, '\'$1_$DOT$_$2\'');
                    expression = wrapExpression(expression.split('.'), paramName);
                    expression = expression.replace(/_\$DOT\$_/g, '.');
                } else {
                    expression = paramName + expression;
                }
                return expression;
            },
            getter: function (expression, safe) {
                var key = expression + safe;
                return getterCache[key] = getterCache[key] || new Function('d', 'return ' + kendo.expr(expression, safe));
            },
            setter: function (expression) {
                return setterCache[expression] = setterCache[expression] || new Function('d,value', kendo.expr(expression) + '=value');
            },
            accessor: function (expression) {
                return {
                    get: kendo.getter(expression),
                    set: kendo.setter(expression)
                };
            },
            guid: function () {
                var id = '', i, random;
                for (i = 0; i < 32; i++) {
                    random = math.random() * 16 | 0;
                    if (i == 8 || i == 12 || i == 16 || i == 20) {
                        id += '-';
                    }
                    id += (i == 12 ? 4 : i == 16 ? random & 3 | 8 : random).toString(16);
                }
                return id;
            },
            roleSelector: function (role) {
                return role.replace(/(\S+)/g, '[' + kendo.attr('role') + '=$1],').slice(0, -1);
            },
            directiveSelector: function (directives) {
                var selectors = directives.split(' ');
                if (selectors) {
                    for (var i = 0; i < selectors.length; i++) {
                        if (selectors[i] != 'view') {
                            selectors[i] = selectors[i].replace(/(\w*)(view|bar|strip|over)$/, '$1-$2');
                        }
                    }
                }
                return selectors.join(' ').replace(/(\S+)/g, 'kendo-mobile-$1,').slice(0, -1);
            },
            triggeredByInput: function (e) {
                return /^(label|input|textarea|select)$/i.test(e.target.tagName);
            },
            onWidgetRegistered: function (callback) {
                for (var i = 0, len = kendo.widgets.length; i < len; i++) {
                    callback(kendo.widgets[i]);
                }
                kendo._widgetRegisteredCallbacks.push(callback);
            },
            logToConsole: function (message, type) {
                var console = window.console;
                if (!kendo.suppressLog && typeof console != 'undefined' && console.log) {
                    console[type || 'log'](message);
                }
            }
        });
        var Widget = Observable.extend({
            init: function (element, options) {
                var that = this;
                that.element = kendo.jQuery(element).handler(that);
                that.angular('init', options);
                Observable.fn.init.call(that);
                var dataSource = options ? options.dataSource : null;
                if (dataSource) {
                    options = extend({}, options, { dataSource: {} });
                }
                options = that.options = extend(true, {}, that.options, options);
                if (dataSource) {
                    options.dataSource = dataSource;
                }
                if (!that.element.attr(kendo.attr('role'))) {
                    that.element.attr(kendo.attr('role'), (options.name || '').toLowerCase());
                }
                that.element.data('kendo' + options.prefix + options.name, that);
                that.bind(that.events, options);
            },
            events: [],
            options: { prefix: '' },
            _hasBindingTarget: function () {
                return !!this.element[0].kendoBindingTarget;
            },
            _tabindex: function (target) {
                target = target || this.wrapper;
                var element = this.element, TABINDEX = 'tabindex', tabindex = target.attr(TABINDEX) || element.attr(TABINDEX);
                element.removeAttr(TABINDEX);
                target.attr(TABINDEX, !isNaN(tabindex) ? tabindex : 0);
            },
            setOptions: function (options) {
                this._setEvents(options);
                $.extend(this.options, options);
            },
            _setEvents: function (options) {
                var that = this, idx = 0, length = that.events.length, e;
                for (; idx < length; idx++) {
                    e = that.events[idx];
                    if (that.options[e] && options[e]) {
                        that.unbind(e, that.options[e]);
                    }
                }
                that.bind(that.events, options);
            },
            resize: function (force) {
                var size = this.getSize(), currentSize = this._size;
                if (force || (size.width > 0 || size.height > 0) && (!currentSize || size.width !== currentSize.width || size.height !== currentSize.height)) {
                    this._size = size;
                    this._resize(size, force);
                    this.trigger('resize', size);
                }
            },
            getSize: function () {
                return kendo.dimensions(this.element);
            },
            size: function (size) {
                if (!size) {
                    return this.getSize();
                } else {
                    this.setSize(size);
                }
            },
            setSize: $.noop,
            _resize: $.noop,
            destroy: function () {
                var that = this;
                that.element.removeData('kendo' + that.options.prefix + that.options.name);
                that.element.removeData('handler');
                that.unbind();
            },
            _destroy: function () {
                this.destroy();
            },
            angular: function () {
            },
            _muteAngularRebind: function (callback) {
                this._muteRebind = true;
                callback.call(this);
                this._muteRebind = false;
            }
        });
        var DataBoundWidget = Widget.extend({
            dataItems: function () {
                return this.dataSource.flatView();
            },
            _angularItems: function (cmd) {
                var that = this;
                that.angular(cmd, function () {
                    return {
                        elements: that.items(),
                        data: $.map(that.dataItems(), function (dataItem) {
                            return { dataItem: dataItem };
                        })
                    };
                });
            }
        });
        kendo.dimensions = function (element, dimensions) {
            var domElement = element[0];
            if (dimensions) {
                element.css(dimensions);
            }
            return {
                width: domElement.offsetWidth,
                height: domElement.offsetHeight
            };
        };
        kendo.notify = noop;
        var templateRegExp = /template$/i, jsonRegExp = /^\s*(?:\{(?:.|\r\n|\n)*\}|\[(?:.|\r\n|\n)*\])\s*$/, jsonFormatRegExp = /^\{(\d+)(:[^\}]+)?\}|^\[[A-Za-z_]+\]$/, dashRegExp = /([A-Z])/g;
        function parseOption(element, option) {
            var value;
            if (option.indexOf('data') === 0) {
                option = option.substring(4);
                option = option.charAt(0).toLowerCase() + option.substring(1);
            }
            option = option.replace(dashRegExp, '-$1');
            value = element.getAttribute('data-' + kendo.ns + option);
            if (value === null) {
                value = undefined;
            } else if (value === 'null') {
                value = null;
            } else if (value === 'true') {
                value = true;
            } else if (value === 'false') {
                value = false;
            } else if (numberRegExp.test(value) && option != 'mask') {
                value = parseFloat(value);
            } else if (jsonRegExp.test(value) && !jsonFormatRegExp.test(value)) {
                value = new Function('return (' + value + ')')();
            }
            return value;
        }
        function parseOptions(element, options, source) {
            var result = {}, option, value, role = element.getAttribute('data-' + kendo.ns + 'role');
            for (option in options) {
                value = parseOption(element, option);
                if (value !== undefined) {
                    if (templateRegExp.test(option) && role != 'drawer') {
                        if (typeof value === 'string') {
                            if ($('#' + value).length) {
                                value = kendo.template($('#' + value).html());
                            } else if (source) {
                                value = kendo.template(source[value]);
                            }
                        } else {
                            value = element.getAttribute(option);
                        }
                    }
                    result[option] = value;
                }
            }
            return result;
        }
        kendo.initWidget = function (element, options, roles) {
            var result, option, widget, idx, length, role, value, dataSource, fullPath, widgetKeyRegExp;
            if (!roles) {
                roles = kendo.ui.roles;
            } else if (roles.roles) {
                roles = roles.roles;
            }
            element = element.nodeType ? element : element[0];
            role = element.getAttribute('data-' + kendo.ns + 'role');
            if (!role) {
                return;
            }
            fullPath = role.indexOf('.') === -1;
            if (fullPath) {
                widget = roles[role];
            } else {
                widget = kendo.getter(role)(window);
            }
            var data = $(element).data(), widgetKey = widget ? 'kendo' + widget.fn.options.prefix + widget.fn.options.name : '';
            if (fullPath) {
                widgetKeyRegExp = new RegExp('^kendo.*' + role + '$', 'i');
            } else {
                widgetKeyRegExp = new RegExp('^' + widgetKey + '$', 'i');
            }
            for (var key in data) {
                if (key.match(widgetKeyRegExp)) {
                    if (key === widgetKey) {
                        result = data[key];
                    } else {
                        return data[key];
                    }
                }
            }
            if (!widget) {
                return;
            }
            dataSource = parseOption(element, 'dataSource');
            options = $.extend({}, parseOptions(element, widget.fn.options), options);
            if (dataSource) {
                if (typeof dataSource === STRING) {
                    options.dataSource = kendo.getter(dataSource)(window);
                } else {
                    options.dataSource = dataSource;
                }
            }
            for (idx = 0, length = widget.fn.events.length; idx < length; idx++) {
                option = widget.fn.events[idx];
                value = parseOption(element, option);
                if (value !== undefined) {
                    options[option] = kendo.getter(value)(window);
                }
            }
            if (!result) {
                result = new widget(element, options);
            } else if (!$.isEmptyObject(options)) {
                result.setOptions(options);
            }
            return result;
        };
        kendo.rolesFromNamespaces = function (namespaces) {
            var roles = [], idx, length;
            if (!namespaces[0]) {
                namespaces = [
                    kendo.ui,
                    kendo.dataviz.ui
                ];
            }
            for (idx = 0, length = namespaces.length; idx < length; idx++) {
                roles[idx] = namespaces[idx].roles;
            }
            return extend.apply(null, [{}].concat(roles.reverse()));
        };
        kendo.init = function (element) {
            var roles = kendo.rolesFromNamespaces(slice.call(arguments, 1));
            $(element).find('[data-' + kendo.ns + 'role]').addBack().each(function () {
                kendo.initWidget(this, {}, roles);
            });
        };
        kendo.destroy = function (element) {
            $(element).find('[data-' + kendo.ns + 'role]').addBack().each(function () {
                var data = $(this).data();
                for (var key in data) {
                    if (key.indexOf('kendo') === 0 && typeof data[key].destroy === FUNCTION) {
                        data[key].destroy();
                    }
                }
            });
        };
        function containmentComparer(a, b) {
            return $.contains(a, b) ? -1 : 1;
        }
        function resizableWidget() {
            var widget = $(this);
            return $.inArray(widget.attr('data-' + kendo.ns + 'role'), [
                'slider',
                'rangeslider'
            ]) > -1 || widget.is(':visible');
        }
        kendo.resize = function (element, force) {
            var widgets = $(element).find('[data-' + kendo.ns + 'role]').addBack().filter(resizableWidget);
            if (!widgets.length) {
                return;
            }
            var widgetsArray = $.makeArray(widgets);
            widgetsArray.sort(containmentComparer);
            $.each(widgetsArray, function () {
                var widget = kendo.widgetInstance($(this));
                if (widget) {
                    widget.resize(force);
                }
            });
        };
        kendo.parseOptions = parseOptions;
        extend(kendo.ui, {
            Widget: Widget,
            DataBoundWidget: DataBoundWidget,
            roles: {},
            progress: function (container, toggle, options) {
                var mask = container.find('.k-loading-mask'), support = kendo.support, browser = support.browser, isRtl, leftRight, webkitCorrection, containerScrollLeft, cssClass;
                options = $.extend({}, {
                    width: '100%',
                    height: '100%',
                    top: container.scrollTop(),
                    opacity: false
                }, options);
                cssClass = options.opacity ? 'k-loading-mask k-opaque' : 'k-loading-mask';
                if (toggle) {
                    if (!mask.length) {
                        isRtl = support.isRtl(container);
                        leftRight = isRtl ? 'right' : 'left';
                        containerScrollLeft = container.scrollLeft();
                        webkitCorrection = browser.webkit ? !isRtl ? 0 : container[0].scrollWidth - container.width() - 2 * containerScrollLeft : 0;
                        mask = $(kendo.format('<div class=\'{0}\'><span class=\'k-loading-text\'>{1}</span><div class=\'k-loading-image\'/><div class=\'k-loading-color\'/></div>', cssClass, kendo.ui.progress.messages.loading)).width(options.width).height(options.height).css('top', options.top).css(leftRight, Math.abs(containerScrollLeft) + webkitCorrection).prependTo(container);
                    }
                } else if (mask) {
                    mask.remove();
                }
            },
            plugin: function (widget, register, prefix) {
                var name = widget.fn.options.name, getter;
                register = register || kendo.ui;
                prefix = prefix || '';
                register[name] = widget;
                register.roles[name.toLowerCase()] = widget;
                getter = 'getKendo' + prefix + name;
                name = 'kendo' + prefix + name;
                var widgetEntry = {
                    name: name,
                    widget: widget,
                    prefix: prefix || ''
                };
                kendo.widgets.push(widgetEntry);
                for (var i = 0, len = kendo._widgetRegisteredCallbacks.length; i < len; i++) {
                    kendo._widgetRegisteredCallbacks[i](widgetEntry);
                }
                $.fn[name] = function (options) {
                    var value = this, args;
                    if (typeof options === STRING) {
                        args = slice.call(arguments, 1);
                        this.each(function () {
                            var widget = $.data(this, name), method, result;
                            if (!widget) {
                                throw new Error(kendo.format('Cannot call method \'{0}\' of {1} before it is initialized', options, name));
                            }
                            method = widget[options];
                            if (typeof method !== FUNCTION) {
                                throw new Error(kendo.format('Cannot find method \'{0}\' of {1}', options, name));
                            }
                            result = method.apply(widget, args);
                            if (result !== undefined) {
                                value = result;
                                return false;
                            }
                        });
                    } else {
                        this.each(function () {
                            return new widget(this, options);
                        });
                    }
                    return value;
                };
                $.fn[name].widget = widget;
                $.fn[getter] = function () {
                    return this.data(name);
                };
            }
        });
        kendo.ui.progress.messages = { loading: 'Loading...' };
        var ContainerNullObject = {
            bind: function () {
                return this;
            },
            nullObject: true,
            options: {}
        };
        var MobileWidget = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.element.autoApplyNS();
                this.wrapper = this.element;
                this.element.addClass('km-widget');
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.element.kendoDestroy();
            },
            options: { prefix: 'Mobile' },
            events: [],
            view: function () {
                var viewElement = this.element.closest(kendo.roleSelector('view splitview modalview drawer'));
                return kendo.widgetInstance(viewElement, kendo.mobile.ui) || ContainerNullObject;
            },
            viewHasNativeScrolling: function () {
                var view = this.view();
                return view && view.options.useNativeScrolling;
            },
            container: function () {
                var element = this.element.closest(kendo.roleSelector('view layout modalview drawer splitview'));
                return kendo.widgetInstance(element.eq(0), kendo.mobile.ui) || ContainerNullObject;
            }
        });
        extend(kendo.mobile, {
            init: function (element) {
                kendo.init(element, kendo.mobile.ui, kendo.ui, kendo.dataviz.ui);
            },
            appLevelNativeScrolling: function () {
                return kendo.mobile.application && kendo.mobile.application.options && kendo.mobile.application.options.useNativeScrolling;
            },
            roles: {},
            ui: {
                Widget: MobileWidget,
                DataBoundWidget: DataBoundWidget.extend(MobileWidget.prototype),
                roles: {},
                plugin: function (widget) {
                    kendo.ui.plugin(widget, kendo.mobile.ui, 'Mobile');
                }
            }
        });
        deepExtend(kendo.dataviz, {
            init: function (element) {
                kendo.init(element, kendo.dataviz.ui);
            },
            ui: {
                roles: {},
                themes: {},
                views: [],
                plugin: function (widget) {
                    kendo.ui.plugin(widget, kendo.dataviz.ui);
                }
            },
            roles: {}
        });
        kendo.touchScroller = function (elements, options) {
            if (!options) {
                options = {};
            }
            options.useNative = true;
            return $(elements).map(function (idx, element) {
                element = $(element);
                if (support.kineticScrollNeeded && kendo.mobile.ui.Scroller && !element.data('kendoMobileScroller')) {
                    element.kendoMobileScroller(options);
                    return element.data('kendoMobileScroller');
                } else {
                    return false;
                }
            })[0];
        };
        kendo.preventDefault = function (e) {
            e.preventDefault();
        };
        kendo.widgetInstance = function (element, suites) {
            var role = element.data(kendo.ns + 'role'), widgets = [], i, length;
            if (role) {
                if (role === 'content') {
                    role = 'scroller';
                }
                if (role === 'editortoolbar') {
                    var editorToolbar = element.data('kendoEditorToolbar');
                    if (editorToolbar) {
                        return editorToolbar;
                    }
                }
                if (role === 'view') {
                    return element.data('kendoView');
                }
                if (suites) {
                    if (suites[0]) {
                        for (i = 0, length = suites.length; i < length; i++) {
                            widgets.push(suites[i].roles[role]);
                        }
                    } else {
                        widgets.push(suites.roles[role]);
                    }
                } else {
                    widgets = [
                        kendo.ui.roles[role],
                        kendo.dataviz.ui.roles[role],
                        kendo.mobile.ui.roles[role]
                    ];
                }
                if (role.indexOf('.') >= 0) {
                    widgets = [kendo.getter(role)(window)];
                }
                for (i = 0, length = widgets.length; i < length; i++) {
                    var widget = widgets[i];
                    if (widget) {
                        var instance = element.data('kendo' + widget.fn.options.prefix + widget.fn.options.name);
                        if (instance) {
                            return instance;
                        }
                    }
                }
            }
        };
        kendo.onResize = function (callback) {
            var handler = callback;
            if (support.mobileOS.android) {
                handler = function () {
                    setTimeout(callback, 600);
                };
            }
            $(window).on(support.resize, handler);
            return handler;
        };
        kendo.unbindResize = function (callback) {
            $(window).off(support.resize, callback);
        };
        kendo.attrValue = function (element, key) {
            return element.data(kendo.ns + key);
        };
        kendo.days = {
            Sunday: 0,
            Monday: 1,
            Tuesday: 2,
            Wednesday: 3,
            Thursday: 4,
            Friday: 5,
            Saturday: 6
        };
        function focusable(element, isTabIndexNotNaN) {
            var nodeName = element.nodeName.toLowerCase();
            return (/input|select|textarea|button|object/.test(nodeName) ? !element.disabled : 'a' === nodeName ? element.href || isTabIndexNotNaN : isTabIndexNotNaN) && visible(element);
        }
        function visible(element) {
            return $.expr.pseudos.visible(element) && !$(element).parents().addBack().filter(function () {
                return $.css(this, 'visibility') === 'hidden';
            }).length;
        }
        $.extend($.expr.pseudos, {
            kendoFocusable: function (element) {
                var idx = $.attr(element, 'tabindex');
                return focusable(element, !isNaN(idx) && idx > -1);
            }
        });
        var MOUSE_EVENTS = [
            'mousedown',
            'mousemove',
            'mouseenter',
            'mouseleave',
            'mouseover',
            'mouseout',
            'mouseup',
            'click'
        ];
        var EXCLUDE_BUST_CLICK_SELECTOR = 'label, input, [data-rel=external]';
        var MouseEventNormalizer = {
            setupMouseMute: function () {
                var idx = 0, length = MOUSE_EVENTS.length, element = document.documentElement;
                if (MouseEventNormalizer.mouseTrap || !support.eventCapture) {
                    return;
                }
                MouseEventNormalizer.mouseTrap = true;
                MouseEventNormalizer.bustClick = false;
                MouseEventNormalizer.captureMouse = false;
                var handler = function (e) {
                    if (MouseEventNormalizer.captureMouse) {
                        if (e.type === 'click') {
                            if (MouseEventNormalizer.bustClick && !$(e.target).is(EXCLUDE_BUST_CLICK_SELECTOR)) {
                                e.preventDefault();
                                e.stopPropagation();
                            }
                        } else {
                            e.stopPropagation();
                        }
                    }
                };
                for (; idx < length; idx++) {
                    element.addEventListener(MOUSE_EVENTS[idx], handler, true);
                }
            },
            muteMouse: function (e) {
                MouseEventNormalizer.captureMouse = true;
                if (e.data.bustClick) {
                    MouseEventNormalizer.bustClick = true;
                }
                clearTimeout(MouseEventNormalizer.mouseTrapTimeoutID);
            },
            unMuteMouse: function () {
                clearTimeout(MouseEventNormalizer.mouseTrapTimeoutID);
                MouseEventNormalizer.mouseTrapTimeoutID = setTimeout(function () {
                    MouseEventNormalizer.captureMouse = false;
                    MouseEventNormalizer.bustClick = false;
                }, 400);
            }
        };
        var eventMap = {
            down: 'touchstart mousedown',
            move: 'mousemove touchmove',
            up: 'mouseup touchend touchcancel',
            cancel: 'mouseleave touchcancel'
        };
        if (support.touch && (support.mobileOS.ios || support.mobileOS.android)) {
            eventMap = {
                down: 'touchstart',
                move: 'touchmove',
                up: 'touchend touchcancel',
                cancel: 'touchcancel'
            };
        } else if (support.pointers) {
            eventMap = {
                down: 'pointerdown',
                move: 'pointermove',
                up: 'pointerup',
                cancel: 'pointercancel pointerleave'
            };
        } else if (support.msPointers) {
            eventMap = {
                down: 'MSPointerDown',
                move: 'MSPointerMove',
                up: 'MSPointerUp',
                cancel: 'MSPointerCancel MSPointerLeave'
            };
        }
        if (support.msPointers && !('onmspointerenter' in window)) {
            $.each({
                MSPointerEnter: 'MSPointerOver',
                MSPointerLeave: 'MSPointerOut'
            }, function (orig, fix) {
                $.event.special[orig] = {
                    delegateType: fix,
                    bindType: fix,
                    handle: function (event) {
                        var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj;
                        if (!related || related !== target && !$.contains(target, related)) {
                            event.type = handleObj.origType;
                            ret = handleObj.handler.apply(this, arguments);
                            event.type = fix;
                        }
                        return ret;
                    }
                };
            });
        }
        var getEventMap = function (e) {
                return eventMap[e] || e;
            }, eventRegEx = /([^ ]+)/g;
        kendo.applyEventMap = function (events, ns) {
            events = events.replace(eventRegEx, getEventMap);
            if (ns) {
                events = events.replace(eventRegEx, '$1.' + ns);
            }
            return events;
        };
        var on = $.fn.on;
        function kendoJQuery(selector, context) {
            return new kendoJQuery.fn.init(selector, context);
        }
        noDepricateExtend(true, kendoJQuery, $);
        kendoJQuery.fn = kendoJQuery.prototype = new $();
        kendoJQuery.fn.constructor = kendoJQuery;
        kendoJQuery.fn.init = function (selector, context) {
            if (context && context instanceof $ && !(context instanceof kendoJQuery)) {
                context = kendoJQuery(context);
            }
            return $.fn.init.call(this, selector, context, rootjQuery);
        };
        kendoJQuery.fn.init.prototype = kendoJQuery.fn;
        var rootjQuery = kendoJQuery(document);
        extend(kendoJQuery.fn, {
            handler: function (handler) {
                this.data('handler', handler);
                return this;
            },
            autoApplyNS: function (ns) {
                this.data('kendoNS', ns || kendo.guid());
                return this;
            },
            on: function () {
                var that = this, ns = that.data('kendoNS');
                if (arguments.length === 1) {
                    return on.call(that, arguments[0]);
                }
                var context = that, args = slice.call(arguments);
                if (typeof args[args.length - 1] === UNDEFINED) {
                    args.pop();
                }
                var callback = args[args.length - 1], events = kendo.applyEventMap(args[0], ns);
                if (support.mouseAndTouchPresent && events.search(/mouse|click/) > -1 && this[0] !== document.documentElement) {
                    MouseEventNormalizer.setupMouseMute();
                    var selector = args.length === 2 ? null : args[1], bustClick = events.indexOf('click') > -1 && events.indexOf('touchend') > -1;
                    on.call(this, {
                        touchstart: MouseEventNormalizer.muteMouse,
                        touchend: MouseEventNormalizer.unMuteMouse
                    }, selector, { bustClick: bustClick });
                }
                if (typeof callback === STRING) {
                    context = that.data('handler');
                    callback = context[callback];
                    args[args.length - 1] = function (e) {
                        callback.call(context, e);
                    };
                }
                args[0] = events;
                on.apply(that, args);
                return that;
            },
            kendoDestroy: function (ns) {
                ns = ns || this.data('kendoNS');
                if (ns) {
                    this.off('.' + ns);
                }
                return this;
            }
        });
        kendo.jQuery = kendoJQuery;
        kendo.eventMap = eventMap;
        kendo.timezone = function () {
            var months = {
                Jan: 0,
                Feb: 1,
                Mar: 2,
                Apr: 3,
                May: 4,
                Jun: 5,
                Jul: 6,
                Aug: 7,
                Sep: 8,
                Oct: 9,
                Nov: 10,
                Dec: 11
            };
            var days = {
                Sun: 0,
                Mon: 1,
                Tue: 2,
                Wed: 3,
                Thu: 4,
                Fri: 5,
                Sat: 6
            };
            function ruleToDate(year, rule) {
                var date;
                var targetDay;
                var ourDay;
                var month = rule[3];
                var on = rule[4];
                var time = rule[5];
                var cache = rule[8];
                if (!cache) {
                    rule[8] = cache = {};
                }
                if (cache[year]) {
                    return cache[year];
                }
                if (!isNaN(on)) {
                    date = new Date(Date.UTC(year, months[month], on, time[0], time[1], time[2], 0));
                } else if (on.indexOf('last') === 0) {
                    date = new Date(Date.UTC(year, months[month] + 1, 1, time[0] - 24, time[1], time[2], 0));
                    targetDay = days[on.substr(4, 3)];
                    ourDay = date.getUTCDay();
                    date.setUTCDate(date.getUTCDate() + targetDay - ourDay - (targetDay > ourDay ? 7 : 0));
                } else if (on.indexOf('>=') >= 0) {
                    date = new Date(Date.UTC(year, months[month], on.substr(5), time[0], time[1], time[2], 0));
                    targetDay = days[on.substr(0, 3)];
                    ourDay = date.getUTCDay();
                    date.setUTCDate(date.getUTCDate() + targetDay - ourDay + (targetDay < ourDay ? 7 : 0));
                }
                return cache[year] = date;
            }
            function findRule(utcTime, rules, zone) {
                rules = rules[zone];
                if (!rules) {
                    var time = zone.split(':');
                    var offset = 0;
                    if (time.length > 1) {
                        offset = time[0] * 60 + Number(time[1]);
                    }
                    return [
                        -1000000,
                        'max',
                        '-',
                        'Jan',
                        1,
                        [
                            0,
                            0,
                            0
                        ],
                        offset,
                        '-'
                    ];
                }
                var year = new Date(utcTime).getUTCFullYear();
                rules = jQuery.grep(rules, function (rule) {
                    var from = rule[0];
                    var to = rule[1];
                    return from <= year && (to >= year || from == year && to == 'only' || to == 'max');
                });
                rules.push(utcTime);
                rules.sort(function (a, b) {
                    if (typeof a != 'number') {
                        a = Number(ruleToDate(year, a));
                    }
                    if (typeof b != 'number') {
                        b = Number(ruleToDate(year, b));
                    }
                    return a - b;
                });
                var rule = rules[jQuery.inArray(utcTime, rules) - 1] || rules[rules.length - 1];
                return isNaN(rule) ? rule : null;
            }
            function findZone(utcTime, zones, timezone) {
                var zoneRules = zones[timezone];
                if (typeof zoneRules === 'string') {
                    zoneRules = zones[zoneRules];
                }
                if (!zoneRules) {
                    throw new Error('Timezone "' + timezone + '" is either incorrect, or kendo.timezones.min.js is not included.');
                }
                for (var idx = zoneRules.length - 1; idx >= 0; idx--) {
                    var until = zoneRules[idx][3];
                    if (until && utcTime > until) {
                        break;
                    }
                }
                var zone = zoneRules[idx + 1];
                if (!zone) {
                    throw new Error('Timezone "' + timezone + '" not found on ' + utcTime + '.');
                }
                return zone;
            }
            function zoneAndRule(utcTime, zones, rules, timezone) {
                if (typeof utcTime != NUMBER) {
                    utcTime = Date.UTC(utcTime.getFullYear(), utcTime.getMonth(), utcTime.getDate(), utcTime.getHours(), utcTime.getMinutes(), utcTime.getSeconds(), utcTime.getMilliseconds());
                }
                var zone = findZone(utcTime, zones, timezone);
                return {
                    zone: zone,
                    rule: findRule(utcTime, rules, zone[1])
                };
            }
            function offset(utcTime, timezone) {
                if (timezone == 'Etc/UTC' || timezone == 'Etc/GMT') {
                    return 0;
                }
                var info = zoneAndRule(utcTime, this.zones, this.rules, timezone);
                var zone = info.zone;
                var rule = info.rule;
                return kendo.parseFloat(rule ? zone[0] - rule[6] : zone[0]);
            }
            function abbr(utcTime, timezone) {
                var info = zoneAndRule(utcTime, this.zones, this.rules, timezone);
                var zone = info.zone;
                var rule = info.rule;
                var base = zone[2];
                if (base.indexOf('/') >= 0) {
                    return base.split('/')[rule && +rule[6] ? 1 : 0];
                } else if (base.indexOf('%s') >= 0) {
                    return base.replace('%s', !rule || rule[7] == '-' ? '' : rule[7]);
                }
                return base;
            }
            function convert(date, fromOffset, toOffset) {
                var tempToOffset = toOffset;
                var diff;
                if (typeof fromOffset == STRING) {
                    fromOffset = this.offset(date, fromOffset);
                }
                if (typeof toOffset == STRING) {
                    toOffset = this.offset(date, toOffset);
                }
                var fromLocalOffset = date.getTimezoneOffset();
                date = new Date(date.getTime() + (fromOffset - toOffset) * 60000);
                var toLocalOffset = date.getTimezoneOffset();
                if (typeof tempToOffset == STRING) {
                    tempToOffset = this.offset(date, tempToOffset);
                }
                diff = toLocalOffset - fromLocalOffset + (toOffset - tempToOffset);
                return new Date(date.getTime() + diff * 60000);
            }
            function apply(date, timezone) {
                return this.convert(date, date.getTimezoneOffset(), timezone);
            }
            function remove(date, timezone) {
                return this.convert(date, timezone, date.getTimezoneOffset());
            }
            function toLocalDate(time) {
                return this.apply(new Date(time), 'Etc/UTC');
            }
            return {
                zones: {},
                rules: {},
                offset: offset,
                convert: convert,
                apply: apply,
                remove: remove,
                abbr: abbr,
                toLocalDate: toLocalDate
            };
        }();
        kendo.date = function () {
            var MS_PER_MINUTE = 60000, MS_PER_DAY = 86400000;
            function adjustDST(date, hours) {
                if (hours === 0 && date.getHours() === 23) {
                    date.setHours(date.getHours() + 2);
                    return true;
                }
                return false;
            }
            function setDayOfWeek(date, day, dir) {
                var hours = date.getHours();
                dir = dir || 1;
                day = (day - date.getDay() + 7 * dir) % 7;
                date.setDate(date.getDate() + day);
                adjustDST(date, hours);
            }
            function dayOfWeek(date, day, dir) {
                date = new Date(date);
                setDayOfWeek(date, day, dir);
                return date;
            }
            function firstDayOfMonth(date) {
                return new Date(date.getFullYear(), date.getMonth(), 1);
            }
            function lastDayOfMonth(date) {
                var last = new Date(date.getFullYear(), date.getMonth() + 1, 0), first = firstDayOfMonth(date), timeOffset = Math.abs(last.getTimezoneOffset() - first.getTimezoneOffset());
                if (timeOffset) {
                    last.setHours(first.getHours() + timeOffset / 60);
                }
                return last;
            }
            function moveDateToWeekStart(date, weekStartDay) {
                if (weekStartDay !== 1) {
                    return addDays(dayOfWeek(date, weekStartDay, -1), 4);
                }
                return addDays(date, 4 - (date.getDay() || 7));
            }
            function calcWeekInYear(date, weekStartDay) {
                var firstWeekInYear = new Date(date.getFullYear(), 0, 1, -6);
                var newDate = moveDateToWeekStart(date, weekStartDay);
                var diffInMS = newDate.getTime() - firstWeekInYear.getTime();
                var days = Math.floor(diffInMS / MS_PER_DAY);
                return 1 + Math.floor(days / 7);
            }
            function weekInYear(date, weekStartDay) {
                if (weekStartDay === undefined) {
                    weekStartDay = kendo.culture().calendar.firstDay;
                }
                var prevWeekDate = addDays(date, -7);
                var nextWeekDate = addDays(date, 7);
                var weekNumber = calcWeekInYear(date, weekStartDay);
                if (weekNumber === 0) {
                    return calcWeekInYear(prevWeekDate, weekStartDay) + 1;
                }
                if (weekNumber === 53 && calcWeekInYear(nextWeekDate, weekStartDay) > 1) {
                    return 1;
                }
                return weekNumber;
            }
            function getDate(date) {
                date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
                adjustDST(date, 0);
                return date;
            }
            function toUtcTime(date) {
                return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
            }
            function getMilliseconds(date) {
                return toInvariantTime(date).getTime() - getDate(toInvariantTime(date));
            }
            function isInTimeRange(value, min, max) {
                var msMin = getMilliseconds(min), msMax = getMilliseconds(max), msValue;
                if (!value || msMin == msMax) {
                    return true;
                }
                if (min >= max) {
                    max += MS_PER_DAY;
                }
                msValue = getMilliseconds(value);
                if (msMin > msValue) {
                    msValue += MS_PER_DAY;
                }
                if (msMax < msMin) {
                    msMax += MS_PER_DAY;
                }
                return msValue >= msMin && msValue <= msMax;
            }
            function isInDateRange(value, min, max) {
                var msMin = min.getTime(), msMax = max.getTime(), msValue;
                if (msMin >= msMax) {
                    msMax += MS_PER_DAY;
                }
                msValue = value.getTime();
                return msValue >= msMin && msValue <= msMax;
            }
            function addDays(date, offset) {
                var hours = date.getHours();
                date = new Date(date);
                setTime(date, offset * MS_PER_DAY);
                adjustDST(date, hours);
                return date;
            }
            function setTime(date, milliseconds, ignoreDST) {
                var offset = date.getTimezoneOffset();
                var difference;
                date.setTime(date.getTime() + milliseconds);
                if (!ignoreDST) {
                    difference = date.getTimezoneOffset() - offset;
                    date.setTime(date.getTime() + difference * MS_PER_MINUTE);
                }
            }
            function setHours(date, time) {
                date = new Date(kendo.date.getDate(date).getTime() + kendo.date.getMilliseconds(time));
                adjustDST(date, time.getHours());
                return date;
            }
            function today() {
                return getDate(new Date());
            }
            function isToday(date) {
                return getDate(date).getTime() == today().getTime();
            }
            function toInvariantTime(date) {
                var staticDate = new Date(1980, 1, 1, 0, 0, 0);
                if (date) {
                    staticDate.setHours(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
                }
                return staticDate;
            }
            return {
                adjustDST: adjustDST,
                dayOfWeek: dayOfWeek,
                setDayOfWeek: setDayOfWeek,
                getDate: getDate,
                isInDateRange: isInDateRange,
                isInTimeRange: isInTimeRange,
                isToday: isToday,
                nextDay: function (date) {
                    return addDays(date, 1);
                },
                previousDay: function (date) {
                    return addDays(date, -1);
                },
                toUtcTime: toUtcTime,
                MS_PER_DAY: MS_PER_DAY,
                MS_PER_HOUR: 60 * MS_PER_MINUTE,
                MS_PER_MINUTE: MS_PER_MINUTE,
                setTime: setTime,
                setHours: setHours,
                addDays: addDays,
                today: today,
                toInvariantTime: toInvariantTime,
                firstDayOfMonth: firstDayOfMonth,
                lastDayOfMonth: lastDayOfMonth,
                weekInYear: weekInYear,
                getMilliseconds: getMilliseconds
            };
        }();
        kendo.stripWhitespace = function (element) {
            if (document.createNodeIterator) {
                var iterator = document.createNodeIterator(element, NodeFilter.SHOW_TEXT, function (node) {
                    return node.parentNode == element ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
                }, false);
                while (iterator.nextNode()) {
                    if (iterator.referenceNode && !iterator.referenceNode.textContent.trim()) {
                        iterator.referenceNode.parentNode.removeChild(iterator.referenceNode);
                    }
                }
            } else {
                for (var i = 0; i < element.childNodes.length; i++) {
                    var child = element.childNodes[i];
                    if (child.nodeType == 3 && !/\S/.test(child.nodeValue)) {
                        element.removeChild(child);
                        i--;
                    }
                    if (child.nodeType == 1) {
                        kendo.stripWhitespace(child);
                    }
                }
            }
        };
        var animationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
            setTimeout(callback, 1000 / 60);
        };
        kendo.animationFrame = function (callback) {
            animationFrame.call(window, callback);
        };
        var animationQueue = [];
        kendo.queueAnimation = function (callback) {
            animationQueue[animationQueue.length] = callback;
            if (animationQueue.length === 1) {
                kendo.runNextAnimation();
            }
        };
        kendo.runNextAnimation = function () {
            kendo.animationFrame(function () {
                if (animationQueue[0]) {
                    animationQueue.shift()();
                    if (animationQueue[0]) {
                        kendo.runNextAnimation();
                    }
                }
            });
        };
        kendo.parseQueryStringParams = function (url) {
            var queryString = url.split('?')[1] || '', params = {}, paramParts = queryString.split(/&|=/), length = paramParts.length, idx = 0;
            for (; idx < length; idx += 2) {
                if (paramParts[idx] !== '') {
                    params[decodeURIComponent(paramParts[idx])] = decodeURIComponent(paramParts[idx + 1]);
                }
            }
            return params;
        };
        kendo.elementUnderCursor = function (e) {
            if (typeof e.x.client != 'undefined') {
                return document.elementFromPoint(e.x.client, e.y.client);
            }
        };
        kendo.wheelDeltaY = function (jQueryEvent) {
            var e = jQueryEvent.originalEvent, deltaY = e.wheelDeltaY, delta;
            if (e.wheelDelta) {
                if (deltaY === undefined || deltaY) {
                    delta = e.wheelDelta;
                }
            } else if (e.detail && e.axis === e.VERTICAL_AXIS) {
                delta = -e.detail * 10;
            }
            return delta;
        };
        kendo.throttle = function (fn, delay) {
            var timeout;
            var lastExecTime = 0;
            if (!delay || delay <= 0) {
                return fn;
            }
            var throttled = function () {
                var that = this;
                var elapsed = +new Date() - lastExecTime;
                var args = arguments;
                function exec() {
                    fn.apply(that, args);
                    lastExecTime = +new Date();
                }
                if (!lastExecTime) {
                    return exec();
                }
                if (timeout) {
                    clearTimeout(timeout);
                }
                if (elapsed > delay) {
                    exec();
                } else {
                    timeout = setTimeout(exec, delay - elapsed);
                }
            };
            throttled.cancel = function () {
                clearTimeout(timeout);
            };
            return throttled;
        };
        kendo.caret = function (element, start, end) {
            var rangeElement;
            var isPosition = start !== undefined;
            if (end === undefined) {
                end = start;
            }
            if (element[0]) {
                element = element[0];
            }
            if (isPosition && element.disabled) {
                return;
            }
            try {
                if (element.selectionStart !== undefined) {
                    if (isPosition) {
                        element.focus();
                        var mobile = support.mobileOS;
                        if (mobile.wp || mobile.android) {
                            setTimeout(function () {
                                element.setSelectionRange(start, end);
                            }, 0);
                        } else {
                            element.setSelectionRange(start, end);
                        }
                    } else {
                        start = [
                            element.selectionStart,
                            element.selectionEnd
                        ];
                    }
                } else if (document.selection) {
                    if ($(element).is(':visible')) {
                        element.focus();
                    }
                    rangeElement = element.createTextRange();
                    if (isPosition) {
                        rangeElement.collapse(true);
                        rangeElement.moveStart('character', start);
                        rangeElement.moveEnd('character', end - start);
                        rangeElement.select();
                    } else {
                        var rangeDuplicated = rangeElement.duplicate(), selectionStart, selectionEnd;
                        rangeElement.moveToBookmark(document.selection.createRange().getBookmark());
                        rangeDuplicated.setEndPoint('EndToStart', rangeElement);
                        selectionStart = rangeDuplicated.text.length;
                        selectionEnd = selectionStart + rangeElement.text.length;
                        start = [
                            selectionStart,
                            selectionEnd
                        ];
                    }
                }
            } catch (e) {
                start = [];
            }
            return start;
        };
        kendo.compileMobileDirective = function (element, scope) {
            var angular = window.angular;
            element.attr('data-' + kendo.ns + 'role', element[0].tagName.toLowerCase().replace('kendo-mobile-', '').replace('-', ''));
            angular.element(element).injector().invoke([
                '$compile',
                function ($compile) {
                    $compile(element)(scope);
                    if (!/^\$(digest|apply)$/.test(scope.$$phase)) {
                        scope.$digest();
                    }
                }
            ]);
            return kendo.widgetInstance(element, kendo.mobile.ui);
        };
        kendo.antiForgeryTokens = function () {
            var tokens = {}, csrf_token = $('meta[name=csrf-token],meta[name=_csrf]').attr('content'), csrf_param = $('meta[name=csrf-param],meta[name=_csrf_header]').attr('content');
            $('input[name^=\'__RequestVerificationToken\']').each(function () {
                tokens[this.name] = this.value;
            });
            if (csrf_param !== undefined && csrf_token !== undefined) {
                tokens[csrf_param] = csrf_token;
            }
            return tokens;
        };
        kendo.cycleForm = function (form) {
            var firstElement = form.find('input, .k-widget').first();
            var lastElement = form.find('button, .k-button').last();
            function focus(el) {
                var widget = kendo.widgetInstance(el);
                if (widget && widget.focus) {
                    widget.focus();
                } else {
                    el.focus();
                }
            }
            lastElement.on('keydown', function (e) {
                if (e.keyCode == kendo.keys.TAB && !e.shiftKey) {
                    e.preventDefault();
                    focus(firstElement);
                }
            });
            firstElement.on('keydown', function (e) {
                if (e.keyCode == kendo.keys.TAB && e.shiftKey) {
                    e.preventDefault();
                    focus(lastElement);
                }
            });
        };
        kendo.focusElement = function (element) {
            var scrollTopPositions = [];
            var scrollableParents = element.parentsUntil('body').filter(function (index, element) {
                var computedStyle = kendo.getComputedStyles(element, ['overflow']);
                return computedStyle.overflow !== 'visible';
            }).add(window);
            scrollableParents.each(function (index, parent) {
                scrollTopPositions[index] = $(parent).scrollTop();
            });
            try {
                element[0].setActive();
            } catch (e) {
                element[0].focus();
            }
            scrollableParents.each(function (index, parent) {
                $(parent).scrollTop(scrollTopPositions[index]);
            });
        };
        kendo.matchesMedia = function (mediaQuery) {
            var media = kendo._bootstrapToMedia(mediaQuery) || mediaQuery;
            return support.matchMedia && window.matchMedia(media).matches;
        };
        kendo._bootstrapToMedia = function (bootstrapMedia) {
            return {
                'xs': '(max-width: 576px)',
                'sm': '(min-width: 576px)',
                'md': '(min-width: 768px)',
                'lg': '(min-width: 992px)',
                'xl': '(min-width: 1200px)'
            }[bootstrapMedia];
        };
        (function () {
            function postToProxy(dataURI, fileName, proxyURL, proxyTarget) {
                var form = $('<form>').attr({
                    action: proxyURL,
                    method: 'POST',
                    target: proxyTarget
                });
                var data = kendo.antiForgeryTokens();
                data.fileName = fileName;
                var parts = dataURI.split(';base64,');
                data.contentType = parts[0].replace('data:', '');
                data.base64 = parts[1];
                for (var name in data) {
                    if (data.hasOwnProperty(name)) {
                        $('<input>').attr({
                            value: data[name],
                            name: name,
                            type: 'hidden'
                        }).appendTo(form);
                    }
                }
                form.appendTo('body').submit().remove();
            }
            var fileSaver = document.createElement('a');
            var downloadAttribute = 'download' in fileSaver && !kendo.support.browser.edge;
            function saveAsBlob(dataURI, fileName) {
                var blob = dataURI;
                if (typeof dataURI == 'string') {
                    var parts = dataURI.split(';base64,');
                    var contentType = parts[0];
                    var base64 = atob(parts[1]);
                    var array = new Uint8Array(base64.length);
                    for (var idx = 0; idx < base64.length; idx++) {
                        array[idx] = base64.charCodeAt(idx);
                    }
                    blob = new Blob([array.buffer], { type: contentType });
                }
                navigator.msSaveBlob(blob, fileName);
            }
            function saveAsDataURI(dataURI, fileName) {
                if (window.Blob && dataURI instanceof Blob) {
                    dataURI = URL.createObjectURL(dataURI);
                }
                fileSaver.download = fileName;
                fileSaver.href = dataURI;
                var e = document.createEvent('MouseEvents');
                e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                fileSaver.dispatchEvent(e);
                setTimeout(function () {
                    URL.revokeObjectURL(dataURI);
                });
            }
            kendo.saveAs = function (options) {
                var save = postToProxy;
                if (!options.forceProxy) {
                    if (downloadAttribute) {
                        save = saveAsDataURI;
                    } else if (navigator.msSaveBlob) {
                        save = saveAsBlob;
                    }
                }
                save(options.dataURI, options.fileName, options.proxyURL, options.proxyTarget);
            };
        }());
        kendo.proxyModelSetters = function proxyModelSetters(data) {
            var observable = {};
            Object.keys(data || {}).forEach(function (property) {
                Object.defineProperty(observable, property, {
                    get: function () {
                        return data[property];
                    },
                    set: function (value) {
                        data[property] = value;
                        data.dirty = true;
                    }
                });
            });
            return observable;
        };
    }(jQuery, window));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.router', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'router',
        name: 'Router',
        category: 'framework',
        description: 'The Router class is responsible for tracking the application state and navigating between the application states.',
        depends: ['core'],
        hidden: false
    };
    (function ($, undefined) {
        var kendo = window.kendo, CHANGE = 'change', BACK = 'back', SAME = 'same', support = kendo.support, location = window.location, history = window.history, CHECK_URL_INTERVAL = 50, BROKEN_BACK_NAV = kendo.support.browser.msie, hashStrip = /^#*/, document = window.document;
        function absoluteURL(path, pathPrefix) {
            if (!pathPrefix) {
                return path;
            }
            if (path + '/' === pathPrefix) {
                path = pathPrefix;
            }
            var regEx = new RegExp('^' + pathPrefix, 'i');
            if (!regEx.test(path)) {
                path = pathPrefix + '/' + path;
            }
            return location.protocol + '//' + (location.host + '/' + path).replace(/\/\/+/g, '/');
        }
        function hashDelimiter(bang) {
            return bang ? '#!' : '#';
        }
        function locationHash(hashDelimiter) {
            var href = location.href;
            if (hashDelimiter === '#!' && href.indexOf('#') > -1 && href.indexOf('#!') < 0) {
                return null;
            }
            return href.split(hashDelimiter)[1] || '';
        }
        function stripRoot(root, url) {
            if (url.indexOf(root) === 0) {
                return url.substr(root.length).replace(/\/\//g, '/');
            } else {
                return url;
            }
        }
        var HistoryAdapter = kendo.Class.extend({
            back: function () {
                if (BROKEN_BACK_NAV) {
                    setTimeout(function () {
                        history.back();
                    });
                } else {
                    history.back();
                }
            },
            forward: function () {
                if (BROKEN_BACK_NAV) {
                    setTimeout(function () {
                        history.forward();
                    });
                } else {
                    history.forward();
                }
            },
            length: function () {
                return history.length;
            },
            replaceLocation: function (url) {
                location.replace(url);
            }
        });
        var PushStateAdapter = HistoryAdapter.extend({
            init: function (root) {
                this.root = root;
            },
            navigate: function (to) {
                history.pushState({}, document.title, absoluteURL(to, this.root));
            },
            replace: function (to) {
                history.replaceState({}, document.title, absoluteURL(to, this.root));
            },
            normalize: function (url) {
                return stripRoot(this.root, url);
            },
            current: function () {
                var current = location.pathname;
                if (location.search) {
                    current += location.search;
                }
                return stripRoot(this.root, current);
            },
            change: function (callback) {
                $(window).bind('popstate.kendo', callback);
            },
            stop: function () {
                $(window).unbind('popstate.kendo');
            },
            normalizeCurrent: function (options) {
                var fixedUrl, root = options.root, pathname = location.pathname, hash = locationHash(hashDelimiter(options.hashBang));
                if (root === pathname + '/') {
                    fixedUrl = root;
                }
                if (root === pathname && hash) {
                    fixedUrl = absoluteURL(hash.replace(hashStrip, ''), root);
                }
                if (fixedUrl) {
                    history.pushState({}, document.title, fixedUrl);
                }
            }
        });
        function fixHash(url) {
            return url.replace(/^(#)?/, '#');
        }
        function fixBang(url) {
            return url.replace(/^(#(!)?)?/, '#!');
        }
        var HashAdapter = HistoryAdapter.extend({
            init: function (bang) {
                this._id = kendo.guid();
                this.prefix = hashDelimiter(bang);
                this.fix = bang ? fixBang : fixHash;
            },
            navigate: function (to) {
                location.hash = this.fix(to);
            },
            replace: function (to) {
                this.replaceLocation(this.fix(to));
            },
            normalize: function (url) {
                if (url.indexOf(this.prefix) < 0) {
                    return url;
                } else {
                    return url.split(this.prefix)[1];
                }
            },
            change: function (callback) {
                if (support.hashChange) {
                    $(window).on('hashchange.' + this._id, callback);
                } else {
                    this._interval = setInterval(callback, CHECK_URL_INTERVAL);
                }
            },
            stop: function () {
                $(window).off('hashchange.' + this._id);
                clearInterval(this._interval);
            },
            current: function () {
                return locationHash(this.prefix);
            },
            normalizeCurrent: function (options) {
                var pathname = location.pathname, root = options.root;
                if (options.pushState && root !== pathname) {
                    this.replaceLocation(root + this.prefix + stripRoot(root, pathname));
                    return true;
                }
                return false;
            }
        });
        var History = kendo.Observable.extend({
            start: function (options) {
                options = options || {};
                this.bind([
                    CHANGE,
                    BACK,
                    SAME
                ], options);
                if (this._started) {
                    return;
                }
                this._started = true;
                options.root = options.root || '/';
                var adapter = this.createAdapter(options), current;
                if (adapter.normalizeCurrent(options)) {
                    return;
                }
                current = adapter.current();
                $.extend(this, {
                    adapter: adapter,
                    root: options.root,
                    historyLength: adapter.length(),
                    current: current,
                    locations: [current]
                });
                adapter.change($.proxy(this, '_checkUrl'));
            },
            createAdapter: function (options) {
                return support.pushState && options.pushState ? new PushStateAdapter(options.root) : new HashAdapter(options.hashBang);
            },
            stop: function () {
                if (!this._started) {
                    return;
                }
                this.adapter.stop();
                this.unbind(CHANGE);
                this._started = false;
            },
            change: function (callback) {
                this.bind(CHANGE, callback);
            },
            replace: function (to, silent) {
                this._navigate(to, silent, function (adapter) {
                    adapter.replace(to);
                    this.locations[this.locations.length - 1] = this.current;
                });
            },
            navigate: function (to, silent) {
                if (to === '#:back') {
                    this.backCalled = true;
                    this.adapter.back();
                    return;
                }
                this._navigate(to, silent, function (adapter) {
                    adapter.navigate(to);
                    this.locations.push(this.current);
                });
            },
            _navigate: function (to, silent, callback) {
                var adapter = this.adapter;
                to = adapter.normalize(to);
                if (this.current === to || this.current === decodeURIComponent(to)) {
                    this.trigger(SAME);
                    return;
                }
                if (!silent) {
                    if (this.trigger(CHANGE, {
                            url: to,
                            decode: false
                        })) {
                        return;
                    }
                }
                this.current = to;
                callback.call(this, adapter);
                this.historyLength = adapter.length();
            },
            _checkUrl: function () {
                var adapter = this.adapter, current = adapter.current(), newLength = adapter.length(), navigatingInExisting = this.historyLength === newLength, back = current === this.locations[this.locations.length - 2] && navigatingInExisting, backCalled = this.backCalled, prev = this.current;
                if (current === null || this.current === current || this.current === decodeURIComponent(current)) {
                    return true;
                }
                this.historyLength = newLength;
                this.backCalled = false;
                this.current = current;
                if (back && this.trigger('back', {
                        url: prev,
                        to: current
                    })) {
                    adapter.forward();
                    this.current = prev;
                    return;
                }
                if (this.trigger(CHANGE, {
                        url: current,
                        backButtonPressed: !backCalled
                    })) {
                    if (back) {
                        adapter.forward();
                    } else {
                        adapter.back();
                        this.historyLength--;
                    }
                    this.current = prev;
                    return;
                }
                if (back) {
                    this.locations.pop();
                } else {
                    this.locations.push(current);
                }
            }
        });
        kendo.History = History;
        kendo.History.HistoryAdapter = HistoryAdapter;
        kendo.History.HashAdapter = HashAdapter;
        kendo.History.PushStateAdapter = PushStateAdapter;
        kendo.absoluteURL = absoluteURL;
        kendo.history = new History();
    }(window.kendo.jQuery));
    (function () {
        var kendo = window.kendo, history = kendo.history, Observable = kendo.Observable, INIT = 'init', ROUTE_MISSING = 'routeMissing', CHANGE = 'change', BACK = 'back', SAME = 'same', optionalParam = /\((.*?)\)/g, namedParam = /(\(\?)?:\w+/g, splatParam = /\*\w+/g, escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
        function namedParamReplace(match, optional) {
            return optional ? match : '([^/]+)';
        }
        function routeToRegExp(route, ignoreCase) {
            return new RegExp('^' + route.replace(escapeRegExp, '\\$&').replace(optionalParam, '(?:$1)?').replace(namedParam, namedParamReplace).replace(splatParam, '(.*?)') + '$', ignoreCase ? 'i' : '');
        }
        function stripUrl(url) {
            return url.replace(/(\?.*)|(#.*)/g, '');
        }
        var Route = kendo.Class.extend({
            init: function (route, callback, ignoreCase) {
                if (!(route instanceof RegExp)) {
                    route = routeToRegExp(route, ignoreCase);
                }
                this.route = route;
                this._callback = callback;
            },
            callback: function (url, back, decode) {
                var params, idx = 0, length, queryStringParams = kendo.parseQueryStringParams(url);
                queryStringParams._back = back;
                url = stripUrl(url);
                params = this.route.exec(url).slice(1);
                length = params.length;
                if (decode) {
                    for (; idx < length; idx++) {
                        if (typeof params[idx] !== 'undefined') {
                            params[idx] = decodeURIComponent(params[idx]);
                        }
                    }
                }
                params.push(queryStringParams);
                this._callback.apply(null, params);
            },
            worksWith: function (url, back, decode) {
                if (this.route.test(stripUrl(url))) {
                    this.callback(url, back, decode);
                    return true;
                } else {
                    return false;
                }
            }
        });
        var Router = Observable.extend({
            init: function (options) {
                if (!options) {
                    options = {};
                }
                Observable.fn.init.call(this);
                this.routes = [];
                this.pushState = options.pushState;
                this.hashBang = options.hashBang;
                this.root = options.root;
                this.ignoreCase = options.ignoreCase !== false;
                this.bind([
                    INIT,
                    ROUTE_MISSING,
                    CHANGE,
                    SAME,
                    BACK
                ], options);
            },
            destroy: function () {
                history.unbind(CHANGE, this._urlChangedProxy);
                history.unbind(SAME, this._sameProxy);
                history.unbind(BACK, this._backProxy);
                this.unbind();
            },
            start: function () {
                var that = this, sameProxy = function () {
                        that._same();
                    }, backProxy = function (e) {
                        that._back(e);
                    }, urlChangedProxy = function (e) {
                        that._urlChanged(e);
                    };
                history.start({
                    same: sameProxy,
                    change: urlChangedProxy,
                    back: backProxy,
                    pushState: that.pushState,
                    hashBang: that.hashBang,
                    root: that.root
                });
                var initEventObject = {
                    url: history.current || '/',
                    preventDefault: $.noop
                };
                if (!that.trigger(INIT, initEventObject)) {
                    that._urlChanged(initEventObject);
                }
                this._urlChangedProxy = urlChangedProxy;
                this._backProxy = backProxy;
            },
            route: function (route, callback) {
                this.routes.push(new Route(route, callback, this.ignoreCase));
            },
            navigate: function (url, silent) {
                kendo.history.navigate(url, silent);
            },
            replace: function (url, silent) {
                kendo.history.replace(url, silent);
            },
            _back: function (e) {
                if (this.trigger(BACK, {
                        url: e.url,
                        to: e.to
                    })) {
                    e.preventDefault();
                }
            },
            _same: function () {
                this.trigger(SAME);
            },
            _urlChanged: function (e) {
                var url = e.url;
                var decode = !!e.decode;
                var back = e.backButtonPressed;
                if (!url) {
                    url = '/';
                }
                if (this.trigger(CHANGE, {
                        url: e.url,
                        params: kendo.parseQueryStringParams(e.url),
                        backButtonPressed: back
                    })) {
                    e.preventDefault();
                    return;
                }
                var idx = 0, routes = this.routes, route, length = routes.length;
                for (; idx < length; idx++) {
                    route = routes[idx];
                    if (route.worksWith(url, back, decode)) {
                        return;
                    }
                }
                if (this.trigger(ROUTE_MISSING, {
                        url: url,
                        params: kendo.parseQueryStringParams(url),
                        backButtonPressed: back
                    })) {
                    e.preventDefault();
                }
            }
        });
        kendo.Router = Router;
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.data.odata', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'data.odata',
        name: 'OData',
        category: 'framework',
        depends: ['core'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, NEWLINE = '\r\n', DOUBLELINE = '\r\n\r\n', isFunction = kendo.isFunction, odataFilters = {
                eq: 'eq',
                neq: 'ne',
                gt: 'gt',
                gte: 'ge',
                lt: 'lt',
                lte: 'le',
                contains: 'substringof',
                doesnotcontain: 'substringof',
                endswith: 'endswith',
                startswith: 'startswith',
                isnull: 'eq',
                isnotnull: 'ne',
                isnullorempty: 'eq',
                isnotnullorempty: 'ne',
                isempty: 'eq',
                isnotempty: 'ne'
            }, odataFiltersVersionFour = extend({}, odataFilters, { contains: 'contains' }), mappers = {
                pageSize: $.noop,
                page: $.noop,
                filter: function (params, filter, useVersionFour) {
                    if (filter) {
                        filter = toOdataFilter(filter, useVersionFour);
                        if (filter) {
                            params.$filter = filter;
                        }
                    }
                },
                sort: function (params, orderby) {
                    var expr = $.map(orderby, function (value) {
                        var order = value.field.replace(/\./g, '/');
                        if (value.dir === 'desc') {
                            order += ' desc';
                        }
                        return order;
                    }).join(',');
                    if (expr) {
                        params.$orderby = expr;
                    }
                },
                skip: function (params, skip) {
                    if (skip) {
                        params.$skip = skip;
                    }
                },
                take: function (params, take) {
                    if (take) {
                        params.$top = take;
                    }
                }
            }, defaultDataType = { read: { dataType: 'jsonp' } };
        function toOdataFilter(filter, useOdataFour) {
            var result = [], logic = filter.logic || 'and', idx, length, field, type, format, operator, value, ignoreCase, filters = filter.filters;
            for (idx = 0, length = filters.length; idx < length; idx++) {
                filter = filters[idx];
                field = filter.field;
                value = filter.value;
                operator = filter.operator;
                if (filter.filters) {
                    filter = toOdataFilter(filter, useOdataFour);
                } else {
                    ignoreCase = filter.ignoreCase;
                    field = field.replace(/\./g, '/');
                    filter = odataFilters[operator];
                    if (useOdataFour) {
                        filter = odataFiltersVersionFour[operator];
                    }
                    if (operator === 'isnullorempty') {
                        filter = kendo.format('{0} {1} null or {0} {1} \'\'', field, filter);
                    } else if (operator === 'isnotnullorempty') {
                        filter = kendo.format('{0} {1} null and {0} {1} \'\'', field, filter);
                    } else if (operator === 'isnull' || operator === 'isnotnull') {
                        filter = kendo.format('{0} {1} null', field, filter);
                    } else if (operator === 'isempty' || operator === 'isnotempty') {
                        filter = kendo.format('{0} {1} \'\'', field, filter);
                    } else if (filter && value !== undefined) {
                        type = $.type(value);
                        if (type === 'string') {
                            format = '\'{1}\'';
                            value = value.replace(/'/g, '\'\'');
                            if (ignoreCase === true) {
                                field = 'tolower(' + field + ')';
                            }
                        } else if (type === 'date') {
                            if (useOdataFour) {
                                format = '{1:yyyy-MM-ddTHH:mm:ss+00:00}';
                                value = kendo.timezone.apply(value, 'Etc/UTC');
                            } else {
                                format = 'datetime\'{1:yyyy-MM-ddTHH:mm:ss}\'';
                            }
                        } else {
                            format = '{1}';
                        }
                        if (filter.length > 3) {
                            if (filter !== 'substringof') {
                                format = '{0}({2},' + format + ')';
                            } else {
                                format = '{0}(' + format + ',{2})';
                                if (operator === 'doesnotcontain') {
                                    if (useOdataFour) {
                                        format = '{0}({2},\'{1}\') eq -1';
                                        filter = 'indexof';
                                    } else {
                                        format += ' eq false';
                                    }
                                }
                            }
                        } else {
                            format = '{2} {0} ' + format;
                        }
                        filter = kendo.format(format, filter, value, field);
                    }
                }
                result.push(filter);
            }
            filter = result.join(' ' + logic + ' ');
            if (result.length > 1) {
                filter = '(' + filter + ')';
            }
            return filter;
        }
        function stripMetadata(obj) {
            for (var name in obj) {
                if (name.indexOf('@odata') === 0) {
                    delete obj[name];
                }
            }
        }
        function hex16() {
            return Math.floor((1 + Math.random()) * 65536).toString(16).substr(1);
        }
        function createBoundary(prefix) {
            return prefix + hex16() + '-' + hex16() + '-' + hex16();
        }
        function createDelimeter(boundary, close) {
            var result = NEWLINE + '--' + boundary;
            if (close) {
                result += '--';
            }
            return result;
        }
        function createCommand(transport, item, httpVerb, command) {
            var transportUrl = transport.options[command].url;
            var commandPrefix = kendo.format('{0} ', httpVerb);
            if (isFunction(transportUrl)) {
                return commandPrefix + transportUrl(item);
            } else {
                return commandPrefix + transportUrl;
            }
        }
        function getOperationHeader(changeset, changeId) {
            var header = '';
            header += createDelimeter(changeset, false);
            header += NEWLINE + 'Content-Type: application/http';
            header += NEWLINE + 'Content-Transfer-Encoding: binary';
            header += NEWLINE + 'Content-ID: ' + changeId;
            return header;
        }
        function getOperationContent(item) {
            var content = '';
            content += NEWLINE + 'Content-Type: application/json;odata=minimalmetadata';
            content += NEWLINE + 'Prefer: return=representation';
            content += DOUBLELINE + kendo.stringify(item);
            return content;
        }
        function getOperations(collection, changeset, changeId, command, transport, skipContent) {
            var requestBody = '';
            for (var i = 0; i < collection.length; i++) {
                requestBody += getOperationHeader(changeset, changeId);
                requestBody += DOUBLELINE + createCommand(transport, collection[i], transport.options[command].type, command) + ' HTTP/1.1';
                if (!skipContent) {
                    requestBody += getOperationContent(collection[i]);
                }
                requestBody += NEWLINE;
                changeId++;
            }
            return requestBody;
        }
        function processCollection(colection, boundary, changeset, changeId, transport, command, skipContent) {
            var requestBody = '';
            requestBody += getBoundary(boundary, changeset);
            requestBody += getOperations(colection, changeset, changeId, command, transport, skipContent);
            requestBody += createDelimeter(changeset, true);
            requestBody += NEWLINE;
            return requestBody;
        }
        function getBoundary(boundary, changeset) {
            var requestBody = '';
            requestBody += '--' + boundary + NEWLINE;
            requestBody += 'Content-Type: multipart/mixed; boundary=' + changeset + NEWLINE;
            return requestBody;
        }
        function createBatchRequest(transport, colections) {
            var options = {};
            var boundary = createBoundary('sf_batch_');
            var requestBody = '';
            var changeId = 0;
            var batchURL = transport.options.batch.url;
            var changeset = createBoundary('sf_changeset_');
            options.type = transport.options.batch.type;
            options.url = isFunction(batchURL) ? batchURL() : batchURL;
            options.headers = { 'Content-Type': 'multipart/mixed; boundary=' + boundary };
            if (colections.updated.length) {
                requestBody += processCollection(colections.updated, boundary, changeset, changeId, transport, 'update', false);
                changeId += colections.updated.length;
                changeset = createBoundary('sf_changeset_');
            }
            if (colections.destroyed.length) {
                requestBody += processCollection(colections.destroyed, boundary, changeset, changeId, transport, 'destroy', true);
                changeId += colections.destroyed.length;
                changeset = createBoundary('sf_changeset_');
            }
            if (colections.created.length) {
                requestBody += processCollection(colections.created, boundary, changeset, changeId, transport, 'create', false);
            }
            requestBody += createDelimeter(boundary, true);
            options.data = requestBody;
            return options;
        }
        function parseBatchResponse(responseText) {
            var responseMarkers = responseText.match(/--changesetresponse_[a-z0-9-]+$/gm);
            var markerIndex = 0;
            var collections = [];
            var changeBody;
            var status;
            var code;
            var marker;
            var jsonModel;
            collections.push({
                models: [],
                passed: true
            });
            for (var i = 0; i < responseMarkers.length; i++) {
                marker = responseMarkers[i];
                if (marker.lastIndexOf('--', marker.length - 1)) {
                    if (i < responseMarkers.length - 1) {
                        collections.push({
                            models: [],
                            passed: true
                        });
                    }
                    continue;
                }
                if (!markerIndex) {
                    markerIndex = responseText.indexOf(marker);
                } else {
                    markerIndex = responseText.indexOf(marker, markerIndex + marker.length);
                }
                changeBody = responseText.substring(markerIndex, responseText.indexOf('--', markerIndex + 1));
                status = changeBody.match(/^HTTP\/1\.\d (\d{3}) (.*)$/gm).pop();
                code = kendo.parseFloat(status.match(/\d{3}/g).pop());
                if (code >= 200 && code <= 299) {
                    jsonModel = changeBody.match(/\{.*\}/gm);
                    if (jsonModel) {
                        collections[collections.length - 1].models.push(JSON.parse(jsonModel[0]));
                    }
                } else {
                    collections[collections.length - 1].passed = false;
                }
            }
            return collections;
        }
        extend(true, kendo.data, {
            schemas: {
                odata: {
                    type: 'json',
                    data: function (data) {
                        return data.d.results || [data.d];
                    },
                    total: 'd.__count'
                }
            },
            transports: {
                odata: {
                    read: {
                        cache: true,
                        dataType: 'jsonp',
                        jsonp: '$callback'
                    },
                    update: {
                        cache: true,
                        dataType: 'json',
                        contentType: 'application/json',
                        type: 'PUT'
                    },
                    create: {
                        cache: true,
                        dataType: 'json',
                        contentType: 'application/json',
                        type: 'POST'
                    },
                    destroy: {
                        cache: true,
                        dataType: 'json',
                        type: 'DELETE'
                    },
                    parameterMap: function (options, type, useVersionFour) {
                        var params, value, option, dataType;
                        options = options || {};
                        type = type || 'read';
                        dataType = (this.options || defaultDataType)[type];
                        dataType = dataType ? dataType.dataType : 'json';
                        if (type === 'read') {
                            params = { $inlinecount: 'allpages' };
                            if (dataType != 'json') {
                                params.$format = 'json';
                            }
                            for (option in options) {
                                if (mappers[option]) {
                                    mappers[option](params, options[option], useVersionFour);
                                } else {
                                    params[option] = options[option];
                                }
                            }
                        } else {
                            if (dataType !== 'json') {
                                throw new Error('Only json dataType can be used for ' + type + ' operation.');
                            }
                            if (type !== 'destroy') {
                                for (option in options) {
                                    value = options[option];
                                    if (typeof value === 'number') {
                                        options[option] = value + '';
                                    }
                                }
                                params = kendo.stringify(options);
                            }
                        }
                        return params;
                    }
                }
            }
        });
        extend(true, kendo.data, {
            schemas: {
                'odata-v4': {
                    type: 'json',
                    data: function (data) {
                        if ($.isArray(data)) {
                            for (var i = 0; i < data.length; i++) {
                                stripMetadata(data[i]);
                            }
                            return data;
                        } else {
                            data = $.extend({}, data);
                            stripMetadata(data);
                            if (data.value) {
                                return data.value;
                            }
                            return [data];
                        }
                    },
                    total: function (data) {
                        return data['@odata.count'];
                    }
                }
            },
            transports: {
                'odata-v4': {
                    batch: { type: 'POST' },
                    read: {
                        cache: true,
                        dataType: 'json'
                    },
                    update: {
                        cache: true,
                        dataType: 'json',
                        contentType: 'application/json;IEEE754Compatible=true',
                        type: 'PUT'
                    },
                    create: {
                        cache: true,
                        dataType: 'json',
                        contentType: 'application/json;IEEE754Compatible=true',
                        type: 'POST'
                    },
                    destroy: {
                        cache: true,
                        dataType: 'json',
                        type: 'DELETE'
                    },
                    parameterMap: function (options, type) {
                        var result = kendo.data.transports.odata.parameterMap(options, type, true);
                        if (type == 'read') {
                            result.$count = true;
                            delete result.$inlinecount;
                        }
                        return result;
                    },
                    submit: function (e) {
                        var that = this;
                        var options = createBatchRequest(that, e.data);
                        var collections = e.data;
                        if (!collections.updated.length && !collections.destroyed.length && !collections.created.length) {
                            return;
                        }
                        $.ajax(extend(true, {}, {
                            success: function (response) {
                                var responses = parseBatchResponse(response);
                                var index = 0;
                                var current;
                                if (collections.updated.length) {
                                    current = responses[index];
                                    if (current.passed) {
                                        e.success(current.models.length ? current.models : [], 'update');
                                    }
                                    index++;
                                }
                                if (collections.destroyed.length) {
                                    current = responses[index];
                                    if (current.passed) {
                                        e.success([], 'destroy');
                                    }
                                    index++;
                                }
                                if (collections.created.length) {
                                    current = responses[index];
                                    if (current.passed) {
                                        e.success(current.models, 'create');
                                    }
                                }
                            },
                            error: function (response, status, error) {
                                e.error(response, status, error);
                            }
                        }, options));
                    }
                }
            }
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.data.xml', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'data.xml',
        name: 'XML',
        category: 'framework',
        depends: ['core'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, isArray = $.isArray, isPlainObject = $.isPlainObject, map = $.map, each = $.each, extend = $.extend, getter = kendo.getter, Class = kendo.Class;
        var XmlDataReader = Class.extend({
            init: function (options) {
                var that = this, total = options.total, model = options.model, parse = options.parse, errors = options.errors, serialize = options.serialize, data = options.data;
                if (model) {
                    if (isPlainObject(model)) {
                        var base = options.modelBase || kendo.data.Model;
                        if (model.fields) {
                            each(model.fields, function (field, value) {
                                if (isPlainObject(value) && value.field) {
                                    if (!$.isFunction(value.field)) {
                                        value = extend(value, { field: that.getter(value.field) });
                                    }
                                } else {
                                    value = { field: that.getter(value) };
                                }
                                model.fields[field] = value;
                            });
                        }
                        var id = model.id;
                        if (id) {
                            var idField = {};
                            idField[that.xpathToMember(id, true)] = { field: that.getter(id) };
                            model.fields = extend(idField, model.fields);
                            model.id = that.xpathToMember(id);
                        }
                        model = base.define(model);
                    }
                    that.model = model;
                }
                if (total) {
                    if (typeof total == 'string') {
                        total = that.getter(total);
                        that.total = function (data) {
                            return parseInt(total(data), 10);
                        };
                    } else if (typeof total == 'function') {
                        that.total = total;
                    }
                }
                if (errors) {
                    if (typeof errors == 'string') {
                        errors = that.getter(errors);
                        that.errors = function (data) {
                            return errors(data) || null;
                        };
                    } else if (typeof errors == 'function') {
                        that.errors = errors;
                    }
                }
                if (data) {
                    if (typeof data == 'string') {
                        data = that.xpathToMember(data);
                        that.data = function (value) {
                            var result = that.evaluate(value, data), modelInstance;
                            result = isArray(result) ? result : [result];
                            if (that.model && model.fields) {
                                modelInstance = new that.model();
                                return map(result, function (value) {
                                    if (value) {
                                        var record = {}, field;
                                        for (field in model.fields) {
                                            record[field] = modelInstance._parse(field, model.fields[field].field(value));
                                        }
                                        return record;
                                    }
                                });
                            }
                            return result;
                        };
                    } else if (typeof data == 'function') {
                        that.data = data;
                    }
                }
                if (typeof parse == 'function') {
                    var xmlParse = that.parse;
                    that.parse = function (data) {
                        var xml = parse.call(that, data);
                        return xmlParse.call(that, xml);
                    };
                }
                if (typeof serialize == 'function') {
                    that.serialize = serialize;
                }
            },
            total: function (result) {
                return this.data(result).length;
            },
            errors: function (data) {
                return data ? data.errors : null;
            },
            serialize: function (data) {
                return data;
            },
            parseDOM: function (element) {
                var result = {}, parsedNode, node, nodeType, nodeName, member, attribute, attributes = element.attributes, attributeCount = attributes.length, idx;
                for (idx = 0; idx < attributeCount; idx++) {
                    attribute = attributes[idx];
                    result['@' + attribute.nodeName] = attribute.nodeValue;
                }
                for (node = element.firstChild; node; node = node.nextSibling) {
                    nodeType = node.nodeType;
                    if (nodeType === 3 || nodeType === 4) {
                        result['#text'] = node.nodeValue;
                    } else if (nodeType === 1) {
                        parsedNode = this.parseDOM(node);
                        nodeName = node.nodeName;
                        member = result[nodeName];
                        if (isArray(member)) {
                            member.push(parsedNode);
                        } else if (member !== undefined) {
                            member = [
                                member,
                                parsedNode
                            ];
                        } else {
                            member = parsedNode;
                        }
                        result[nodeName] = member;
                    }
                }
                return result;
            },
            evaluate: function (value, expression) {
                var members = expression.split('.'), member, result, length, intermediateResult, idx;
                while (member = members.shift()) {
                    value = value[member];
                    if (isArray(value)) {
                        result = [];
                        expression = members.join('.');
                        for (idx = 0, length = value.length; idx < length; idx++) {
                            intermediateResult = this.evaluate(value[idx], expression);
                            intermediateResult = isArray(intermediateResult) ? intermediateResult : [intermediateResult];
                            result.push.apply(result, intermediateResult);
                        }
                        return result;
                    }
                }
                return value;
            },
            parse: function (xml) {
                var documentElement, tree, result = {};
                documentElement = xml.documentElement || $.parseXML(xml).documentElement;
                tree = this.parseDOM(documentElement);
                result[documentElement.nodeName] = tree;
                return result;
            },
            xpathToMember: function (member, raw) {
                if (!member) {
                    return '';
                }
                member = member.replace(/^\//, '').replace(/\//g, '.');
                if (member.indexOf('@') >= 0) {
                    return member.replace(/\.?(@.*)/, raw ? '$1' : '["$1"]');
                }
                if (member.indexOf('text()') >= 0) {
                    return member.replace(/(\.?text\(\))/, raw ? '#text' : '["#text"]');
                }
                return member;
            },
            getter: function (member) {
                return getter(this.xpathToMember(member), true);
            }
        });
        $.extend(true, kendo.data, {
            XmlDataReader: XmlDataReader,
            readers: { xml: XmlDataReader }
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.data', [
        'kendo.core',
        'kendo.data.odata',
        'kendo.data.xml'
    ], f);
}(function () {
    var __meta__ = {
        id: 'data',
        name: 'Data source',
        category: 'framework',
        description: 'Powerful component for using local and remote data.Fully supports CRUD, Sorting, Paging, Filtering, Grouping, and Aggregates.',
        depends: ['core'],
        features: [
            {
                id: 'data-odata',
                name: 'OData',
                description: 'Support for accessing Open Data Protocol (OData) services.',
                depends: ['data.odata']
            },
            {
                id: 'data-signalr',
                name: 'SignalR',
                description: 'Support for binding to SignalR hubs.',
                depends: ['data.signalr']
            },
            {
                id: 'data-XML',
                name: 'XML',
                description: 'Support for binding to XML.',
                depends: ['data.xml']
            }
        ]
    };
    (function ($, undefined) {
        var extend = $.extend, proxy = $.proxy, isPlainObject = $.isPlainObject, isEmptyObject = $.isEmptyObject, isArray = $.isArray, grep = $.grep, ajax = $.ajax, map, each = $.each, noop = $.noop, kendo = window.kendo, isFunction = kendo.isFunction, Observable = kendo.Observable, Class = kendo.Class, STRING = 'string', FUNCTION = 'function', ASCENDING = 'asc', CREATE = 'create', READ = 'read', UPDATE = 'update', DESTROY = 'destroy', CHANGE = 'change', SYNC = 'sync', GET = 'get', ERROR = 'error', REQUESTSTART = 'requestStart', PROGRESS = 'progress', REQUESTEND = 'requestEnd', crud = [
                CREATE,
                READ,
                UPDATE,
                DESTROY
            ], identity = function (o) {
                return o;
            }, getter = kendo.getter, stringify = kendo.stringify, math = Math, push = [].push, join = [].join, pop = [].pop, splice = [].splice, shift = [].shift, slice = [].slice, unshift = [].unshift, toString = {}.toString, stableSort = kendo.support.stableSort, dateRegExp = /^\/Date\((.*?)\)\/$/;
        var ObservableArray = Observable.extend({
            init: function (array, type) {
                var that = this;
                that.type = type || ObservableObject;
                Observable.fn.init.call(that);
                that.length = array.length;
                that.wrapAll(array, that);
            },
            at: function (index) {
                return this[index];
            },
            toJSON: function () {
                var idx, length = this.length, value, json = new Array(length);
                for (idx = 0; idx < length; idx++) {
                    value = this[idx];
                    if (value instanceof ObservableObject) {
                        value = value.toJSON();
                    }
                    json[idx] = value;
                }
                return json;
            },
            parent: noop,
            wrapAll: function (source, target) {
                var that = this, idx, length, parent = function () {
                        return that;
                    };
                target = target || [];
                for (idx = 0, length = source.length; idx < length; idx++) {
                    target[idx] = that.wrap(source[idx], parent);
                }
                return target;
            },
            wrap: function (object, parent) {
                var that = this, observable;
                if (object !== null && toString.call(object) === '[object Object]') {
                    observable = object instanceof that.type || object instanceof Model;
                    if (!observable) {
                        object = object instanceof ObservableObject ? object.toJSON() : object;
                        object = new that.type(object);
                    }
                    object.parent = parent;
                    object.bind(CHANGE, function (e) {
                        that.trigger(CHANGE, {
                            field: e.field,
                            node: e.node,
                            index: e.index,
                            items: e.items || [this],
                            action: e.node ? e.action || 'itemloaded' : 'itemchange'
                        });
                    });
                }
                return object;
            },
            push: function () {
                var index = this.length, items = this.wrapAll(arguments), result;
                result = push.apply(this, items);
                this.trigger(CHANGE, {
                    action: 'add',
                    index: index,
                    items: items
                });
                return result;
            },
            slice: slice,
            sort: [].sort,
            join: join,
            pop: function () {
                var length = this.length, result = pop.apply(this);
                if (length) {
                    this.trigger(CHANGE, {
                        action: 'remove',
                        index: length - 1,
                        items: [result]
                    });
                }
                return result;
            },
            splice: function (index, howMany, item) {
                var items = this.wrapAll(slice.call(arguments, 2)), result, i, len;
                result = splice.apply(this, [
                    index,
                    howMany
                ].concat(items));
                if (result.length) {
                    this.trigger(CHANGE, {
                        action: 'remove',
                        index: index,
                        items: result
                    });
                    for (i = 0, len = result.length; i < len; i++) {
                        if (result[i] && result[i].children) {
                            result[i].unbind(CHANGE);
                        }
                    }
                }
                if (item) {
                    this.trigger(CHANGE, {
                        action: 'add',
                        index: index,
                        items: items
                    });
                }
                return result;
            },
            shift: function () {
                var length = this.length, result = shift.apply(this);
                if (length) {
                    this.trigger(CHANGE, {
                        action: 'remove',
                        index: 0,
                        items: [result]
                    });
                }
                return result;
            },
            unshift: function () {
                var items = this.wrapAll(arguments), result;
                result = unshift.apply(this, items);
                this.trigger(CHANGE, {
                    action: 'add',
                    index: 0,
                    items: items
                });
                return result;
            },
            indexOf: function (item) {
                var that = this, idx, length;
                for (idx = 0, length = that.length; idx < length; idx++) {
                    if (that[idx] === item) {
                        return idx;
                    }
                }
                return -1;
            },
            forEach: function (callback, thisArg) {
                var idx = 0;
                var length = this.length;
                var context = thisArg || window;
                for (; idx < length; idx++) {
                    callback.call(context, this[idx], idx, this);
                }
            },
            map: function (callback, thisArg) {
                var idx = 0;
                var result = [];
                var length = this.length;
                var context = thisArg || window;
                for (; idx < length; idx++) {
                    result[idx] = callback.call(context, this[idx], idx, this);
                }
                return result;
            },
            reduce: function (callback) {
                var idx = 0, result, length = this.length;
                if (arguments.length == 2) {
                    result = arguments[1];
                } else if (idx < length) {
                    result = this[idx++];
                }
                for (; idx < length; idx++) {
                    result = callback(result, this[idx], idx, this);
                }
                return result;
            },
            reduceRight: function (callback) {
                var idx = this.length - 1, result;
                if (arguments.length == 2) {
                    result = arguments[1];
                } else if (idx > 0) {
                    result = this[idx--];
                }
                for (; idx >= 0; idx--) {
                    result = callback(result, this[idx], idx, this);
                }
                return result;
            },
            filter: function (callback, thisArg) {
                var idx = 0;
                var result = [];
                var item;
                var length = this.length;
                var context = thisArg || window;
                for (; idx < length; idx++) {
                    item = this[idx];
                    if (callback.call(context, item, idx, this)) {
                        result[result.length] = item;
                    }
                }
                return result;
            },
            find: function (callback, thisArg) {
                var idx = 0;
                var item;
                var length = this.length;
                var context = thisArg || window;
                for (; idx < length; idx++) {
                    item = this[idx];
                    if (callback.call(context, item, idx, this)) {
                        return item;
                    }
                }
            },
            every: function (callback, thisArg) {
                var idx = 0;
                var item;
                var length = this.length;
                var context = thisArg || window;
                for (; idx < length; idx++) {
                    item = this[idx];
                    if (!callback.call(context, item, idx, this)) {
                        return false;
                    }
                }
                return true;
            },
            some: function (callback, thisArg) {
                var idx = 0;
                var item;
                var length = this.length;
                var context = thisArg || window;
                for (; idx < length; idx++) {
                    item = this[idx];
                    if (callback.call(context, item, idx, this)) {
                        return true;
                    }
                }
                return false;
            },
            remove: function (item) {
                var idx = this.indexOf(item);
                if (idx !== -1) {
                    this.splice(idx, 1);
                }
            },
            empty: function () {
                this.splice(0, this.length);
            }
        });
        if (typeof Symbol !== 'undefined' && Symbol.iterator && !ObservableArray.prototype[Symbol.iterator]) {
            ObservableArray.prototype[Symbol.iterator] = [][Symbol.iterator];
        }
        var LazyObservableArray = ObservableArray.extend({
            init: function (data, type, events) {
                Observable.fn.init.call(this);
                this.type = type || ObservableObject;
                if (events) {
                    this._events = events;
                }
                for (var idx = 0; idx < data.length; idx++) {
                    this[idx] = data[idx];
                }
                this.length = idx;
                this._parent = proxy(function () {
                    return this;
                }, this);
            },
            at: function (index) {
                var item = this[index];
                if (!(item instanceof this.type)) {
                    item = this[index] = this.wrap(item, this._parent);
                } else {
                    item.parent = this._parent;
                }
                return item;
            }
        });
        function eventHandler(context, type, field, prefix) {
            return function (e) {
                var event = {}, key;
                for (key in e) {
                    event[key] = e[key];
                }
                
                if (prefix || e.field) { //Custom Change//
                    event.field = field + '.' + e.field;
                } else {
                    event.field = field;
                }
                if (type == CHANGE && context._notifyChange) {
                    context._notifyChange(event);
                }
                context.trigger(type, event);
            };
        }
        var ObservableObject = Observable.extend({
            init: function (value) {
                var that = this, member, field, parent = function () {
                        return that;
                    };
                Observable.fn.init.call(this);
                this._handlers = {};
                for (field in value) {
                    member = value[field];
                    if (typeof member === 'object' && member && !member.getTime && field.charAt(0) != '_') {
                        member = that.wrap(member, field, parent);
                    }
                    that[field] = member;
                }
                that.uid = kendo.guid();
            },
            shouldSerialize: function (field) {
                return this.hasOwnProperty(field) && field !== '_handlers' && field !== '_events' && typeof this[field] !== FUNCTION && field !== 'uid';
            },
            forEach: function (f) {
                for (var i in this) {
                    if (this.shouldSerialize(i)) {
                        f(this[i], i);
                    }
                }
            },
            toJSON: function () {
                var result = {}, value, field;
                for (field in this) {
                    if (this.shouldSerialize(field)) {
                        value = this[field];
                        if (value instanceof ObservableObject || value instanceof ObservableArray) {
                            value = value.toJSON();
                        }
                        result[field] = value;
                    }
                }
                return result;
            },
            get: function (field) {
                var that = this, result;
                that.trigger(GET, { field: field });
                if (field === 'this') {
                    result = that;
                } else {
                    result = kendo.getter(field, true)(that);
                }
                return result;
            },
            _set: function (field, value) {
                var that = this;
                var composite = field.indexOf('.') >= 0;
                if (composite) {
                    var paths = field.split('.'), path = '';
                    while (paths.length > 1) {
                        path += paths.shift();
                        var obj = kendo.getter(path, true)(that);
                        if (obj instanceof ObservableObject) {
                            obj.set(paths.join('.'), value);
                            return composite;
                        }
                        path += '.';
                    }
                }
                kendo.setter(field)(that, value);
                return composite;
            },
            set: function (field, value) {
                var that = this, isSetPrevented = false, composite = field.indexOf('.') >= 0, current = kendo.getter(field, true)(that);
                if (current !== value) {
                    if (current instanceof Observable && this._handlers[field]) {
                        if (this._handlers[field].get) {
                            current.unbind(GET, this._handlers[field].get);
                        }
                        current.unbind(CHANGE, this._handlers[field].change);
                    }
                    isSetPrevented = that.trigger('set', {
                        field: field,
                        value: value
                    });
                    if (!isSetPrevented) {
                        if (!composite) {
                            value = that.wrap(value, field, function () {
                                return that;
                            });
                        }
                        if (!that._set(field, value) || field.indexOf('(') >= 0 || field.indexOf('[') >= 0) {
                            that.trigger(CHANGE, { field: field });
                        }
                    }
                }
                return isSetPrevented;
            },
            parent: noop,
            wrap: function (object, field, parent) {
                var that = this;
                var get;
                var change;
                var type = toString.call(object);
                if (object != null && (type === '[object Object]' || type === '[object Array]')) {
                    var isObservableArray = object instanceof ObservableArray;
                    var isDataSource = object instanceof DataSource;
                    if (type === '[object Object]' && !isDataSource && !isObservableArray) {
                        if (!(object instanceof ObservableObject)) {
                            object = new ObservableObject(object);
                        }
                        get = eventHandler(that, GET, field, true);
                        object.bind(GET, get);
                        change = eventHandler(that, CHANGE, field, true);
                        object.bind(CHANGE, change);
                        that._handlers[field] = {
                            get: get,
                            change: change
                        };
                    } else if (type === '[object Array]' || isObservableArray || isDataSource) {
                        if (!isObservableArray && !isDataSource) {
                            object = new ObservableArray(object);
                        }
                        change = eventHandler(that, CHANGE, field, false);
                        object.bind(CHANGE, change);
                        that._handlers[field] = { change: change };
                    }
                    object.parent = parent;
                }
                return object;
            }
        });
        function equal(x, y) {
            if (x === y) {
                return true;
            }
            var xtype = $.type(x), ytype = $.type(y), field;
            if (xtype !== ytype) {
                return false;
            }
            if (xtype === 'date') {
                return x.getTime() === y.getTime();
            }
            if (xtype !== 'object' && xtype !== 'array') {
                return false;
            }
            for (field in x) {
                if (!equal(x[field], y[field])) {
                    return false;
                }
            }
            return true;
        }
        var parsers = {
            'number': function (value) {
                if (typeof value === STRING && value.toLowerCase() === 'null') {
                    return null;
                }
                return kendo.parseFloat(value);
            },
            'date': function (value) {
                if (typeof value === STRING && value.toLowerCase() === 'null') {
                    return null;
                }
                return kendo.parseDate(value);
            },
            'boolean': function (value) {
                if (typeof value === STRING) {
                    if (value.toLowerCase() === 'null') {
                        return null;
                    } else {
                        return value.toLowerCase() === 'true';
                    }
                }
                return value != null ? !!value : value;
            },
            'string': function (value) {
                if (typeof value === STRING && value.toLowerCase() === 'null') {
                    return null;
                }
                return value != null ? value + '' : value;
            },
            'default': function (value) {
                return value;
            }
        };
        var defaultValues = {
            'string': '',
            'number': 0,
            'date': new Date(),
            'boolean': false,
            'default': ''
        };
        function getFieldByName(obj, name) {
            var field, fieldName;
            for (fieldName in obj) {
                field = obj[fieldName];
                if (isPlainObject(field) && field.field && field.field === name) {
                    return field;
                } else if (field === name) {
                    return field;
                }
            }
            return null;
        }
        var Model = ObservableObject.extend({
            init: function (data) {
                var that = this;
                if (!data || $.isEmptyObject(data)) {
                    data = $.extend({}, that.defaults, data);
                    if (that._initializers) {
                        for (var idx = 0; idx < that._initializers.length; idx++) {
                            var name = that._initializers[idx];
                            data[name] = that.defaults[name]();
                        }
                    }
                }
                ObservableObject.fn.init.call(that, data);
                that.dirty = false;
                that.dirtyFields = {};
                if (that.idField) {
                    that.id = that.get(that.idField);
                    if (that.id === undefined) {
                        that.id = that._defaultId;
                    }
                }
            },
            shouldSerialize: function (field) {
                return ObservableObject.fn.shouldSerialize.call(this, field) && field !== 'uid' && !(this.idField !== 'id' && field === 'id') && field !== 'dirty' && field !== 'dirtyFields' && field !== '_accessors';
            },
            _parse: function (field, value) {
                var that = this, fieldName = field, fields = that.fields || {}, parse;
                field = fields[field];
                if (!field) {
                    field = getFieldByName(fields, fieldName);
                }
                if (field) {
                    parse = field.parse;
                    if (!parse && field.type) {
                        parse = parsers[field.type.toLowerCase()];
                    }
                }
                return parse ? parse(value) : value;
            },
            _notifyChange: function (e) {
                var action = e.action;
                if (action == 'add' || action == 'remove') {
                    this.dirty = true;
                    this.dirtyFields[e.field] = true;
                }
            },
            editable: function (field) {
                field = (this.fields || {})[field];
                return field ? field.editable !== false : true;
            },
            set: function (field, value, initiator) {
                var that = this;
                var dirty = that.dirty;
                if (that.editable(field)) {
                    value = that._parse(field, value);
                    if (!equal(value, that.get(field))) {
                        that.dirty = true;
                        that.dirtyFields[field] = true;
                        if (ObservableObject.fn.set.call(that, field, value, initiator) && !dirty) {
                            that.dirty = dirty;
                            if (!that.dirty) {
                                that.dirtyFields[field] = false;
                            }
                        }
                    } else {
                        that.trigger('equalSet', {
                            field: field,
                            value: value
                        });
                    }
                }
            },
            accept: function (data) {
                var that = this, parent = function () {
                        return that;
                    }, field;
                for (field in data) {
                    var value = data[field];
                    if (field.charAt(0) != '_') {
                        value = that.wrap(data[field], field, parent);
                    }
                    that._set(field, value);
                }
                if (that.idField) {
                    that.id = that.get(that.idField);
                }
                that.dirty = false;
                that.dirtyFields = {};
            },
            isNew: function () {
                return this.id === this._defaultId;
            }
        });
        Model.define = function (base, options) {
            if (options === undefined) {
                options = base;
                base = Model;
            }
            var model, proto = extend({ defaults: {} }, options), name, field, type, value, idx, length, fields = {}, originalName, id = proto.id, functionFields = [];
            if (id) {
                proto.idField = id;
            }
            if (proto.id) {
                delete proto.id;
            }
            if (id) {
                proto.defaults[id] = proto._defaultId = '';
            }
            if (toString.call(proto.fields) === '[object Array]') {
                for (idx = 0, length = proto.fields.length; idx < length; idx++) {
                    field = proto.fields[idx];
                    if (typeof field === STRING) {
                        fields[field] = {};
                    } else if (field.field) {
                        fields[field.field] = field;
                    }
                }
                proto.fields = fields;
            }
            for (name in proto.fields) {
                field = proto.fields[name];
                type = field.type || 'default';
                value = null;
                originalName = name;
                name = typeof field.field === STRING ? field.field : name;
                if (!field.nullable) {
                    value = proto.defaults[originalName !== name ? originalName : name] = field.defaultValue !== undefined ? field.defaultValue : defaultValues[type.toLowerCase()];
                    if (typeof value === 'function') {
                        functionFields.push(name);
                    }
                }
                if (options.id === name) {
                    proto._defaultId = value;
                }
                proto.defaults[originalName !== name ? originalName : name] = value;
                field.parse = field.parse || parsers[type];
            }
            if (functionFields.length > 0) {
                proto._initializers = functionFields;
            }
            model = base.extend(proto);
            model.define = function (options) {
                return Model.define(model, options);
            };
            if (proto.fields) {
                model.fields = proto.fields;
                model.idField = proto.idField;
            }
            return model;
        };
        var Comparer = {
            selector: function (field) {
                return isFunction(field) ? field : getter(field);
            },
            compare: function (field) {
                var selector = this.selector(field);
                return function (a, b) {
                    a = selector(a);
                    b = selector(b);
                    if (a == null && b == null) {
                        return 0;
                    }
                    if (a == null) {
                        return -1;
                    }
                    if (b == null) {
                        return 1;
                    }
                    if (a.localeCompare) {
                        return a.localeCompare(b);
                    }
                    return a > b ? 1 : a < b ? -1 : 0;
                };
            },
            create: function (sort) {
                var compare = sort.compare || this.compare(sort.field);
                if (sort.dir == 'desc') {
                    return function (a, b) {
                        return compare(b, a, true);
                    };
                }
                return compare;
            },
            combine: function (comparers) {
                return function (a, b) {
                    var result = comparers[0](a, b), idx, length;
                    for (idx = 1, length = comparers.length; idx < length; idx++) {
                        result = result || comparers[idx](a, b);
                    }
                    return result;
                };
            }
        };
        var StableComparer = extend({}, Comparer, {
            asc: function (field) {
                var selector = this.selector(field);
                return function (a, b) {
                    var valueA = selector(a);
                    var valueB = selector(b);
                    if (valueA && valueA.getTime && valueB && valueB.getTime) {
                        valueA = valueA.getTime();
                        valueB = valueB.getTime();
                    }
                    if (valueA === valueB) {
                        return a.__position - b.__position;
                    }
                    if (valueA == null) {
                        return -1;
                    }
                    if (valueB == null) {
                        return 1;
                    }
                    if (valueA.localeCompare) {
                        return valueA.localeCompare(valueB);
                    }
                    return valueA > valueB ? 1 : -1;
                };
            },
            desc: function (field) {
                var selector = this.selector(field);
                return function (a, b) {
                    var valueA = selector(a);
                    var valueB = selector(b);
                    if (valueA && valueA.getTime && valueB && valueB.getTime) {
                        valueA = valueA.getTime();
                        valueB = valueB.getTime();
                    }
                    if (valueA === valueB) {
                        return a.__position - b.__position;
                    }
                    if (valueA == null) {
                        return 1;
                    }
                    if (valueB == null) {
                        return -1;
                    }
                    if (valueB.localeCompare) {
                        return valueB.localeCompare(valueA);
                    }
                    return valueA < valueB ? 1 : -1;
                };
            },
            create: function (sort) {
                return this[sort.dir](sort.field);
            }
        });
        map = function (array, callback) {
            var idx, length = array.length, result = new Array(length);
            for (idx = 0; idx < length; idx++) {
                result[idx] = callback(array[idx], idx, array);
            }
            return result;
        };
        var operators = function () {
            function quote(str) {
                if (typeof str == 'string') {
                    str = str.replace(/[\r\n]+/g, '');
                }
                return JSON.stringify(str);
            }
            function textOp(impl) {
                return function (a, b, ignore, accentFoldingFiltering) {
                    b += '';
                    if (ignore) {
                        a = '(' + a + ' || \'\').toString()' + (accentFoldingFiltering ? '.toLocaleLowerCase(\'' + accentFoldingFiltering + '\')' : '.toLowerCase()');
                        b = accentFoldingFiltering ? b.toLocaleLowerCase(accentFoldingFiltering) : b.toLowerCase();
                    }
                    return impl(a, quote(b), ignore);
                };
            }
            function operator(op, a, b, ignore, accentFoldingFiltering) {
                if (b != null) {
                    if (typeof b === STRING) {
                        var date = dateRegExp.exec(b);
                        if (date) {
                            b = new Date(+date[1]);
                        } else if (ignore) {
                            b = quote(accentFoldingFiltering ? b.toLocaleLowerCase(accentFoldingFiltering) : b.toLowerCase());
                            a = '((' + a + ' || \'\')+\'\')' + (accentFoldingFiltering ? '.toLocaleLowerCase(\'' + accentFoldingFiltering + '\')' : '.toLowerCase()');
                        } else {
                            b = quote(b);
                        }
                    }
                    if (b.getTime) {
                        a = '(' + a + '&&' + a + '.getTime?' + a + '.getTime():' + a + ')';
                        b = b.getTime();
                    }
                }
                return a + ' ' + op + ' ' + b;
            }
            function getMatchRegexp(pattern) {
                for (var rx = '/^', esc = false, i = 0; i < pattern.length; ++i) {
                    var ch = pattern.charAt(i);
                    if (esc) {
                        rx += '\\' + ch;
                    } else if (ch == '~') {
                        esc = true;
                        continue;
                    } else if (ch == '*') {
                        rx += '.*';
                    } else if (ch == '?') {
                        rx += '.';
                    } else if ('.+^$()[]{}|\\/\n\r\u2028\u2029\xA0'.indexOf(ch) >= 0) {
                        rx += '\\' + ch;
                    } else {
                        rx += ch;
                    }
                    esc = false;
                }
                return rx + '$/';
            }
            return {
                quote: function (value) {
                    if (value && value.getTime) {
                        return 'new Date(' + value.getTime() + ')';
                    }
                    return quote(value);
                },
                eq: function (a, b, ignore, accentFoldingFiltering) {
                    return operator('==', a, b, ignore, accentFoldingFiltering);
                },
                neq: function (a, b, ignore, accentFoldingFiltering) {
                    return operator('!=', a, b, ignore, accentFoldingFiltering);
                },
                gt: function (a, b, ignore) {
                    return operator('>', a, b, ignore);
                },
                gte: function (a, b, ignore) {
                    return operator('>=', a, b, ignore);
                },
                lt: function (a, b, ignore) {
                    return operator('<', a, b, ignore);
                },
                lte: function (a, b, ignore) {
                    return operator('<=', a, b, ignore);
                },
                startswith: textOp(function (a, b) {
                    return a + '.lastIndexOf(' + b + ', 0) == 0';
                }),
                doesnotstartwith: textOp(function (a, b) {
                    return a + '.lastIndexOf(' + b + ', 0) == -1';
                }),
                endswith: textOp(function (a, b) {
                    var n = b ? b.length - 2 : 0;
                    return a + '.indexOf(' + b + ', ' + a + '.length - ' + n + ') >= 0';
                }),
                doesnotendwith: textOp(function (a, b) {
                    var n = b ? b.length - 2 : 0;
                    return a + '.indexOf(' + b + ', ' + a + '.length - ' + n + ') < 0';
                }),
                contains: textOp(function (a, b) {
                    return a + '.indexOf(' + b + ') >= 0';
                }),
                doesnotcontain: textOp(function (a, b) {
                    return a + '.indexOf(' + b + ') == -1';
                }),
                matches: textOp(function (a, b) {
                    b = b.substring(1, b.length - 1);
                    return getMatchRegexp(b) + '.test(' + a + ')';
                }),
                doesnotmatch: textOp(function (a, b) {
                    b = b.substring(1, b.length - 1);
                    return '!' + getMatchRegexp(b) + '.test(' + a + ')';
                }),
                isempty: function (a) {
                    return a + ' === \'\'';
                },
                isnotempty: function (a) {
                    return a + ' !== \'\'';
                },
                isnull: function (a) {
                    return '(' + a + ' == null)';
                },
                isnotnull: function (a) {
                    return '(' + a + ' != null)';
                },
                isnullorempty: function (a) {
                    return '(' + a + ' === null) || (' + a + ' === \'\')';
                },
                isnotnullorempty: function (a) {
                    return '(' + a + ' !== null) && (' + a + ' !== \'\')';
                }
            };
        }();
        function Query(data) {
            this.data = data || [];
        }
        Query.filterExpr = function (expression) {
            var expressions = [], logic = {
                    and: ' && ',
                    or: ' || '
                }, idx, length, filter, expr, fieldFunctions = [], operatorFunctions = [], field, operator, filters = expression.filters;
            for (idx = 0, length = filters.length; idx < length; idx++) {
                filter = filters[idx];
                field = filter.field;
                operator = filter.operator;
                if (filter.filters) {
                    expr = Query.filterExpr(filter);
                    filter = expr.expression.replace(/__o\[(\d+)\]/g, function (match, index) {
                        index = +index;
                        return '__o[' + (operatorFunctions.length + index) + ']';
                    }).replace(/__f\[(\d+)\]/g, function (match, index) {
                        index = +index;
                        return '__f[' + (fieldFunctions.length + index) + ']';
                    });
                    operatorFunctions.push.apply(operatorFunctions, expr.operators);
                    fieldFunctions.push.apply(fieldFunctions, expr.fields);
                } else {
                    if (typeof field === FUNCTION) {
                        expr = '__f[' + fieldFunctions.length + '](d)';
                        fieldFunctions.push(field);
                    } else {
                        expr = kendo.expr(field);
                    }
                    if (typeof operator === FUNCTION) {
                        filter = '__o[' + operatorFunctions.length + '](' + expr + ', ' + operators.quote(filter.value) + ')';
                        operatorFunctions.push(operator);
                    } else {
                        filter = operators[(operator || 'eq').toLowerCase()](expr, filter.value, filter.ignoreCase !== undefined ? filter.ignoreCase : true, expression.accentFoldingFiltering);
                    }
                }
                expressions.push(filter);
            }
            return {
                expression: '(' + expressions.join(logic[expression.logic]) + ')',
                fields: fieldFunctions,
                operators: operatorFunctions
            };
        };
        function normalizeSort(field, dir) {
            if (field) {
                var descriptor = typeof field === STRING ? {
                        field: field,
                        dir: dir
                    } : field, descriptors = isArray(descriptor) ? descriptor : descriptor !== undefined ? [descriptor] : [];
                return grep(descriptors, function (d) {
                    return !!d.dir;
                });
            }
        }
        var operatorMap = {
            '==': 'eq',
            equals: 'eq',
            isequalto: 'eq',
            equalto: 'eq',
            equal: 'eq',
            '!=': 'neq',
            ne: 'neq',
            notequals: 'neq',
            isnotequalto: 'neq',
            notequalto: 'neq',
            notequal: 'neq',
            '<': 'lt',
            islessthan: 'lt',
            lessthan: 'lt',
            less: 'lt',
            '<=': 'lte',
            le: 'lte',
            islessthanorequalto: 'lte',
            lessthanequal: 'lte',
            '>': 'gt',
            isgreaterthan: 'gt',
            greaterthan: 'gt',
            greater: 'gt',
            '>=': 'gte',
            isgreaterthanorequalto: 'gte',
            greaterthanequal: 'gte',
            ge: 'gte',
            notsubstringof: 'doesnotcontain',
            isnull: 'isnull',
            isempty: 'isempty',
            isnotempty: 'isnotempty'
        };
        function normalizeOperator(expression) {
            var idx, length, filter, operator, filters = expression.filters;
            if (filters) {
                for (idx = 0, length = filters.length; idx < length; idx++) {
                    filter = filters[idx];
                    operator = filter.operator;
                    if (operator && typeof operator === STRING) {
                        filter.operator = operatorMap[operator.toLowerCase()] || operator;
                    }
                    normalizeOperator(filter);
                }
            }
        }
        function normalizeFilter(expression) {
            if (expression && !isEmptyObject(expression)) {
                if (isArray(expression) || !expression.filters) {
                    expression = {
                        logic: 'and',
                        filters: isArray(expression) ? expression : [expression]
                    };
                }
                normalizeOperator(expression);
                return expression;
            }
        }
        Query.normalizeFilter = normalizeFilter;
        function compareDescriptor(f1, f2) {
            if (f1.logic || f2.logic) {
                return false;
            }
            return f1.field === f2.field && f1.value === f2.value && f1.operator === f2.operator;
        }
        function normalizeDescriptor(filter) {
            filter = filter || {};
            if (isEmptyObject(filter)) {
                return {
                    logic: 'and',
                    filters: []
                };
            }
            return normalizeFilter(filter);
        }
        function fieldComparer(a, b) {
            if (b.logic || a.field > b.field) {
                return 1;
            } else if (a.field < b.field) {
                return -1;
            } else {
                return 0;
            }
        }
        function compareFilters(expr1, expr2) {
            expr1 = normalizeDescriptor(expr1);
            expr2 = normalizeDescriptor(expr2);
            if (expr1.logic !== expr2.logic) {
                return false;
            }
            var f1, f2;
            var filters1 = (expr1.filters || []).slice();
            var filters2 = (expr2.filters || []).slice();
            if (filters1.length !== filters2.length) {
                return false;
            }
            filters1 = filters1.sort(fieldComparer);
            filters2 = filters2.sort(fieldComparer);
            for (var idx = 0; idx < filters1.length; idx++) {
                f1 = filters1[idx];
                f2 = filters2[idx];
                if (f1.logic && f2.logic) {
                    if (!compareFilters(f1, f2)) {
                        return false;
                    }
                } else if (!compareDescriptor(f1, f2)) {
                    return false;
                }
            }
            return true;
        }
        Query.compareFilters = compareFilters;
        function normalizeAggregate(expressions) {
            return isArray(expressions) ? expressions : [expressions];
        }
        function normalizeGroup(field, dir, compare, skipItemSorting) {
            var descriptor = typeof field === STRING ? {
                    field: field,
                    dir: dir,
                    compare: compare,
                    skipItemSorting: skipItemSorting
                } : field, descriptors = isArray(descriptor) ? descriptor : descriptor !== undefined ? [descriptor] : [];
            return map(descriptors, function (d) {
                return {
                    field: d.field,
                    dir: d.dir || 'asc',
                    aggregates: d.aggregates,
                    compare: d.compare,
                    skipItemSorting: d.skipItemSorting
                };
            });
        }
        function normalizeGroupWithoutCompare(field, dir, compare) {
            var descriptors = normalizeGroup(field, dir, compare);
            for (var i = 0; i < descriptors.length; i++) {
                delete descriptors[i].compare;
            }
            return descriptors;
        }
        function anyGroupDescriptorHasCompare(groupDescriptors) {
            var descriptors = isArray(groupDescriptors) ? groupDescriptors : [groupDescriptors];
            for (var i = 0; i < descriptors.length; i++) {
                if (descriptors[i] && isFunction(descriptors[i].compare)) {
                    return true;
                }
            }
            return false;
        }
        Query.prototype = {
            toArray: function () {
                return this.data;
            },
            range: function (index, count) {
                return new Query(this.data.slice(index, index + count));
            },
            skip: function (count) {
                return new Query(this.data.slice(count));
            },
            take: function (count) {
                return new Query(this.data.slice(0, count));
            },
            select: function (selector) {
                return new Query(map(this.data, selector));
            },
            order: function (selector, dir, inPlace) {
                var sort = { dir: dir };
                if (selector) {
                    if (selector.compare) {
                        sort.compare = selector.compare;
                    } else {
                        sort.field = selector;
                    }
                }
                if (inPlace) {
                    return new Query(this.data.sort(Comparer.create(sort)));
                }
                return new Query(this.data.slice(0).sort(Comparer.create(sort)));
            },
            orderBy: function (selector, inPlace) {
                return this.order(selector, 'asc', inPlace);
            },
            orderByDescending: function (selector, inPlace) {
                return this.order(selector, 'desc', inPlace);
            },
            sort: function (field, dir, comparer, inPlace) {
                var idx, length, descriptors = normalizeSort(field, dir), comparers = [];
                comparer = comparer || Comparer;
                if (descriptors.length) {
                    for (idx = 0, length = descriptors.length; idx < length; idx++) {
                        comparers.push(comparer.create(descriptors[idx]));
                    }
                    return this.orderBy({ compare: comparer.combine(comparers) }, inPlace);
                }
                return this;
            },
            filter: function (expressions) {
                var idx, current, length, compiled, predicate, data = this.data, fields, operators, result = [], filter;
                expressions = normalizeFilter(expressions);
                if (!expressions || expressions.filters.length === 0) {
                    return this;
                }
                compiled = Query.filterExpr(expressions);
                fields = compiled.fields;
                operators = compiled.operators;
                predicate = filter = new Function('d, __f, __o', 'return ' + compiled.expression);
                if (fields.length || operators.length) {
                    filter = function (d) {
                        return predicate(d, fields, operators);
                    };
                }
                for (idx = 0, length = data.length; idx < length; idx++) {
                    current = data[idx];
                    if (filter(current)) {
                        result.push(current);
                    }
                }
                return new Query(result);
            },
            group: function (descriptors, allData) {
                descriptors = normalizeGroup(descriptors || []);
                allData = allData || this.data;
                var that = this, result = new Query(that.data), descriptor;
                if (descriptors.length > 0) {
                    descriptor = descriptors[0];
                    result = result.groupBy(descriptor).select(function (group) {
                        var data = new Query(allData).filter([{
                                field: group.field,
                                operator: 'eq',
                                value: group.value,
                                ignoreCase: false
                            }]);
                        return {
                            field: group.field,
                            value: group.value,
                            items: descriptors.length > 1 ? new Query(group.items).group(descriptors.slice(1), data.toArray()).toArray() : group.items,
                            hasSubgroups: descriptors.length > 1,
                            aggregates: data.aggregate(descriptor.aggregates)
                        };
                    });
                }
                return result;
            },
            groupBy: function (descriptor) {
                var that = this;
                if (isEmptyObject(descriptor) || !this.data.length) {
                    return new Query([]);
                }
                var field = descriptor.field, sorted = descriptor.skipItemSorting ? this.data : this._sortForGrouping(field, descriptor.dir || 'asc'), accessor = kendo.accessor(field), item, groupValue = accessor.get(sorted[0], field), group = {
                        field: field,
                        value: groupValue,
                        items: []
                    }, currentValue, idx, len, result = [group];
                for (idx = 0, len = sorted.length; idx < len; idx++) {
                    item = sorted[idx];
                    currentValue = accessor.get(item, field);
                    if (!groupValueComparer(groupValue, currentValue)) {
                        groupValue = currentValue;
                        group = {
                            field: field,
                            value: groupValue,
                            items: []
                        };
                        result.push(group);
                    }
                    group.items.push(item);
                }
                result = that._sortGroups(result, descriptor);
                return new Query(result);
            },
            _sortForGrouping: function (field, dir) {
                var idx, length, data = this.data;
                if (!stableSort) {
                    for (idx = 0, length = data.length; idx < length; idx++) {
                        data[idx].__position = idx;
                    }
                    data = new Query(data).sort(field, dir, StableComparer).toArray();
                    for (idx = 0, length = data.length; idx < length; idx++) {
                        delete data[idx].__position;
                    }
                    return data;
                }
                return this.sort(field, dir).toArray();
            },
            _sortGroups: function (groups, descriptor) {
                var result = groups;
                if (descriptor && isFunction(descriptor.compare)) {
                    result = new Query(result).order({ compare: descriptor.compare }, descriptor.dir || ASCENDING).toArray();
                }
                return result;
            },
            aggregate: function (aggregates) {
                var idx, len, result = {}, state = {};
                if (aggregates && aggregates.length) {
                    for (idx = 0, len = this.data.length; idx < len; idx++) {
                        calculateAggregate(result, aggregates, this.data[idx], idx, len, state);
                    }
                }
                return result;
            }
        };
        function groupValueComparer(a, b) {
            if (a && a.getTime && b && b.getTime) {
                return a.getTime() === b.getTime();
            }
            return a === b;
        }
        function calculateAggregate(accumulator, aggregates, item, index, length, state) {
            aggregates = aggregates || [];
            var idx, aggr, functionName, len = aggregates.length;
            for (idx = 0; idx < len; idx++) {
                aggr = aggregates[idx];
                functionName = aggr.aggregate;
                var field = aggr.field;
                accumulator[field] = accumulator[field] || {};
                state[field] = state[field] || {};
                state[field][functionName] = state[field][functionName] || {};
                accumulator[field][functionName] = functions[functionName.toLowerCase()](accumulator[field][functionName], item, kendo.accessor(field), index, length, state[field][functionName]);
            }
        }
        var functions = {
            sum: function (accumulator, item, accessor) {
                var value = accessor.get(item);
                if (!isNumber(accumulator)) {
                    accumulator = value;
                } else if (isNumber(value)) {
                    accumulator += value;
                }
                return accumulator;
            },
            count: function (accumulator) {
                return (accumulator || 0) + 1;
            },
            average: function (accumulator, item, accessor, index, length, state) {
                var value = accessor.get(item);
                if (state.count === undefined) {
                    state.count = 0;
                }
                if (!isNumber(accumulator)) {
                    accumulator = value;
                } else if (isNumber(value)) {
                    accumulator += value;
                }
                if (isNumber(value)) {
                    state.count++;
                }
                if (index == length - 1 && isNumber(accumulator)) {
                    accumulator = accumulator / state.count;
                }
                return accumulator;
            },
            max: function (accumulator, item, accessor) {
                var value = accessor.get(item);
                if (!isNumber(accumulator) && !isDate(accumulator)) {
                    accumulator = value;
                }
                if (accumulator < value && (isNumber(value) || isDate(value))) {
                    accumulator = value;
                }
                return accumulator;
            },
            min: function (accumulator, item, accessor) {
                var value = accessor.get(item);
                if (!isNumber(accumulator) && !isDate(accumulator)) {
                    accumulator = value;
                }
                if (accumulator > value && (isNumber(value) || isDate(value))) {
                    accumulator = value;
                }
                return accumulator;
            }
        };
        function isNumber(val) {
            return typeof val === 'number' && !isNaN(val);
        }
        function isDate(val) {
            return val && val.getTime;
        }
        function toJSON(array) {
            var idx, length = array.length, result = new Array(length);
            for (idx = 0; idx < length; idx++) {
                result[idx] = array[idx].toJSON();
            }
            return result;
        }
        Query.normalizeGroup = normalizeGroup;
        Query.normalizeSort = normalizeSort;
        Query.process = function (data, options, inPlace) {
            options = options || {};
            var group = options.group;
            var customGroupSort = anyGroupDescriptorHasCompare(normalizeGroup(group || []));
            var query = new Query(data), groupDescriptorsWithoutCompare = normalizeGroupWithoutCompare(group || []), normalizedSort = normalizeSort(options.sort || []), sort = customGroupSort ? normalizedSort : groupDescriptorsWithoutCompare.concat(normalizedSort), groupDescriptorsWithoutSort, total, filterCallback = options.filterCallback, filter = options.filter, skip = options.skip, take = options.take;
            if (sort && inPlace) {
                query = query.sort(sort, undefined, undefined, inPlace);
            }
            if (filter) {
                query = query.filter(filter);
                if (filterCallback) {
                    query = filterCallback(query);
                }
                total = query.toArray().length;
            }
            if (sort && !inPlace) {
                query = query.sort(sort);
                if (group) {
                    data = query.toArray();
                }
            }
            if (customGroupSort) {
                query = query.group(group, data);
                if (skip !== undefined && take !== undefined) {
                    query = new Query(flatGroups(query.toArray())).range(skip, take);
                    groupDescriptorsWithoutSort = map(groupDescriptorsWithoutCompare, function (groupDescriptor) {
                        return extend({}, groupDescriptor, { skipItemSorting: true });
                    });
                    query = query.group(groupDescriptorsWithoutSort, data);
                }
            } else {
                if (skip !== undefined && take !== undefined) {
                    query = query.range(skip, take);
                }
                if (group) {
                    query = query.group(group, data);
                }
            }
            return {
                total: total,
                data: query.toArray()
            };
        };
        var LocalTransport = Class.extend({
            init: function (options) {
                this.data = options.data;
            },
            read: function (options) {
                options.success(this.data);
            },
            update: function (options) {
                options.success(options.data);
            },
            create: function (options) {
                options.success(options.data);
            },
            destroy: function (options) {
                options.success(options.data);
            }
        });
        var RemoteTransport = Class.extend({
            init: function (options) {
                var that = this, parameterMap;
                options = that.options = extend({}, that.options, options);
                each(crud, function (index, type) {
                    if (typeof options[type] === STRING) {
                        options[type] = { url: options[type] };
                    }
                });
                that.cache = options.cache ? Cache.create(options.cache) : {
                    find: noop,
                    add: noop
                };
                parameterMap = options.parameterMap;
                if (options.submit) {
                    that.submit = options.submit;
                }
                if (isFunction(options.push)) {
                    that.push = options.push;
                }
                if (!that.push) {
                    that.push = identity;
                }
                that.parameterMap = isFunction(parameterMap) ? parameterMap : function (options) {
                    var result = {};
                    each(options, function (option, value) {
                        if (option in parameterMap) {
                            option = parameterMap[option];
                            if (isPlainObject(option)) {
                                value = option.value(value);
                                option = option.key;
                            }
                        }
                        result[option] = value;
                    });
                    return result;
                };
            },
            options: { parameterMap: identity },
            create: function (options) {
                return ajax(this.setup(options, CREATE));
            },
            read: function (options) {
                var that = this, success, error, result, cache = that.cache;
                options = that.setup(options, READ);
                success = options.success || noop;
                error = options.error || noop;
                result = cache.find(options.data);
                if (result !== undefined) {
                    success(result);
                } else {
                    options.success = function (result) {
                        cache.add(options.data, result);
                        success(result);
                    };
                    $.ajax(options);
                }
            },
            update: function (options) {
                return ajax(this.setup(options, UPDATE));
            },
            destroy: function (options) {
                return ajax(this.setup(options, DESTROY));
            },
            setup: function (options, type) {
                options = options || {};
                var that = this, parameters, operation = that.options[type], data = isFunction(operation.data) ? operation.data(options.data) : operation.data;
                options = extend(true, {}, operation, options);
                parameters = extend(true, {}, data, options.data);
                options.data = that.parameterMap(parameters, type);
                if (isFunction(options.url)) {
                    options.url = options.url(parameters);
                }
                return options;
            }
        });
        var Cache = Class.extend({
            init: function () {
                this._store = {};
            },
            add: function (key, data) {
                if (key !== undefined) {
                    this._store[stringify(key)] = data;
                }
            },
            find: function (key) {
                return this._store[stringify(key)];
            },
            clear: function () {
                this._store = {};
            },
            remove: function (key) {
                delete this._store[stringify(key)];
            }
        });
        Cache.create = function (options) {
            var store = {
                'inmemory': function () {
                    return new Cache();
                }
            };
            if (isPlainObject(options) && isFunction(options.find)) {
                return options;
            }
            if (options === true) {
                return new Cache();
            }
            return store[options]();
        };
        function serializeRecords(data, getters, modelInstance, originalFieldNames, fieldNames) {
            var record, getter, originalName, idx, setters = {}, length;
            for (idx = 0, length = data.length; idx < length; idx++) {
                record = data[idx];
                for (getter in getters) {
                    originalName = fieldNames[getter];
                    if (originalName && originalName !== getter) {
                        if (!setters[originalName]) {
                            setters[originalName] = kendo.setter(originalName);
                        }
                        setters[originalName](record, getters[getter](record));
                        delete record[getter];
                    }
                }
            }
        }
        function convertRecords(data, getters, modelInstance, originalFieldNames, fieldNames) {
            var record, getter, originalName, idx, length;
            for (idx = 0, length = data.length; idx < length; idx++) {
                record = data[idx];
                for (getter in getters) {
                    record[getter] = modelInstance._parse(getter, getters[getter](record));
                    originalName = fieldNames[getter];
                    if (originalName && originalName !== getter) {
                        delete record[originalName];
                    }
                }
            }
        }
        function convertGroup(data, getters, modelInstance, originalFieldNames, fieldNames) {
            var record, idx, fieldName, length;
            for (idx = 0, length = data.length; idx < length; idx++) {
                record = data[idx];
                fieldName = originalFieldNames[record.field];
                if (fieldName && fieldName != record.field) {
                    record.field = fieldName;
                }
                record.value = modelInstance._parse(record.field, record.value);
                if (record.hasSubgroups) {
                    convertGroup(record.items, getters, modelInstance, originalFieldNames, fieldNames);
                } else {
                    convertRecords(record.items, getters, modelInstance, originalFieldNames, fieldNames);
                }
            }
        }
        function wrapDataAccess(originalFunction, model, converter, getters, originalFieldNames, fieldNames) {
            return function (data) {
                data = originalFunction(data);
                return wrapDataAccessBase(model, converter, getters, originalFieldNames, fieldNames)(data);
            };
        }
        function wrapDataAccessBase(model, converter, getters, originalFieldNames, fieldNames) {
            return function (data) {
                if (data && !isEmptyObject(getters)) {
                    if (toString.call(data) !== '[object Array]' && !(data instanceof ObservableArray)) {
                        data = [data];
                    }
                    converter(data, getters, new model(), originalFieldNames, fieldNames);
                }
                return data || [];
            };
        }
        var DataReader = Class.extend({
            init: function (schema) {
                var that = this, member, get, model, base;
                schema = schema || {};
                for (member in schema) {
                    get = schema[member];
                    that[member] = typeof get === STRING ? getter(get) : get;
                }
                base = schema.modelBase || Model;
                if (isPlainObject(that.model)) {
                    that.model = model = base.define(that.model);
                }
                var dataFunction = proxy(that.data, that);
                that._dataAccessFunction = dataFunction;
                if (that.model) {
                    var groupsFunction = proxy(that.groups, that), serializeFunction = proxy(that.serialize, that), originalFieldNames = {}, getters = {}, serializeGetters = {}, fieldNames = {}, shouldSerialize = false, fieldName, name;
                    model = that.model;
                    if (model.fields) {
                        each(model.fields, function (field, value) {
                            var fromName;
                            fieldName = field;
                            if (isPlainObject(value) && value.field) {
                                fieldName = value.field;
                            } else if (typeof value === STRING) {
                                fieldName = value;
                            }
                            if (isPlainObject(value) && value.from) {
                                fromName = value.from;
                            }
                            shouldSerialize = shouldSerialize || fromName && fromName !== field || fieldName !== field;
                            name = fromName || fieldName;
                            getters[field] = name.indexOf('.') !== -1 ? getter(name, true) : getter(name);
                            serializeGetters[field] = getter(field);
                            originalFieldNames[fromName || fieldName] = field;
                            fieldNames[field] = fromName || fieldName;
                        });
                        if (!schema.serialize && shouldSerialize) {
                            that.serialize = wrapDataAccess(serializeFunction, model, serializeRecords, serializeGetters, originalFieldNames, fieldNames);
                        }
                    }
                    that._dataAccessFunction = dataFunction;
                    that._wrapDataAccessBase = wrapDataAccessBase(model, convertRecords, getters, originalFieldNames, fieldNames);
                    that.data = wrapDataAccess(dataFunction, model, convertRecords, getters, originalFieldNames, fieldNames);
                    that.groups = wrapDataAccess(groupsFunction, model, convertGroup, getters, originalFieldNames, fieldNames);
                }
            },
            errors: function (data) {
                return data ? data.errors : null;
            },
            parse: identity,
            data: identity,
            total: function (data) {
                return data.length;
            },
            groups: identity,
            aggregates: function () {
                return {};
            },
            serialize: function (data) {
                return data;
            }
        });
        function fillLastGroup(originalGroup, newGroup) {
            var currOriginal;
            var currentNew;
            if (newGroup.items && newGroup.items.length) {
                for (var i = 0; i < newGroup.items.length; i++) {
                    currOriginal = originalGroup.items[i];
                    currentNew = newGroup.items[i];
                    if (currOriginal && currentNew) {
                        if (currOriginal.hasSubgroups) {
                            fillLastGroup(currOriginal, currentNew);
                        } else if (currOriginal.field && currOriginal.value == currentNew.value) {
                            currOriginal.items.push.apply(currOriginal.items, currentNew.items);
                        } else {
                            originalGroup.items.push.apply(originalGroup.items, [currentNew]);
                        }
                    } else if (currentNew) {
                        originalGroup.items.push.apply(originalGroup.items, [currentNew]);
                    }
                }
            }
        }
        function mergeGroups(target, dest, skip, take) {
            var group, idx = 0, items;
            while (dest.length && take) {
                group = dest[idx];
                items = group.items;
                var length = items.length;
                if (target && target.field === group.field && target.value === group.value) {
                    if (target.hasSubgroups && target.items.length) {
                        mergeGroups(target.items[target.items.length - 1], group.items, skip, take);
                    } else {
                        items = items.slice(skip, skip + take);
                        target.items = target.items.concat(items);
                    }
                    dest.splice(idx--, 1);
                } else if (group.hasSubgroups && items.length) {
                    mergeGroups(group, items, skip, take);
                    if (!group.items.length) {
                        dest.splice(idx--, 1);
                    }
                } else {
                    items = items.slice(skip, skip + take);
                    group.items = items;
                    if (!group.items.length) {
                        dest.splice(idx--, 1);
                    }
                }
                if (items.length === 0) {
                    skip -= length;
                } else {
                    skip = 0;
                    take -= items.length;
                }
                if (++idx >= dest.length) {
                    break;
                }
            }
            if (idx < dest.length) {
                dest.splice(idx, dest.length - idx);
            }
        }
        function flatGroups(groups, indexFunction) {
            var result = [];
            var groupsLength = (groups || []).length;
            var group;
            var items;
            var indexFn = isFunction(indexFunction) ? indexFunction : function (array, index) {
                return array[index];
            };
            for (var groupIndex = 0; groupIndex < groupsLength; groupIndex++) {
                group = indexFn(groups, groupIndex);
                if (group.hasSubgroups) {
                    result = result.concat(flatGroups(group.items));
                } else {
                    items = group.items;
                    for (var itemIndex = 0; itemIndex < items.length; itemIndex++) {
                        result.push(indexFn(items, itemIndex));
                    }
                }
            }
            return result;
        }
        function flattenGroups(data) {
            var idx, result = [], length, items, itemIndex;
            for (idx = 0, length = data.length; idx < length; idx++) {
                var group = data.at(idx);
                if (group.hasSubgroups) {
                    result = result.concat(flattenGroups(group.items));
                } else {
                    items = group.items;
                    for (itemIndex = 0; itemIndex < items.length; itemIndex++) {
                        result.push(items.at(itemIndex));
                    }
                }
            }
            return result;
        }
        function wrapGroupItems(data, model) {
            var idx, length, group;
            if (model) {
                for (idx = 0, length = data.length; idx < length; idx++) {
                    group = data.at(idx);
                    if (group.hasSubgroups) {
                        wrapGroupItems(group.items, model);
                    } else {
                        group.items = new LazyObservableArray(group.items, model, group.items._events);
                    }
                }
            }
        }
        function eachGroupItems(data, func) {
            for (var idx = 0; idx < data.length; idx++) {
                if (data[idx].hasSubgroups) {
                    if (eachGroupItems(data[idx].items, func)) {
                        return true;
                    }
                } else if (func(data[idx].items, data[idx])) {
                    return true;
                }
            }
        }
        function replaceInRanges(ranges, data, item, observable) {
            for (var idx = 0; idx < ranges.length; idx++) {
                if (ranges[idx].data === data) {
                    break;
                }
                if (replaceInRange(ranges[idx].data, item, observable)) {
                    break;
                }
            }
        }
        function replaceInRange(items, item, observable) {
            for (var idx = 0, length = items.length; idx < length; idx++) {
                if (items[idx] && items[idx].hasSubgroups) {
                    return replaceInRange(items[idx].items, item, observable);
                } else if (items[idx] === item || items[idx] === observable) {
                    items[idx] = observable;
                    return true;
                }
            }
        }
        function replaceWithObservable(view, data, ranges, type, serverGrouping) {
            for (var viewIndex = 0, length = view.length; viewIndex < length; viewIndex++) {
                var item = view[viewIndex];
                if (!item || item instanceof type) {
                    continue;
                }
                if (item.hasSubgroups !== undefined && !serverGrouping) {
                    replaceWithObservable(item.items, data, ranges, type, serverGrouping);
                } else {
                    for (var idx = 0; idx < data.length; idx++) {
                        if (data[idx] === item) {
                            view[viewIndex] = data.at(idx);
                            replaceInRanges(ranges, data, item, view[viewIndex]);
                            break;
                        }
                    }
                }
            }
        }
        function removeModel(data, model) {
            var length = data.length;
            var dataItem;
            var idx;
            for (idx = 0; idx < length; idx++) {
                dataItem = data[idx];
                if (dataItem.uid && dataItem.uid == model.uid) {
                    data.splice(idx, 1);
                    return dataItem;
                }
            }
        }
        function indexOfPristineModel(data, model) {
            if (model) {
                return indexOf(data, function (item) {
                    return item.uid && item.uid == model.uid || item[model.idField] === model.id && model.id !== model._defaultId;
                });
            }
            return -1;
        }
        function indexOfModel(data, model) {
            if (model) {
                return indexOf(data, function (item) {
                    return item.uid == model.uid;
                });
            }
            return -1;
        }
        function indexOf(data, comparer) {
            var idx, length;
            for (idx = 0, length = data.length; idx < length; idx++) {
                if (comparer(data[idx])) {
                    return idx;
                }
            }
            return -1;
        }
        function fieldNameFromModel(fields, name) {
            if (fields && !isEmptyObject(fields)) {
                var descriptor = fields[name];
                var fieldName;
                if (isPlainObject(descriptor)) {
                    fieldName = descriptor.from || descriptor.field || name;
                } else {
                    fieldName = fields[name] || name;
                }
                if (isFunction(fieldName)) {
                    return name;
                }
                return fieldName;
            }
            return name;
        }
        function convertFilterDescriptorsField(descriptor, model) {
            var idx, length, target = {};
            for (var field in descriptor) {
                if (field !== 'filters') {
                    target[field] = descriptor[field];
                }
            }
            if (descriptor.filters) {
                target.filters = [];
                for (idx = 0, length = descriptor.filters.length; idx < length; idx++) {
                    target.filters[idx] = convertFilterDescriptorsField(descriptor.filters[idx], model);
                }
            } else {
                target.field = fieldNameFromModel(model.fields, target.field);
            }
            return target;
        }
        function convertDescriptorsField(descriptors, model) {
            var idx, length, result = [], target, descriptor;
            for (idx = 0, length = descriptors.length; idx < length; idx++) {
                target = {};
                descriptor = descriptors[idx];
                for (var field in descriptor) {
                    target[field] = descriptor[field];
                }
                target.field = fieldNameFromModel(model.fields, target.field);
                if (target.aggregates && isArray(target.aggregates)) {
                    target.aggregates = convertDescriptorsField(target.aggregates, model);
                }
                result.push(target);
            }
            return result;
        }
        var DataSource = Observable.extend({
            init: function (options) {
                var that = this, model, data;
                if (options) {
                    data = options.data;
                }
                options = that.options = extend({}, that.options, options);
                that._map = {};
                that._prefetch = {};
                that._data = [];
                that._pristineData = [];
                that._ranges = [];
                that._view = [];
                that._pristineTotal = 0;
                that._destroyed = [];
                that._pageSize = options.pageSize;
                that._page = options.page || (options.pageSize ? 1 : undefined);
                that._sort = normalizeSort(options.sort);
                that._filter = normalizeFilter(options.filter);
                that._group = normalizeGroup(options.group);
                that._aggregate = options.aggregate;
                that._total = options.total;
                that._shouldDetachObservableParents = true;
                Observable.fn.init.call(that);
                that.transport = Transport.create(options, data, that);
                if (isFunction(that.transport.push)) {
                    that.transport.push({
                        pushCreate: proxy(that._pushCreate, that),
                        pushUpdate: proxy(that._pushUpdate, that),
                        pushDestroy: proxy(that._pushDestroy, that)
                    });
                }
                if (options.offlineStorage != null) {
                    if (typeof options.offlineStorage == 'string') {
                        var key = options.offlineStorage;
                        that._storage = {
                            getItem: function () {
                                return JSON.parse(localStorage.getItem(key));
                            },
                            setItem: function (item) {
                                localStorage.setItem(key, stringify(that.reader.serialize(item)));
                            }
                        };
                    } else {
                        that._storage = options.offlineStorage;
                    }
                }
                that.reader = new kendo.data.readers[options.schema.type || 'json'](options.schema);
                model = that.reader.model || {};
                that._detachObservableParents();
                that._data = that._observe(that._data);
                that._online = true;
                that.bind([
                    'push',
                    ERROR,
                    CHANGE,
                    REQUESTSTART,
                    SYNC,
                    REQUESTEND,
                    PROGRESS
                ], options);
            },
            options: {
                data: null,
                schema: { modelBase: Model },
                offlineStorage: null,
                serverSorting: false,
                serverPaging: false,
                serverFiltering: false,
                serverGrouping: false,
                serverAggregates: false,
                batch: false,
                inPlaceSort: false
            },
            clone: function () {
                return this;
            },
            online: function (value) {
                if (value !== undefined) {
                    if (this._online != value) {
                        this._online = value;
                        if (value) {
                            return this.sync();
                        }
                    }
                    return $.Deferred().resolve().promise();
                } else {
                    return this._online;
                }
            },
            offlineData: function (state) {
                if (this.options.offlineStorage == null) {
                    return null;
                }
                if (state !== undefined) {
                    return this._storage.setItem(state);
                }
                return this._storage.getItem() || [];
            },
            _isServerGrouped: function () {
                var group = this.group() || [];
                return this.options.serverGrouping && group.length;
            },
            _pushCreate: function (result) {
                this._push(result, 'pushCreate');
            },
            _pushUpdate: function (result) {
                this._push(result, 'pushUpdate');
            },
            _pushDestroy: function (result) {
                this._push(result, 'pushDestroy');
            },
            _push: function (result, operation) {
                var data = this._readData(result);
                if (!data) {
                    data = result;
                }
                this[operation](data);
            },
            _flatData: function (data, skip) {
                if (data) {
                    if (this._isServerGrouped()) {
                        return flattenGroups(data);
                    }
                    if (!skip) {
                        for (var idx = 0; idx < data.length; idx++) {
                            data.at(idx);
                        }
                    }
                }
                return data;
            },
            parent: noop,
            get: function (id) {
                var idx, length, data = this._flatData(this._data, this.options.useRanges);
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].id == id) {
                        return data[idx];
                    }
                }
            },
            getByUid: function (id) {
                return this._getByUid(id, this._data);
            },
            _getByUid: function (id, dataItems) {
                var idx, length, data = this._flatData(dataItems, this.options.useRanges);
                if (!data) {
                    return;
                }
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].uid == id) {
                        return data[idx];
                    }
                }
            },
            indexOf: function (model) {
                return indexOfModel(this._data, model);
            },
            at: function (index) {
                return this._data.at(index);
            },
            data: function (value) {
                var that = this;
                if (value !== undefined) {
                    that._detachObservableParents();
                    that._data = this._observe(value);
                    that._pristineData = value.slice(0);
                    that._storeData();
                    that._ranges = [];
                    that.trigger('reset');
                    that._addRange(that._data);
                    that._total = that._data.length;
                    that._pristineTotal = that._total;
                    that._process(that._data);
                } else {
                    if (that._data) {
                        for (var idx = 0; idx < that._data.length; idx++) {
                            that._data.at(idx);
                        }
                    }
                    return that._data;
                }
            },
            view: function (value) {
                if (value === undefined) {
                    return this._view;
                } else {
                    this._view = this._observeView(value);
                }
            },
            _observeView: function (data) {
                var that = this;
                replaceWithObservable(data, that._data, that._ranges, that.reader.model || ObservableObject, that._isServerGrouped());
                var view = new LazyObservableArray(data, that.reader.model);
                view.parent = function () {
                    return that.parent();
                };
                return view;
            },
            flatView: function () {
                var groups = this.group() || [];
                if (groups.length) {
                    return flattenGroups(this._view);
                } else {
                    return this._view;
                }
            },
            add: function (model) {
                return this.insert(this._data.length, model);
            },
            _createNewModel: function (model) {
                if (this.reader.model) {
                    return new this.reader.model(model);
                }
                if (model instanceof ObservableObject) {
                    return model;
                }
                return new ObservableObject(model);
            },
            insert: function (index, model) {
                if (!model) {
                    model = index;
                    index = 0;
                }
                if (!(model instanceof Model)) {
                    model = this._createNewModel(model);
                }
                if (this._isServerGrouped()) {
                    this._data.splice(index, 0, this._wrapInEmptyGroup(model));
                } else {
                    this._data.splice(index, 0, model);
                }
                this._insertModelInRange(index, model);
                return model;
            },
            pushInsert: function (index, items) {
                var that = this;
                var rangeSpan = that._getCurrentRangeSpan();
                if (!items) {
                    items = index;
                    index = 0;
                }
                if (!isArray(items)) {
                    items = [items];
                }
                var pushed = [];
                var autoSync = this.options.autoSync;
                this.options.autoSync = false;
                try {
                    for (var idx = 0; idx < items.length; idx++) {
                        var item = items[idx];
                        var result = this.insert(index, item);
                        pushed.push(result);
                        var pristine = result.toJSON();
                        if (this._isServerGrouped()) {
                            pristine = this._wrapInEmptyGroup(pristine);
                        }
                        this._pristineData.push(pristine);
                        if (rangeSpan && rangeSpan.length) {
                            $(rangeSpan).last()[0].pristineData.push(pristine);
                        }
                        index++;
                    }
                } finally {
                    this.options.autoSync = autoSync;
                }
                if (pushed.length) {
                    this.trigger('push', {
                        type: 'create',
                        items: pushed
                    });
                }
            },
            pushCreate: function (items) {
                this.pushInsert(this._data.length, items);
            },
            pushUpdate: function (items) {
                if (!isArray(items)) {
                    items = [items];
                }
                var pushed = [];
                for (var idx = 0; idx < items.length; idx++) {
                    var item = items[idx];
                    var model = this._createNewModel(item);
                    var target = this.get(model.id);
                    if (target) {
                        pushed.push(target);
                        target.accept(item);
                        target.trigger(CHANGE);
                        this._updatePristineForModel(target, item);
                    } else {
                        this.pushCreate(item);
                    }
                }
                if (pushed.length) {
                    this.trigger('push', {
                        type: 'update',
                        items: pushed
                    });
                }
            },
            pushDestroy: function (items) {
                var pushed = this._removeItems(items);
                if (pushed.length) {
                    this.trigger('push', {
                        type: 'destroy',
                        items: pushed
                    });
                }
            },
            _removeItems: function (items, removePristine) {
                if (!isArray(items)) {
                    items = [items];
                }
                var shouldRemovePristine = typeof removePristine !== 'undefined' ? removePristine : true;
                var destroyed = [];
                var autoSync = this.options.autoSync;
                this.options.autoSync = false;
                try {
                    for (var idx = 0; idx < items.length; idx++) {
                        var item = items[idx];
                        var model = this._createNewModel(item);
                        var found = false;
                        this._eachItem(this._data, function (items) {
                            for (var idx = 0; idx < items.length; idx++) {
                                var item = items.at(idx);
                                if (item.id === model.id) {
                                    destroyed.push(item);
                                    items.splice(idx, 1);
                                    found = true;
                                    break;
                                }
                            }
                        });
                        if (found && shouldRemovePristine) {
                            this._removePristineForModel(model);
                            this._destroyed.pop();
                        }
                    }
                } finally {
                    this.options.autoSync = autoSync;
                }
                return destroyed;
            },
            remove: function (model) {
                var result, that = this, hasGroups = that._isServerGrouped();
                this._eachItem(that._data, function (items) {
                    result = removeModel(items, model);

                    //Custom Change - START// // no keep // (--DATASOURCE--)
                    //if (!that._deletedItems)
                    //    that._deletedItems = [];
                    //that._deletedItems.push(result);
                    //Custom Change - END// // no keep //

                    if (result && hasGroups) {
                        if (!result.isNew || !result.isNew()) {
                            that._destroyed.push(result);
                        }
                        return true;
                    }
                });
                this._removeModelFromRanges(model);
                return model;
            },
            destroyed: function () {
                return this._destroyed;
            },
            created: function () {
                var idx, length, result = [], data = this._flatData(this._data, this.options.useRanges);
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].isNew && data[idx].isNew()) {
                        result.push(data[idx]);
                    }
                }
                return result;
            },
            updated: function () {
                var idx, length, result = [], data = this._flatData(this._data, this.options.useRanges);
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].isNew && !data[idx].isNew() && data[idx].dirty) {
                        result.push(data[idx]);
                    }
                }
                return result;
            },
            sync: function () {
                var that = this, created = [], updated = [], destroyed = that._destroyed;
                var promise = $.Deferred().resolve().promise();
                if (that.online()) {
                    if (!that.reader.model) {
                        return promise;
                    }
                    created = that.created();
                    updated = that.updated();
                    var promises = [];
                    if (that.options.batch && that.transport.submit) {
                        promises = that._sendSubmit(created, updated, destroyed);
                    } else {
                        promises.push.apply(promises, that._send('create', created));
                        promises.push.apply(promises, that._send('update', updated));
                        promises.push.apply(promises, that._send('destroy', destroyed));
                    }
                    promise = $.when.apply(null, promises).then(function () {
                        var idx, length;
                        for (idx = 0, length = arguments.length; idx < length; idx++) {
                            if (arguments[idx]) {
                                that._accept(arguments[idx]);
                            }
                        }
                        that._storeData(true);
                        that._syncEnd();
                        that._change({ action: 'sync' });
                        that.trigger(SYNC);
                    });
                } else {
                    that._storeData(true);
                    that._syncEnd();
                    that._change({ action: 'sync' });
                }
                return promise;
            },
            _syncEnd: noop,
            cancelChanges: function (model) {
                var that = this;
                if (model instanceof kendo.data.Model) {
                    that._cancelModel(model);
                } else {
                    that._destroyed = [];
                    that._detachObservableParents();
                    that._data = that._observe(that._pristineData);
                    if (that.options.serverPaging) {
                        that._total = that._pristineTotal;
                    }
                    that._ranges = [];
                    that._addRange(that._data, 0);
                    that._changesCanceled();
                    that._change();
                    that._markOfflineUpdatesAsDirty();
                }
            },
            _changesCanceled: noop,
            _markOfflineUpdatesAsDirty: function () {
                var that = this;
                if (that.options.offlineStorage != null) {
                    that._eachItem(that._data, function (items) {
                        for (var idx = 0; idx < items.length; idx++) {
                            var item = items.at(idx);
                            if (item.__state__ == 'update' || item.__state__ == 'create') {
                                item.dirty = true;
                            }
                        }
                    });
                }
            },
            hasChanges: function () {
                var idx, length, data = this._flatData(this._data, this.options.useRanges);
                if (this._destroyed.length) {
                    return true;
                }
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].isNew && data[idx].isNew() || data[idx].dirty) {
                        return true;
                    }
                }
                return false;
            },
            _accept: function (result) {
                var that = this, models = result.models, response = result.response, idx = 0, serverGroup = that._isServerGrouped(), pristine = that._pristineData, type = result.type, length;
                that.trigger(REQUESTEND, {
                    response: response,
                    type: type
                });
                if (response && !isEmptyObject(response)) {
                    response = that.reader.parse(response);
                    if (that._handleCustomErrors(response)) {
                        return;
                    }
                    response = that.reader.data(response);
                    if (!isArray(response)) {
                        response = [response];
                    }
                } else {
                    response = $.map(models, function (model) {
                        return model.toJSON();
                    });
                }
                if (type === 'destroy') {
                    that._destroyed = [];
                }
                for (idx = 0, length = models.length; idx < length; idx++) {
                    if (type !== 'destroy') {
                        models[idx].accept(response[idx]);
                        if (type === 'create') {
                            pristine.push(serverGroup ? that._wrapInEmptyGroup(models[idx].toJSON()) : response[idx]);
                        } else if (type === 'update') {
                            that._updatePristineForModel(models[idx], response[idx]);
                        }
                    } else {
                        that._removePristineForModel(models[idx]);
                    }
                }
            },
            _updatePristineForModel: function (model, values) {
                this._executeOnPristineForModel(model, function (index, items) {
                    kendo.deepExtend(items[index], values);
                });
            },
            _executeOnPristineForModel: function (model, callback) {
                this._eachPristineItem(function (items) {
                    var index = indexOfPristineModel(items, model);
                    if (index > -1) {
                        callback(index, items);
                        return true;
                    }
                });
            },
            _removePristineForModel: function (model) {
                this._executeOnPristineForModel(model, function (index, items) {
                    items.splice(index, 1);
                });
            },
            _readData: function (data) {
                var read = !this._isServerGrouped() ? this.reader.data : this.reader.groups;
                return read.call(this.reader, data);
            },
            _eachPristineItem: function (callback) {
                var that = this;
                var options = that.options;
                var rangeSpan = that._getCurrentRangeSpan();
                that._eachItem(that._pristineData, callback);
                if (options.serverPaging && options.useRanges) {
                    each(rangeSpan, function (i, range) {
                        that._eachItem(range.pristineData, callback);
                    });
                }
            },
            _eachItem: function (data, callback) {
                if (data && data.length) {
                    if (this._isServerGrouped()) {
                        eachGroupItems(data, callback);
                    } else {
                        callback(data);
                    }
                }
            },
            _pristineForModel: function (model) {
                var pristine, idx, callback = function (items) {
                        idx = indexOfPristineModel(items, model);
                        if (idx > -1) {
                            pristine = items[idx];
                            return true;
                        }
                    };
                this._eachPristineItem(callback);
                return pristine;
            },
            _cancelModel: function (model) {
                var that = this;
                var pristine = this._pristineForModel(model);
                this._eachItem(this._data, function (items) {
                    var idx = indexOfModel(items, model);
                    if (idx >= 0) {
                        if (pristine && (!model.isNew() || pristine.__state__)) {
                            items[idx].accept(pristine);
                            if (pristine.__state__ == 'update') {
                                items[idx].dirty = true;
                            }
                        } else {
                            that._modelCanceled(model);
                            items.splice(idx, 1);
                            that._removeModelFromRanges(model);
                        }
                    }
                });
            },
            _modelCanceled: noop,
            _submit: function (promises, data) {
                var that = this;
                that.trigger(REQUESTSTART, { type: 'submit' });
                that.trigger(PROGRESS);
                that.transport.submit(extend({
                    success: function (response, type) {
                        var promise = $.grep(promises, function (x) {
                            return x.type == type;
                        })[0];
                        if (promise) {
                            promise.resolve({
                                response: response,
                                models: promise.models,
                                type: type
                            });
                        }
                    },
                    error: function (response, status, error) {
                        for (var idx = 0; idx < promises.length; idx++) {
                            promises[idx].reject(response);
                        }
                        that.error(response, status, error);
                    }
                }, data));
            },
            _sendSubmit: function (created, updated, destroyed) {
                var that = this, promises = [];
                if (that.options.batch) {
                    if (created.length) {
                        promises.push($.Deferred(function (deferred) {
                            deferred.type = 'create';
                            deferred.models = created;
                        }));
                    }
                    if (updated.length) {
                        promises.push($.Deferred(function (deferred) {
                            deferred.type = 'update';
                            deferred.models = updated;
                        }));
                    }
                    if (destroyed.length) {
                        promises.push($.Deferred(function (deferred) {
                            deferred.type = 'destroy';
                            deferred.models = destroyed;
                        }));
                    }
                    that._submit(promises, {
                        data: {
                            created: that.reader.serialize(toJSON(created)),
                            updated: that.reader.serialize(toJSON(updated)),
                            destroyed: that.reader.serialize(toJSON(destroyed))
                        }
                    });
                }
                return promises;
            },
            _promise: function (data, models, type) {
                var that = this;
                return $.Deferred(function (deferred) {
                    that.trigger(REQUESTSTART, { type: type });
                    that.trigger(PROGRESS);
                    that.transport[type].call(that.transport, extend({
                        success: function (response) {
                            deferred.resolve({
                                response: response,
                                models: models,
                                type: type
                            });
                        },
                        error: function (response, status, error) {
                            deferred.reject(response);
                            that.error(response, status, error);
                        }
                    }, data));
                }).promise();
            },
            _send: function (method, data) {
                var that = this, idx, length, promises = [], converted = that.reader.serialize(toJSON(data));
                if (that.options.batch) {
                    if (data.length) {
                        promises.push(that._promise({ data: { models: converted } }, data, method));
                    }
                } else {
                    for (idx = 0, length = data.length; idx < length; idx++) {
                        promises.push(that._promise({ data: converted[idx] }, [data[idx]], method));
                    }
                }
                return promises;
            },
            read: function (data) {
                var that = this, params = that._params(data);
                var deferred = $.Deferred();
                that._queueRequest(params, function () {
                    var isPrevented = that.trigger(REQUESTSTART, { type: 'read' });
                    if (!isPrevented) {
                        that.trigger(PROGRESS);
                        that._ranges = [];
                        that.trigger('reset');
                        if (that.online()) {
                            that.transport.read({
                                data: params,
                                success: function (data) {
                                    that._ranges = [];
                                    that.success(data, params);
                                    deferred.resolve();
                                },
                                error: function () {
                                    var args = slice.call(arguments);
                                    that.error.apply(that, args);
                                    deferred.reject.apply(deferred, args);
                                }
                            });
                        } else if (that.options.offlineStorage != null) {
                            that.success(that.offlineData(), params);
                            deferred.resolve();
                        }
                    } else {
                        that._dequeueRequest();
                        deferred.resolve(isPrevented);
                    }
                });
                return deferred.promise();
            },
            _readAggregates: function (data) {
                return this.reader.aggregates(data);
            },
            success: function (data) {
                var that = this, options = that.options, items, replaceSubset;
                that.trigger(REQUESTEND, {
                    response: data,
                    type: 'read'
                });
                if (that.online()) {
                    data = that.reader.parse(data);
                    if (that._handleCustomErrors(data)) {
                        that._dequeueRequest();
                        return;
                    }
                    that._total = that.reader.total(data);
                    if (that._pageSize > that._total) {
                        that._pageSize = that._total;
                        if (that.options.pageSize && that.options.pageSize > that._pageSize) {
                            that._pageSize = that.options.pageSize;
                        }
                    }
                    if (that._aggregate && options.serverAggregates) {
                        that._aggregateResult = that._readAggregates(data);
                    }
                    data = that._readData(data);
                    that._destroyed = [];
                } else {
                    data = that._readData(data);
                    items = [];
                    var itemIds = {};
                    var model = that.reader.model;
                    var idField = model ? model.idField : 'id';
                    var idx;
                    for (idx = 0; idx < this._destroyed.length; idx++) {
                        var id = this._destroyed[idx][idField];
                        itemIds[id] = id;
                    }
                    for (idx = 0; idx < data.length; idx++) {
                        var item = data[idx];
                        var state = item.__state__;
                        if (state == 'destroy') {
                            if (!itemIds[item[idField]]) {
                                this._destroyed.push(this._createNewModel(item));
                            }
                        } else {
                            items.push(item);
                        }
                    }
                    data = items;
                    that._total = data.length;
                }
                that._pristineTotal = that._total;
                replaceSubset = that._skip && that._data.length && that._skip < that._data.length;
                if (that.options.endless) {
                    if (replaceSubset) {
                        that._pristineData.splice(that._skip, that._pristineData.length);
                    }
                    items = data.slice(0);
                    for (var j = 0; j < items.length; j++) {
                        that._pristineData.push(items[j]);
                    }
                } else {
                    that._pristineData = data.slice(0);
                }
                that._detachObservableParents();
                if (that.options.endless) {
                    that._data.unbind(CHANGE, that._changeHandler);
                    if (that._isServerGrouped() && that._data[that._data.length - 1].value === data[0].value) {
                        fillLastGroup(that._data[that._data.length - 1], data[0]);
                        data.shift();
                    }
                    data = that._observe(data);
                    if (replaceSubset) {
                        that._data.splice(that._skip, that._data.length);
                    }
                    for (var i = 0; i < data.length; i++) {
                        that._data.push(data[i]);
                    }
                    that._data.bind(CHANGE, that._changeHandler);
                } else {
                    that._data = that._observe(data);
                }
                that._markOfflineUpdatesAsDirty();
                that._storeData();
                that._addRange(that._data);
                that._process(that._data);
                that._dequeueRequest();
            },
            _detachObservableParents: function () {
                if (this._data && this._shouldDetachObservableParents) {
                    for (var idx = 0; idx < this._data.length; idx++) {
                        if (this._data[idx].parent) {
                            this._data[idx].parent = noop;
                        }
                    }
                }
            },
            _storeData: function (updatePristine) {
                var serverGrouping = this._isServerGrouped();
                var model = this.reader.model;
                function items(data) {
                    var state = [];
                    for (var idx = 0; idx < data.length; idx++) {
                        var dataItem = data.at(idx);
                        var item = dataItem.toJSON();
                        if (serverGrouping && dataItem.items) {
                            item.items = items(dataItem.items);
                        } else {
                            item.uid = dataItem.uid;
                            if (model) {
                                if (dataItem.isNew()) {
                                    item.__state__ = 'create';
                                } else if (dataItem.dirty) {
                                    item.__state__ = 'update';
                                }
                            }
                        }
                        state.push(item);
                    }
                    return state;
                }
                if (this.options.offlineStorage != null) {
                    var state = items(this._data);
                    var destroyed = [];
                    for (var idx = 0; idx < this._destroyed.length; idx++) {
                        var item = this._destroyed[idx].toJSON();
                        item.__state__ = 'destroy';
                        destroyed.push(item);
                    }
                    this.offlineData(state.concat(destroyed));
                    if (updatePristine) {
                        this._pristineData = this.reader.reader ? this.reader.reader._wrapDataAccessBase(state) : this.reader._wrapDataAccessBase(state);
                    }
                }
            },
            _addRange: function (data, skip) {
                var that = this, start = typeof skip !== 'undefined' ? skip : that._skip || 0, end = start + that._flatData(data, true).length;
                that._ranges.push({
                    start: start,
                    end: end,
                    data: data,
                    pristineData: data.toJSON(),
                    timestamp: that._timeStamp()
                });
                that._sortRanges();
            },
            _sortRanges: function () {
                this._ranges.sort(function (x, y) {
                    return x.start - y.start;
                });
            },
            error: function (xhr, status, errorThrown) {
                this._dequeueRequest();
                this.trigger(REQUESTEND, {});
                this.trigger(ERROR, {
                    xhr: xhr,
                    status: status,
                    errorThrown: errorThrown
                });
            },
            _params: function (data) {
                var that = this, options = extend({
                        take: that.take(),
                        skip: that.skip(),
                        page: that.page(),
                        pageSize: that.pageSize(),
                        sort: that._sort,
                        filter: that._filter,
                        group: that._group,
                        aggregate: that._aggregate
                    }, data);
                if (!that.options.serverPaging) {
                    delete options.take;
                    delete options.skip;
                    delete options.page;
                    delete options.pageSize;
                }
                if (!that.options.serverGrouping) {
                    delete options.group;
                } else if (that.reader.model && options.group) {
                    options.group = convertDescriptorsField(options.group, that.reader.model);
                }
                if (!that.options.serverFiltering) {
                    delete options.filter;
                } else if (that.reader.model && options.filter) {
                    options.filter = convertFilterDescriptorsField(options.filter, that.reader.model);
                }
                if (!that.options.serverSorting) {
                    delete options.sort;
                } else if (that.reader.model && options.sort) {
                    options.sort = convertDescriptorsField(options.sort, that.reader.model);
                }
                if (!that.options.serverAggregates) {
                    delete options.aggregate;
                } else if (that.reader.model && options.aggregate) {
                    options.aggregate = convertDescriptorsField(options.aggregate, that.reader.model);
                }
                return options;
            },
            _queueRequest: function (options, callback) {
                var that = this;
                if (!that._requestInProgress) {
                    that._requestInProgress = true;
                    that._pending = undefined;
                    callback();
                } else {
                    that._pending = {
                        callback: proxy(callback, that),
                        options: options
                    };
                }
            },
            _dequeueRequest: function () {
                var that = this;
                that._requestInProgress = false;
                if (that._pending) {
                    that._queueRequest(that._pending.options, that._pending.callback);
                }
            },
            _handleCustomErrors: function (response) {
                if (this.reader.errors) {
                    var errors = this.reader.errors(response);
                    if (errors) {
                        this.trigger(ERROR, {
                            xhr: null,
                            status: 'customerror',
                            errorThrown: 'custom error',
                            errors: errors
                        });
                        return true;
                    }
                }
                return false;
            },
            _shouldWrap: function (data) {
                var model = this.reader.model;
                if (model && data.length) {
                    return !(data[0] instanceof model);
                }
                return false;
            },
            _observe: function (data) {
                var that = this, model = that.reader.model;
                that._shouldDetachObservableParents = true;
                if (data instanceof ObservableArray) {
                    that._shouldDetachObservableParents = false;
                    if (that._shouldWrap(data)) {
                        data.type = that.reader.model;
                        data.wrapAll(data, data);
                    }
                } else {
                    var arrayType = that.pageSize() && !that.options.serverPaging ? LazyObservableArray : ObservableArray;
                    data = new arrayType(data, that.reader.model);
                    data.parent = function () {
                        return that.parent();
                    };
                }
                if (that._isServerGrouped()) {
                    wrapGroupItems(data, model);
                }
                if (that._changeHandler && that._data && that._data instanceof ObservableArray && !(that.options.useRanges && that.options.serverPaging)) {
                    that._data.unbind(CHANGE, that._changeHandler);
                } else {
                    that._changeHandler = proxy(that._change, that);
                }
                return data.bind(CHANGE, that._changeHandler);
            },
            _updateTotalForAction: function (action, items) {
                var that = this;
                var total = parseInt(that._total, 10);
                if (!isNumber(that._total)) {
                    total = parseInt(that._pristineTotal, 10);
                }
                if (action === 'add') {
                    total += items.length;
                } else if (action === 'remove') {
                    total -= items.length;
                } else if (action !== 'itemchange' && action !== 'sync' && !that.options.serverPaging) {
                    total = that._pristineTotal;
                } else if (action === 'sync') {
                    total = that._pristineTotal = parseInt(that._total, 10);
                }
                that._total = total;
            },
            _change: function (e) {
                var that = this, idx, length, action = e ? e.action : '';
                if (action === 'remove') {
                    for (idx = 0, length = e.items.length; idx < length; idx++) {
                        if (!e.items[idx].isNew || !e.items[idx].isNew()) {
                            that._destroyed.push(e.items[idx]);
                        }
                    }
                }
                if (that.options.autoSync && (action === 'add' || action === 'remove' || action === 'itemchange')) {
                    var handler = function (args) {
                        if (args.action === 'sync') {
                            that.unbind('change', handler);
                            that._updateTotalForAction(action, e.items);
                        }
                    };
                    that.first('change', handler);
                    that.sync();
                } else {
                    that._updateTotalForAction(action, e ? e.items : []);
                    that._process(that._data, e);
                }
            },
            _calculateAggregates: function (data, options) {
                options = options || {};
                var query = new Query(data), aggregates = options.aggregate, filter = options.filter;
                if (filter) {
                    query = query.filter(filter);
                }
                return query.aggregate(aggregates);
            },
            _process: function (data, e) {
                var that = this, options = {}, result;
                if (that.options.serverPaging !== true) {
                    options.skip = that._skip;
                    options.take = that._take || that._pageSize;
                    if (options.skip === undefined && that._page !== undefined && that._pageSize !== undefined) {
                        options.skip = (that._page - 1) * that._pageSize;
                    }
                    if (that.options.useRanges) {
                        options.skip = that.currentRangeStart();
                    }
                }
                if (that.options.serverSorting !== true) {
                    options.sort = that._sort;
                }
                if (that.options.serverFiltering !== true) {
                    options.filter = that._filter;
                }
                if (that.options.serverGrouping !== true) {
                    options.group = that._group;
                }
                if (that.options.serverAggregates !== true) {
                    options.aggregate = that._aggregate;
                }
                if (that.options.serverGrouping) {
                    that._clearEmptyGroups(data);
                }
                result = that._queryProcess(data, options);
                if (that.options.serverAggregates !== true) {
                    that._aggregateResult = that._calculateAggregates(result.dataToAggregate || data, options);
                }
                that.view(result.data);
                that._setFilterTotal(result.total, false);
                e = e || {};
                e.items = e.items || that._view;
                that.trigger(CHANGE, e);
            },
            _clearEmptyGroups: function (data) {
                for (var idx = data.length - 1; idx >= 0; idx--) {
                    var group = data[idx];
                    if (group.hasSubgroups) {
                        this._clearEmptyGroups(group.items);
                    } else {
                        if (group.items && !group.items.length) {
                            splice.apply(group.parent(), [
                                idx,
                                1
                            ]);
                        }
                    }
                }
            },
            _queryProcess: function (data, options) {
                if (this.options.inPlaceSort) {
                    return Query.process(data, options, this.options.inPlaceSort);
                } else {
                    return Query.process(data, options);
                }
            },
            _mergeState: function (options) {
                var that = this;
                if (options !== undefined) {
                    that._pageSize = options.pageSize;
                    that._page = options.page;
                    that._sort = options.sort;
                    that._filter = options.filter;
                    that._group = options.group;
                    that._aggregate = options.aggregate;
                    that._skip = that._currentRangeStart = options.skip;
                    that._take = options.take;
                    if (that._skip === undefined) {
                        that._skip = that._currentRangeStart = that.skip();
                        options.skip = that.skip();
                    }
                    if (that._take === undefined && that._pageSize !== undefined) {
                        that._take = that._pageSize;
                        options.take = that._take;
                    }
                    if (options.sort) {
                        that._sort = options.sort = normalizeSort(options.sort);
                    }
                    if (options.filter) {
                        that._filter = options.filter = that.options.accentFoldingFiltering && !$.isEmptyObject(options.filter) ? $.extend({}, normalizeFilter(options.filter), { accentFoldingFiltering: that.options.accentFoldingFiltering }) : normalizeFilter(options.filter);
                    }
                    if (options.group) {
                        that._group = options.group = normalizeGroup(options.group);
                    }
                    if (options.aggregate) {
                        that._aggregate = options.aggregate = normalizeAggregate(options.aggregate);
                    }
                }
                return options;
            },
            query: function (options) {
                var result;
                var remote = this.options.serverSorting || this.options.serverPaging || this.options.serverFiltering || this.options.serverGrouping || this.options.serverAggregates;
                if (remote || (this._data === undefined || this._data.length === 0) && !this._destroyed.length) {
                    if (this.options.endless) {
                        var moreItemsCount = options.pageSize - this.pageSize();
                        if (moreItemsCount > 0) {
                            moreItemsCount = this.pageSize();
                            options.page = options.pageSize / moreItemsCount;
                            options.pageSize = moreItemsCount;
                        } else {
                            options.page = 1;
                            this.options.endless = false;
                        }
                    }
                    return this.read(this._mergeState(options));
                }
                var isPrevented = this.trigger(REQUESTSTART, { type: 'read' });
                if (!isPrevented) {
                    this.trigger(PROGRESS);
                    result = this._queryProcess(this._data, this._mergeState(options));
                    this._setFilterTotal(result.total, true);
                    this._aggregateResult = this._calculateAggregates(result.dataToAggregate || this._data, options);
                    this.view(result.data);
                    this.trigger(REQUESTEND, { type: 'read' });
                    this.trigger(CHANGE, { items: result.data });
                }
                return $.Deferred().resolve(isPrevented).promise();
            },
            _setFilterTotal: function (filterTotal, setDefaultValue) {
                var that = this;
                if (!that.options.serverFiltering) {
                    if (filterTotal !== undefined) {
                        that._total = filterTotal;
                    } else if (setDefaultValue) {
                        that._total = that._data.length;
                    }
                }
            },
            fetch: function (callback) {
                var that = this;
                var fn = function (isPrevented) {
                    if (isPrevented !== true && isFunction(callback)) {
                        callback.call(that);
                    }
                };
                return this._query().done(fn);
            },
            _query: function (options) {
                var that = this;
                return that.query(extend({}, {
                    page: that.page(),
                    pageSize: that.pageSize(),
                    sort: that.sort(),
                    filter: that.filter(),
                    group: that.group(),
                    aggregate: that.aggregate()
                }, options));
            },
            next: function (options) {
                var that = this, page = that.page(), total = that.total();
                options = options || {};
                if (!page || total && page + 1 > that.totalPages()) {
                    return;
                }
                that._skip = that._currentRangeStart = page * that.take();
                page += 1;
                options.page = page;
                that._query(options);
                return page;
            },
            prev: function (options) {
                var that = this, page = that.page();
                options = options || {};
                if (!page || page === 1) {
                    return;
                }
                that._skip = that._currentRangeStart = that._skip - that.take();
                page -= 1;
                options.page = page;
                that._query(options);
                return page;
            },
            page: function (val) {
                var that = this, skip;
                if (val !== undefined) {
                    val = math.max(math.min(math.max(val, 1), that.totalPages()), 1);
                    that._query(that._pageableQueryOptions({ page: val }));
                    return;
                }
                skip = that.skip();
                return skip !== undefined ? math.round((skip || 0) / (that.take() || 1)) + 1 : undefined;
            },
            pageSize: function (val) {
                var that = this;
                if (val !== undefined) {
                    that._query(that._pageableQueryOptions({
                        pageSize: val,
                        page: 1
                    }));
                    return;
                }
                return that.take();
            },
            sort: function (val) {
                var that = this;
                if (val !== undefined) {
                    that._query({ sort: val });
                    return;
                }
                return that._sort;
            },
            filter: function (val) {
                var that = this;
                if (val === undefined) {
                    return that._filter;
                }
                that.trigger('reset');
                that._query({
                    filter: val,
                    page: 1
                });
            },
            group: function (val) {
                var that = this;
                if (val !== undefined) {
                    that._query({ group: val });
                    return;
                }
                return that._group;
            },
            total: function () {
                return parseInt(this._total || 0, 10);
            },
            aggregate: function (val) {
                var that = this;
                if (val !== undefined) {
                    that._query({ aggregate: val });
                    return;
                }
                return that._aggregate;
            },
            aggregates: function () {
                var result = this._aggregateResult;
                if (isEmptyObject(result)) {
                    result = this._emptyAggregates(this.aggregate());
                }
                return result;
            },
            _emptyAggregates: function (aggregates) {
                var result = {};
                if (!isEmptyObject(aggregates)) {
                    var aggregate = {};
                    if (!isArray(aggregates)) {
                        aggregates = [aggregates];
                    }
                    for (var idx = 0; idx < aggregates.length; idx++) {
                        aggregate[aggregates[idx].aggregate] = 0;
                        result[aggregates[idx].field] = aggregate;
                    }
                }
                return result;
            },
            _pageableQueryOptions: function (options) {
                return options;
            },
            _wrapInEmptyGroup: function (model) {
                var groups = this.group(), parent, group, idx, length;
                for (idx = groups.length - 1, length = 0; idx >= length; idx--) {
                    group = groups[idx];
                    parent = {
                        value: model.get ? model.get(group.field) : model[group.field],
                        field: group.field,
                        items: parent ? [parent] : [model],
                        hasSubgroups: !!parent,
                        aggregates: this._emptyAggregates(group.aggregates)
                    };
                }
                return parent;
            },
            totalPages: function () {
                var that = this, pageSize = that.pageSize() || that.total();
                return math.ceil((that.total() || 0) / pageSize);
            },
            inRange: function (skip, take) {
                var that = this, end = math.min(skip + take, that.total());
                if (!that.options.serverPaging && that._data.length > 0) {
                    return true;
                }
                return that._findRange(skip, end).length > 0;
            },
            lastRange: function () {
                var ranges = this._ranges;
                return ranges[ranges.length - 1] || {
                    start: 0,
                    end: 0,
                    data: []
                };
            },
            firstItemUid: function () {
                var ranges = this._ranges;
                return ranges.length && ranges[0].data.length && ranges[0].data[0].uid;
            },
            enableRequestsInProgress: function () {
                this._skipRequestsInProgress = false;
            },
            _timeStamp: function () {
                return new Date().getTime();
            },
            range: function (skip, take, callback) {
                this._currentRequestTimeStamp = this._timeStamp();
                this._skipRequestsInProgress = true;
                skip = math.min(skip || 0, this.total());
                callback = isFunction(callback) ? callback : noop;
                var that = this, pageSkip = math.max(math.floor(skip / take), 0) * take, size = math.min(pageSkip + take, that.total()), data;
                data = that._findRange(skip, math.min(skip + take, that.total()));
                if (data.length || that.total() === 0) {
                    that._processRangeData(data, skip, take, pageSkip, size);
                    callback();
                    return;
                }
                if (take !== undefined) {
                    if (!that._rangeExists(pageSkip, size)) {
                        that.prefetch(pageSkip, take, function () {
                            if (skip > pageSkip && size < that.total() && !that._rangeExists(size, math.min(size + take, that.total()))) {
                                that.prefetch(size, take, function () {
                                    that.range(skip, take, callback);
                                });
                            } else {
                                that.range(skip, take, callback);
                            }
                        });
                    } else if (pageSkip < skip) {
                        that.prefetch(size, take, function () {
                            that.range(skip, take, callback);
                        });
                    }
                }
            },
            _findRange: function (start, end) {
                var that = this, ranges = that._ranges, range, data = [], skipIdx, takeIdx, startIndex, endIndex, rangeData, rangeEnd, processed, options = that.options, remote = options.serverSorting || options.serverPaging || options.serverFiltering || options.serverGrouping || options.serverAggregates, flatData, count, length;
                for (skipIdx = 0, length = ranges.length; skipIdx < length; skipIdx++) {
                    range = ranges[skipIdx];
                    if (start >= range.start && start <= range.end) {
                        count = 0;
                        for (takeIdx = skipIdx; takeIdx < length; takeIdx++) {
                            range = ranges[takeIdx];
                            flatData = that._flatData(range.data, true);
                            if (flatData.length && start + count >= range.start) {
                                rangeData = range.data;
                                rangeEnd = range.end;
                                if (!remote) {
                                    if (options.inPlaceSort) {
                                        processed = that._queryProcess(range.data, { filter: that.filter() });
                                    } else {
                                        var sort = normalizeGroupWithoutCompare(that.group() || []).concat(normalizeSort(that.sort() || []));
                                        processed = that._queryProcess(range.data, {
                                            sort: sort,
                                            filter: that.filter()
                                        });
                                    }
                                    flatData = rangeData = processed.data;
                                    if (processed.total !== undefined) {
                                        rangeEnd = processed.total;
                                    }
                                }
                                startIndex = 0;
                                if (start + count > range.start) {
                                    startIndex = start + count - range.start;
                                }
                                endIndex = flatData.length;
                                if (rangeEnd > end) {
                                    endIndex = endIndex - (rangeEnd - end);
                                }
                                count += endIndex - startIndex;
                                data = that._mergeGroups(data, rangeData, startIndex, endIndex);
                                if (end <= range.end && count == end - start) {
                                    return data;
                                }
                            }
                        }
                        break;
                    }
                }
                return [];
            },
            _mergeGroups: function (data, range, skip, take) {
                if (this._isServerGrouped()) {
                    var temp = range.toJSON(), prevGroup;
                    if (data.length) {
                        prevGroup = data[data.length - 1];
                    }
                    mergeGroups(prevGroup, temp, skip, take);
                    return data.concat(temp);
                }
                return data.concat(range.slice(skip, take));
            },
            _processRangeData: function (data, skip, take, pageSkip, size) {
                var that = this;
                that._pending = undefined;
                that._skip = skip > that.skip() ? math.min(size, (that.totalPages() - 1) * that.take()) : pageSkip;
                that._currentRangeStart = skip;
                that._take = take;
                var paging = that.options.serverPaging;
                var sorting = that.options.serverSorting;
                var filtering = that.options.serverFiltering;
                var aggregates = that.options.serverAggregates;
                try {
                    that.options.serverPaging = true;
                    if (!that._isServerGrouped() && !(that.group() && that.group().length)) {
                        that.options.serverSorting = true;
                    }
                    that.options.serverFiltering = true;
                    that.options.serverPaging = true;
                    that.options.serverAggregates = true;
                    if (paging) {
                        that._detachObservableParents();
                        that._data = data = that._observe(data);
                    }
                    that._process(data);
                } finally {
                    that.options.serverPaging = paging;
                    that.options.serverSorting = sorting;
                    that.options.serverFiltering = filtering;
                    that.options.serverAggregates = aggregates;
                }
            },
            skip: function () {
                var that = this;
                if (that._skip === undefined) {
                    return that._page !== undefined ? (that._page - 1) * (that.take() || 1) : undefined;
                }
                return that._skip;
            },
            currentRangeStart: function () {
                return this._currentRangeStart || 0;
            },
            take: function () {
                return this._take || this._pageSize;
            },
            _prefetchSuccessHandler: function (skip, size, callback, force) {
                var that = this;
                var timestamp = that._timeStamp();
                return function (data) {
                    var found = false, range = {
                            start: skip,
                            end: size,
                            data: [],
                            timestamp: that._timeStamp()
                        }, idx, length, temp;
                    that._dequeueRequest();
                    that.trigger(REQUESTEND, {
                        response: data,
                        type: 'read'
                    });
                    data = that.reader.parse(data);
                    temp = that._readData(data);
                    if (temp.length) {
                        for (idx = 0, length = that._ranges.length; idx < length; idx++) {
                            if (that._ranges[idx].start === skip) {
                                found = true;
                                range = that._ranges[idx];
                                range.pristineData = temp;
                                range.data = that._observe(temp);
                                range.end = range.start + that._flatData(range.data, true).length;
                                that._sortRanges();
                                break;
                            }
                        }
                        if (!found) {
                            that._addRange(that._observe(temp), skip);
                        }
                    }
                    that._total = that.reader.total(data);
                    if (force || (timestamp >= that._currentRequestTimeStamp || !that._skipRequestsInProgress)) {
                        if (callback && temp.length) {
                            callback();
                        } else {
                            that.trigger(CHANGE, {});
                        }
                    }
                };
            },
            prefetch: function (skip, take, callback) {
                var that = this, size = math.min(skip + take, that.total()), options = {
                        take: take,
                        skip: skip,
                        page: skip / take + 1,
                        pageSize: take,
                        sort: that._sort,
                        filter: that._filter,
                        group: that._group,
                        aggregate: that._aggregate
                    };
                if (!that._rangeExists(skip, size)) {
                    clearTimeout(that._timeout);
                    that._timeout = setTimeout(function () {
                        that._queueRequest(options, function () {
                            if (!that.trigger(REQUESTSTART, { type: 'read' })) {
                                that.transport.read({
                                    data: that._params(options),
                                    success: that._prefetchSuccessHandler(skip, size, callback),
                                    error: function () {
                                        var args = slice.call(arguments);
                                        that.error.apply(that, args);
                                    }
                                });
                            } else {
                                that._dequeueRequest();
                            }
                        });
                    }, 100);
                } else if (callback) {
                    callback();
                }
            },
            _multiplePrefetch: function (skip, take, callback) {
                var that = this, size = math.min(skip + take, that.total()), options = {
                        take: take,
                        skip: skip,
                        page: skip / take + 1,
                        pageSize: take,
                        sort: that._sort,
                        filter: that._filter,
                        group: that._group,
                        aggregate: that._aggregate
                    };
                if (!that._rangeExists(skip, size)) {
                    if (!that.trigger(REQUESTSTART, { type: 'read' })) {
                        that.transport.read({
                            data: that._params(options),
                            success: that._prefetchSuccessHandler(skip, size, callback, true)
                        });
                    }
                } else if (callback) {
                    callback();
                }
            },
            _rangeExists: function (start, end) {
                var that = this, ranges = that._ranges, idx, length;
                for (idx = 0, length = ranges.length; idx < length; idx++) {
                    if (ranges[idx].start <= start && ranges[idx].end >= end) {
                        return true;
                    }
                }
                return false;
            },
            _getCurrentRangeSpan: function () {
                var that = this;
                var ranges = that._ranges;
                var start = that.currentRangeStart();
                var end = start + (that.take() || 0);
                var rangeSpan = [];
                var range;
                var idx;
                var length = ranges.length;
                for (idx = 0; idx < length; idx++) {
                    range = ranges[idx];
                    if (range.start <= start && range.end >= start || range.start >= start && range.start <= end) {
                        rangeSpan.push(range);
                    }
                }
                return rangeSpan;
            },
            _removeModelFromRanges: function (model) {
                var that = this;
                var range;
                for (var idx = 0, length = this._ranges.length; idx < length; idx++) {
                    range = this._ranges[idx];
                    that._removeModelFromRange(range, model);
                }
                that._updateRangesLength();
            },
            _removeModelFromRange: function (range, model) {
                this._eachItem(range.data, function (data) {
                    for (var idx = 0; idx < data.length; idx++) {
                        var dataItem = data[idx];
                        if (dataItem.uid && dataItem.uid == model.uid) {
                            [].splice.call(data, idx, 1);
                            break;
                        }
                    }
                });
            },
            _insertModelInRange: function (index, model) {
                var that = this;
                var ranges = that._ranges || [];
                var rangesLength = ranges.length;
                var range;
                var i;
                for (i = 0; i < rangesLength; i++) {
                    range = ranges[i];
                    if (range.start <= index && range.end >= index) {
                        if (!that._getByUid(model.uid, range.data)) {
                            if (that._isServerGrouped()) {
                                range.data.splice(index, 0, that._wrapInEmptyGroup(model));
                            } else {
                                range.data.splice(index, 0, model);
                            }
                        }
                        break;
                    }
                }
                that._updateRangesLength();
            },
            _updateRangesLength: function () {
                var that = this;
                var ranges = that._ranges || [];
                var rangesLength = ranges.length;
                var mismatchFound = false;
                var mismatchLength = 0;
                var lengthDifference = 0;
                var range;
                var i;
                for (i = 0; i < rangesLength; i++) {
                    range = ranges[i];
                    lengthDifference = that._flatData(range.data, true).length - math.abs(range.end - range.start);
                    if (!mismatchFound && lengthDifference !== 0) {
                        mismatchFound = true;
                        mismatchLength = lengthDifference;
                        range.end += mismatchLength;
                        continue;
                    }
                    if (mismatchFound) {
                        range.start += mismatchLength;
                        range.end += mismatchLength;
                    }
                }
            }
        });
        var Transport = {};
        Transport.create = function (options, data, dataSource) {
            var transport, transportOptions = options.transport ? $.extend({}, options.transport) : null;
            if (transportOptions) {
                transportOptions.read = typeof transportOptions.read === STRING ? { url: transportOptions.read } : transportOptions.read;
                if (options.type === 'jsdo') {
                    transportOptions.dataSource = dataSource;
                }
                if (options.type) {
                    kendo.data.transports = kendo.data.transports || {};
                    kendo.data.schemas = kendo.data.schemas || {};
                    if (!kendo.data.transports[options.type]) {
                        kendo.logToConsole('Unknown DataSource transport type \'' + options.type + '\'.\nVerify that registration scripts for this type are included after Kendo UI on the page.', 'warn');
                    } else if (!isPlainObject(kendo.data.transports[options.type])) {
                        transport = new kendo.data.transports[options.type](extend(transportOptions, { data: data }));
                    } else {
                        transportOptions = extend(true, {}, kendo.data.transports[options.type], transportOptions);
                    }
                    options.schema = extend(true, {}, kendo.data.schemas[options.type], options.schema);
                }
                if (!transport) {
                    transport = isFunction(transportOptions.read) ? transportOptions : new RemoteTransport(transportOptions);
                }
            } else {
                transport = new LocalTransport({ data: options.data || [] });
            }
            return transport;
        };
        DataSource.create = function (options) {
            if (isArray(options) || options instanceof ObservableArray) {
                options = { data: options };
            }
            var dataSource = options || {}, data = dataSource.data, fields = dataSource.fields, table = dataSource.table, select = dataSource.select, idx, length, model = {}, field;
            if (!data && fields && !dataSource.transport) {
                if (table) {
                    data = inferTable(table, fields);
                } else if (select) {
                    data = inferSelect(select, fields);
                    if (dataSource.group === undefined && data[0] && data[0].optgroup !== undefined) {
                        dataSource.group = 'optgroup';
                    }
                }
            }
            if (kendo.data.Model && fields && (!dataSource.schema || !dataSource.schema.model)) {
                for (idx = 0, length = fields.length; idx < length; idx++) {
                    field = fields[idx];
                    if (field.type) {
                        model[field.field] = field;
                    }
                }
                if (!isEmptyObject(model)) {
                    dataSource.schema = extend(true, dataSource.schema, { model: { fields: model } });
                }
            }
            dataSource.data = data;
            select = null;
            dataSource.select = null;
            table = null;
            dataSource.table = null;
            return dataSource instanceof DataSource ? dataSource : new DataSource(dataSource);
        };
        function inferSelect(select, fields) {
            select = $(select)[0];
            var options = select.options;
            var firstField = fields[0];
            var secondField = fields[1];
            var data = [];
            var idx, length;
            var optgroup;
            var option;
            var record;
            var value;
            for (idx = 0, length = options.length; idx < length; idx++) {
                record = {};
                option = options[idx];
                optgroup = option.parentNode;
                if (optgroup === select) {
                    optgroup = null;
                }
                if (option.disabled || optgroup && optgroup.disabled) {
                    continue;
                }
                if (optgroup) {
                    record.optgroup = optgroup.label;
                }
                record[firstField.field] = option.text;
                value = option.attributes.value;
                if (value && value.specified) {
                    value = option.value;
                } else {
                    value = option.text;
                }
                record[secondField.field] = value;
                data.push(record);
            }
            return data;
        }
        function inferTable(table, fields) {
            var tbody = $(table)[0].tBodies[0], rows = tbody ? tbody.rows : [], idx, length, fieldIndex, fieldCount = fields.length, data = [], cells, record, cell, empty;
            for (idx = 0, length = rows.length; idx < length; idx++) {
                record = {};
                empty = true;
                cells = rows[idx].cells;
                for (fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
                    cell = cells[fieldIndex];
                    if (cell.nodeName.toLowerCase() !== 'th') {
                        empty = false;
                        record[fields[fieldIndex].field] = cell.innerHTML;
                    }
                }
                if (!empty) {
                    data.push(record);
                }
            }
            return data;
        }
        var Node = Model.define({
            idField: 'id',
            init: function (value) {
                var that = this, hasChildren = that.hasChildren || value && value.hasChildren, childrenField = 'items', childrenOptions = {};
                kendo.data.Model.fn.init.call(that, value);
                if (typeof that.children === STRING) {
                    childrenField = that.children;
                }
                childrenOptions = {
                    schema: {
                        data: childrenField,
                        model: {
                            hasChildren: hasChildren,
                            id: that.idField,
                            fields: that.fields
                        }
                    }
                };
                if (typeof that.children !== STRING) {
                    extend(childrenOptions, that.children);
                }
                childrenOptions.data = value;
                if (!hasChildren) {
                    hasChildren = childrenOptions.schema.data;
                }
                if (typeof hasChildren === STRING) {
                    hasChildren = kendo.getter(hasChildren);
                }
                if (isFunction(hasChildren)) {
                    var hasChildrenObject = hasChildren.call(that, that);
                    if (hasChildrenObject && hasChildrenObject.length === 0) {
                        that.hasChildren = false;
                    } else {
                        that.hasChildren = !!hasChildrenObject;
                    }
                }
                that._childrenOptions = childrenOptions;
                if (that.hasChildren) {
                    that._initChildren();
                }
                that._loaded = !!(value && value._loaded);
            },
            _initChildren: function () {
                var that = this;
                var children, transport, parameterMap;
                if (!(that.children instanceof HierarchicalDataSource)) {
                    children = that.children = new HierarchicalDataSource(that._childrenOptions);
                    transport = children.transport;
                    parameterMap = transport.parameterMap;
                    transport.parameterMap = function (data, type) {
                        data[that.idField || 'id'] = that.id;
                        if (parameterMap) {
                            data = parameterMap(data, type);
                        }
                        return data;
                    };
                    children.parent = function () {
                        return that;
                    };
                    children.bind(CHANGE, function (e) {
                        e.node = e.node || that;
                        that.trigger(CHANGE, e);
                    });
                    children.bind(ERROR, function (e) {
                        var collection = that.parent();
                        if (collection) {
                            e.node = e.node || that;
                            collection.trigger(ERROR, e);
                        }
                    });
                    that._updateChildrenField();
                }
            },
            append: function (model) {
                this._initChildren();
                this.loaded(true);
                this.children.add(model);
            },
            hasChildren: false,
            level: function () {
                var parentNode = this.parentNode(), level = 0;
                while (parentNode && parentNode.parentNode) {
                    level++;
                    parentNode = parentNode.parentNode ? parentNode.parentNode() : null;
                }
                return level;
            },
            _updateChildrenField: function () {
                var fieldName = this._childrenOptions.schema.data;
                this[fieldName || 'items'] = this.children.data();
            },
            _childrenLoaded: function () {
                this._loaded = true;
                this._updateChildrenField();
            },
            load: function () {
                var options = {};
                var method = '_query';
                var children, promise;
                if (this.hasChildren) {
                    this._initChildren();
                    children = this.children;
                    options[this.idField || 'id'] = this.id;
                    if (!this._loaded) {
                        children._data = undefined;
                        method = 'read';
                    }
                    children.one(CHANGE, proxy(this._childrenLoaded, this));
                    if (this._matchFilter) {
                        options.filter = {
                            field: '_matchFilter',
                            operator: 'eq',
                            value: true
                        };
                    }
                    promise = children[method](options);
                } else {
                    this.loaded(true);
                }
                return promise || $.Deferred().resolve().promise();
            },
            parentNode: function () {
                var array = this.parent();
                return array.parent();
            },
            loaded: function (value) {
                if (value !== undefined) {
                    this._loaded = value;
                } else {
                    return this._loaded;
                }
            },
            shouldSerialize: function (field) {
                return Model.fn.shouldSerialize.call(this, field) && field !== 'children' && field !== '_loaded' && field !== 'hasChildren' && field !== '_childrenOptions';
            }
        });
        function dataMethod(name) {
            return function () {
                var data = this._data, result = DataSource.fn[name].apply(this, slice.call(arguments));
                if (this._data != data) {
                    this._attachBubbleHandlers();
                }
                return result;
            };
        }
        var HierarchicalDataSource = DataSource.extend({
            init: function (options) {
                var node = Node.define({ children: options });
                if (options.filter && !options.serverFiltering) {
                    this._hierarchicalFilter = options.filter;
                    options.filter = null;
                }
                DataSource.fn.init.call(this, extend(true, {}, {
                    schema: {
                        modelBase: node,
                        model: node
                    }
                }, options));
                this._attachBubbleHandlers();
            },
            _attachBubbleHandlers: function () {
                var that = this;
                that._data.bind(ERROR, function (e) {
                    that.trigger(ERROR, e);
                });
            },
            read: function (data) {
                var result = DataSource.fn.read.call(this, data);
                if (this._hierarchicalFilter) {
                    if (this._data && this._data.length > 0) {
                        this.filter(this._hierarchicalFilter);
                    } else {
                        this.options.filter = this._hierarchicalFilter;
                        this._filter = normalizeFilter(this.options.filter);
                        this._hierarchicalFilter = null;
                    }
                }
                return result;
            },
            remove: function (node) {
                var parentNode = node.parentNode(), dataSource = this, result;
                if (parentNode && parentNode._initChildren) {
                    dataSource = parentNode.children;
                }
                result = DataSource.fn.remove.call(dataSource, node);
                if (parentNode && !dataSource.data().length) {
                    parentNode.hasChildren = false;
                }
                return result;
            },
            success: dataMethod('success'),
            data: dataMethod('data'),
            insert: function (index, model) {
                var parentNode = this.parent();
                if (parentNode && parentNode._initChildren) {
                    parentNode.hasChildren = true;
                    parentNode._initChildren();
                }
                return DataSource.fn.insert.call(this, index, model);
            },
            filter: function (val) {
                if (val === undefined) {
                    return this._filter;
                }
                if (!this.options.serverFiltering && this._markHierarchicalQuery(val)) {
                    val = {
                        logic: 'or',
                        filters: [
                            val,
                            {
                                field: '_matchFilter',
                                operator: 'equals',
                                value: true
                            }
                        ]
                    };
                }
                this.trigger('reset');
                this._query({
                    filter: val,
                    page: 1
                });
            },
            _markHierarchicalQuery: function (expressions) {
                var compiled;
                var predicate;
                var fields;
                var operators;
                var filter;
                var accentFoldingFiltering = this.options.accentFoldingFiltering;
                expressions = accentFoldingFiltering ? $.extend({}, normalizeFilter(expressions), { accentFoldingFiltering: accentFoldingFiltering }) : normalizeFilter(expressions);
                if (!expressions || expressions.filters.length === 0) {
                    this._updateHierarchicalFilter(function () {
                        return true;
                    });
                    return false;
                }
                compiled = Query.filterExpr(expressions);
                fields = compiled.fields;
                operators = compiled.operators;
                predicate = filter = new Function('d, __f, __o', 'return ' + compiled.expression);
                if (fields.length || operators.length) {
                    filter = function (d) {
                        return predicate(d, fields, operators);
                    };
                }
                this._updateHierarchicalFilter(filter);
                return true;
            },
            _updateHierarchicalFilter: function (filter) {
                var current;
                var data = this._data;
                var result = false;
                for (var idx = 0; idx < data.length; idx++) {
                    current = data[idx];
                    if (current.hasChildren) {
                        current._matchFilter = current.children._updateHierarchicalFilter(filter);
                        if (!current._matchFilter) {
                            current._matchFilter = filter(current);
                        }
                    } else {
                        current._matchFilter = filter(current);
                    }
                    if (current._matchFilter) {
                        result = true;
                    }
                }
                return result;
            },
            _find: function (method, value) {
                var idx, length, node, children;
                var data = this._data;
                if (!data) {
                    return;
                }
                node = DataSource.fn[method].call(this, value);
                if (node) {
                    return node;
                }
                data = this._flatData(this._data);
                for (idx = 0, length = data.length; idx < length; idx++) {
                    children = data[idx].children;
                    if (!(children instanceof HierarchicalDataSource)) {
                        continue;
                    }
                    node = children[method](value);
                    if (node) {
                        return node;
                    }
                }
            },
            get: function (id) {
                return this._find('get', id);
            },
            getByUid: function (uid) {
                return this._find('getByUid', uid);
            }
        });
        function inferList(list, fields) {
            var items = $(list).children(), idx, length, data = [], record, textField = fields[0].field, urlField = fields[1] && fields[1].field, spriteCssClassField = fields[2] && fields[2].field, imageUrlField = fields[3] && fields[3].field, item, id, textChild, className, children;
            function elements(collection, tagName) {
                return collection.filter(tagName).add(collection.find(tagName));
            }
            for (idx = 0, length = items.length; idx < length; idx++) {
                record = { _loaded: true };
                item = items.eq(idx);
                textChild = item[0].firstChild;
                children = item.children();
                list = children.filter('ul');
                children = children.filter(':not(ul)');
                id = item.attr('data-id');
                if (id) {
                    record.id = id;
                }
                if (textChild) {
                    record[textField] = textChild.nodeType == 3 ? textChild.nodeValue : children.text();
                }
                if (urlField) {
                    record[urlField] = elements(children, 'a').attr('href');
                }
                if (imageUrlField) {
                    record[imageUrlField] = elements(children, 'img').attr('src');
                }
                if (spriteCssClassField) {
                    className = elements(children, '.k-sprite').prop('className');
                    record[spriteCssClassField] = className && $.trim(className.replace('k-sprite', ''));
                }
                if (list.length) {
                    record.items = inferList(list.eq(0), fields);
                }
                if (item.attr('data-hasChildren') == 'true') {
                    record.hasChildren = true;
                }
                data.push(record);
            }
            return data;
        }
        HierarchicalDataSource.create = function (options) {
            options = options && options.push ? { data: options } : options;
            var dataSource = options || {}, data = dataSource.data, fields = dataSource.fields, list = dataSource.list;
            if (data && data._dataSource) {
                return data._dataSource;
            }
            if (!data && fields && !dataSource.transport) {
                if (list) {
                    data = inferList(list, fields);
                }
            }
            dataSource.data = data;
            return dataSource instanceof HierarchicalDataSource ? dataSource : new HierarchicalDataSource(dataSource);
        };
        var Buffer = kendo.Observable.extend({
            init: function (dataSource, viewSize, disablePrefetch) {
                kendo.Observable.fn.init.call(this);
                this._prefetching = false;
                this.dataSource = dataSource;
                this.prefetch = !disablePrefetch;
                var buffer = this;
                dataSource.bind('change', function () {
                    buffer._change();
                });
                dataSource.bind('reset', function () {
                    buffer._reset();
                });
                this._syncWithDataSource();
                this.setViewSize(viewSize);
            },
            setViewSize: function (viewSize) {
                this.viewSize = viewSize;
                this._recalculate();
            },
            at: function (index) {
                var pageSize = this.pageSize, itemPresent = true;
                if (index >= this.total()) {
                    this.trigger('endreached', { index: index });
                    return null;
                }
                if (!this.useRanges) {
                    return this.dataSource.view()[index];
                }
                if (this.useRanges) {
                    if (index < this.dataOffset || index >= this.skip + pageSize) {
                        itemPresent = this.range(Math.floor(index / pageSize) * pageSize);
                    }
                    if (index === this.prefetchThreshold) {
                        this._prefetch();
                    }
                    if (index === this.midPageThreshold) {
                        this.range(this.nextMidRange, true);
                    } else if (index === this.nextPageThreshold) {
                        this.range(this.nextFullRange);
                    } else if (index === this.pullBackThreshold) {
                        if (this.offset === this.skip) {
                            this.range(this.previousMidRange);
                        } else {
                            this.range(this.previousFullRange);
                        }
                    }
                    if (itemPresent) {
                        return this.dataSource.at(index - this.dataOffset);
                    } else {
                        this.trigger('endreached', { index: index });
                        return null;
                    }
                }
            },
            indexOf: function (item) {
                return this.dataSource.data().indexOf(item) + this.dataOffset;
            },
            total: function () {
                return parseInt(this.dataSource.total(), 10);
            },
            next: function () {
                var buffer = this, pageSize = buffer.pageSize, offset = buffer.skip - buffer.viewSize + pageSize, pageSkip = math.max(math.floor(offset / pageSize), 0) * pageSize;
                this.offset = offset;
                this.dataSource.prefetch(pageSkip, pageSize, function () {
                    buffer._goToRange(offset, true);
                });
            },
            range: function (offset, nextRange) {
                if (this.offset === offset) {
                    return true;
                }
                var buffer = this, pageSize = this.pageSize, pageSkip = math.max(math.floor(offset / pageSize), 0) * pageSize, dataSource = this.dataSource;
                if (nextRange) {
                    pageSkip += pageSize;
                }
                if (dataSource.inRange(offset, pageSize)) {
                    this.offset = offset;
                    this._recalculate();
                    this._goToRange(offset);
                    return true;
                } else if (this.prefetch) {
                    dataSource.prefetch(pageSkip, pageSize, function () {
                        buffer.offset = offset;
                        buffer._recalculate();
                        buffer._goToRange(offset, true);
                    });
                    return false;
                }
                return true;
            },
            syncDataSource: function () {
                var offset = this.offset;
                this.offset = null;
                this.range(offset);
            },
            destroy: function () {
                this.unbind();
            },
            _prefetch: function () {
                var buffer = this, pageSize = this.pageSize, prefetchOffset = this.skip + pageSize, dataSource = this.dataSource;
                if (!dataSource.inRange(prefetchOffset, pageSize) && !this._prefetching && this.prefetch) {
                    this._prefetching = true;
                    this.trigger('prefetching', {
                        skip: prefetchOffset,
                        take: pageSize
                    });
                    dataSource.prefetch(prefetchOffset, pageSize, function () {
                        buffer._prefetching = false;
                        buffer.trigger('prefetched', {
                            skip: prefetchOffset,
                            take: pageSize
                        });
                    });
                }
            },
            _goToRange: function (offset, expanding) {
                if (this.offset !== offset) {
                    return;
                }
                this.dataOffset = offset;
                this._expanding = expanding;
                this.dataSource.range(offset, this.pageSize);
                this.dataSource.enableRequestsInProgress();
            },
            _reset: function () {
                this._syncPending = true;
            },
            _change: function () {
                var dataSource = this.dataSource;
                this.length = this.useRanges ? dataSource.lastRange().end : dataSource.view().length;
                if (this._syncPending) {
                    this._syncWithDataSource();
                    this._recalculate();
                    this._syncPending = false;
                    this.trigger('reset', { offset: this.offset });
                }
                this.trigger('resize');
                if (this._expanding) {
                    this.trigger('expand');
                }
                delete this._expanding;
            },
            _syncWithDataSource: function () {
                var dataSource = this.dataSource;
                this._firstItemUid = dataSource.firstItemUid();
                this.dataOffset = this.offset = dataSource.skip() || 0;
                this.pageSize = dataSource.pageSize();
                this.useRanges = dataSource.options.serverPaging;
            },
            _recalculate: function () {
                var pageSize = this.pageSize, offset = this.offset, viewSize = this.viewSize, skip = Math.ceil(offset / pageSize) * pageSize;
                this.skip = skip;
                this.midPageThreshold = skip + pageSize - 1;
                this.nextPageThreshold = skip + viewSize - 1;
                this.prefetchThreshold = skip + Math.floor(pageSize / 3 * 2);
                this.pullBackThreshold = this.offset - 1;
                this.nextMidRange = skip + pageSize - viewSize;
                this.nextFullRange = skip;
                this.previousMidRange = offset - viewSize;
                this.previousFullRange = skip - pageSize;
            }
        });
        var BatchBuffer = kendo.Observable.extend({
            init: function (dataSource, batchSize) {
                var batchBuffer = this;
                kendo.Observable.fn.init.call(batchBuffer);
                this.dataSource = dataSource;
                this.batchSize = batchSize;
                this._total = 0;
                this.buffer = new Buffer(dataSource, batchSize * 3);
                this.buffer.bind({
                    'endreached': function (e) {
                        batchBuffer.trigger('endreached', { index: e.index });
                    },
                    'prefetching': function (e) {
                        batchBuffer.trigger('prefetching', {
                            skip: e.skip,
                            take: e.take
                        });
                    },
                    'prefetched': function (e) {
                        batchBuffer.trigger('prefetched', {
                            skip: e.skip,
                            take: e.take
                        });
                    },
                    'reset': function () {
                        batchBuffer._total = 0;
                        batchBuffer.trigger('reset');
                    },
                    'resize': function () {
                        batchBuffer._total = Math.ceil(this.length / batchBuffer.batchSize);
                        batchBuffer.trigger('resize', {
                            total: batchBuffer.total(),
                            offset: this.offset
                        });
                    }
                });
            },
            syncDataSource: function () {
                this.buffer.syncDataSource();
            },
            at: function (index) {
                var buffer = this.buffer, skip = index * this.batchSize, take = this.batchSize, view = [], item;
                if (buffer.offset > skip) {
                    buffer.at(buffer.offset - 1);
                }
                for (var i = 0; i < take; i++) {
                    item = buffer.at(skip + i);
                    if (item === null) {
                        break;
                    }
                    view.push(item);
                }
                return view;
            },
            total: function () {
                return this._total;
            },
            destroy: function () {
                this.buffer.destroy();
                this.unbind();
            }
        });
        extend(true, kendo.data, {
            readers: { json: DataReader },
            Query: Query,
            DataSource: DataSource,
            HierarchicalDataSource: HierarchicalDataSource,
            Node: Node,
            ObservableObject: ObservableObject,
            ObservableArray: ObservableArray,
            LazyObservableArray: LazyObservableArray,
            LocalTransport: LocalTransport,
            RemoteTransport: RemoteTransport,
            Cache: Cache,
            DataReader: DataReader,
            Model: Model,
            Buffer: Buffer,
            BatchBuffer: BatchBuffer
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.binder', [
        'kendo.core',
        'kendo.data'
    ], f);
}(function () {
    var __meta__ = {
        id: 'binder',
        name: 'MVVM',
        category: 'framework',
        description: 'Model View ViewModel (MVVM) is a design pattern which helps developers separate the Model (the data) from the View (the UI).',
        depends: [
            'core',
            'data'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Observable = kendo.Observable, ObservableObject = kendo.data.ObservableObject, ObservableArray = kendo.data.ObservableArray, toString = {}.toString, binders = {}, Class = kendo.Class, proxy = $.proxy, VALUE = 'value', SOURCE = 'source', EVENTS = 'events', CHECKED = 'checked', CSS = 'css', deleteExpando = true, FUNCTION = 'function', CHANGE = 'change';
        (function () {
            var a = document.createElement('a');
            try {
                delete a.test;
            } catch (e) {
                deleteExpando = false;
            }
        }());
        var Binding = Observable.extend({
            init: function (parents, path) {
                var that = this;
                Observable.fn.init.call(that);
                that.source = parents[0];
                that.parents = parents;
                that.path = path;
                that.dependencies = {};
                that.dependencies[path] = true;
                that.observable = that.source instanceof Observable;
                that._access = function (e) {
                    that.dependencies[e.field] = true;
                };
                if (that.observable) {
                    that._change = function (e) {
                        that.change(e);
                    };
                    that.source.bind(CHANGE, that._change);
                }
            },
            _parents: function () {
                var parents = this.parents;
                var value = this.get();
                if (value && typeof value.parent == 'function') {
                    var parent = value.parent();
                    if ($.inArray(parent, parents) < 0) {
                        parents = [parent].concat(parents);
                    }
                }
                return parents;
            },
            change: function (e) {
                var dependency, ch, field = e.field, that = this;
                if (that.path === 'this') {
                    that.trigger(CHANGE, e);
                } else {
                    for (dependency in that.dependencies) {
                        if (dependency.indexOf(field) === 0) {
                            ch = dependency.charAt(field.length);
                            if (!ch || ch === '.' || ch === '[') {
                                that.trigger(CHANGE, e);
                                break;
                            }
                        }
                    }
                }
            },
            start: function (source) {
                source.bind('get', this._access);
            },
            stop: function (source) {
                source.unbind('get', this._access);
            },
            get: function () {
                var that = this, source = that.source, index = 0, path = that.path, result = source;
                if (!that.observable) {
                    return result;
                }
                that.start(that.source);
                result = source.get(path);
                while (result === undefined && source) {
                    source = that.parents[++index];
                    if (source instanceof ObservableObject) {
                        result = source.get(path);
                    }
                }
                if (result === undefined) {
                    source = that.source;
                    while (result === undefined && source) {
                        source = source.parent();
                        if (source instanceof ObservableObject) {
                            result = source.get(path);
                        }
                    }
                }
                if (typeof result === 'function') {
                    index = path.lastIndexOf('.');
                    if (index > 0) {
                        source = source.get(path.substring(0, index));
                    }
                    that.start(source);
                    if (source !== that.source) {
                        result = result.call(source, that.source);
                    } else {
                        result = result.call(source);
                    }
                    that.stop(source);
                }
                if (source && source !== that.source) {
                    that.currentSource = source;
                    source.unbind(CHANGE, that._change).bind(CHANGE, that._change);
                }
                that.stop(that.source);
                return result;
            },
            set: function (value) {
                var source = this.currentSource || this.source;
                var field = kendo.getter(this.path)(source);
                if (typeof field === 'function') {
                    if (source !== this.source) {
                        field.call(source, this.source, value);
                    } else {
                        field.call(source, value);
                    }
                } else {
                    source.set(this.path, value);
                }
            },
            destroy: function () {
                if (this.observable) {
                    this.source.unbind(CHANGE, this._change);
                    if (this.currentSource) {
                        this.currentSource.unbind(CHANGE, this._change);
                    }
                }
                this.unbind();
            }
        });
        var EventBinding = Binding.extend({
            get: function () {
                var source = this.source, path = this.path, index = 0, handler;
                handler = source.get(path);
                while (!handler && source) {
                    source = this.parents[++index];
                    if (source instanceof ObservableObject) {
                        handler = source.get(path);
                    }
                }
                return proxy(handler, source);
            }
        });
        var TemplateBinding = Binding.extend({
            init: function (source, path, template) {
                var that = this;
                Binding.fn.init.call(that, source, path);
                that.template = template;
            },
            render: function (value) {
                var html;
                this.start(this.source);
                html = kendo.render(this.template, value);
                this.stop(this.source);
                return html;
            }
        });
        var Binder = Class.extend({
            init: function (element, bindings, options) {
                this.element = element;
                this.bindings = bindings;
                this.options = options;
            },
            bind: function (binding, attribute) {
                var that = this;
                binding = attribute ? binding[attribute] : binding;
                binding.bind(CHANGE, function (e) {
                    that.refresh(attribute || e);
                });
                that.refresh(attribute);
            },
            destroy: function () {
            }
        });
        var TypedBinder = Binder.extend({
            dataType: function () {
                var dataType = this.element.getAttribute('data-type') || this.element.type || 'text';
                return dataType.toLowerCase();
            },
            parsedValue: function () {
                return this._parseValue(this.element.value, this.dataType());
            },
            _parseValue: function (value, dataType) {
                if (dataType == 'date') {
                    value = kendo.parseDate(value, 'yyyy-MM-dd');
                } else if (dataType == 'datetime-local') {
                    value = kendo.parseDate(value, [
                        'yyyy-MM-ddTHH:mm:ss',
                        'yyyy-MM-ddTHH:mm'
                    ]);
                } else if (dataType == 'number') {
                    value = kendo.parseFloat(value);
                } else if (dataType == 'boolean') {
                    value = value.toLowerCase();
                    if (kendo.parseFloat(value) !== null) {
                        value = Boolean(kendo.parseFloat(value));
                    } else {
                        value = value.toLowerCase() === 'true';
                    }
                }
                return value;
            }
        });
        binders.attr = Binder.extend({
            refresh: function (key) {
                this.element.setAttribute(key, this.bindings.attr[key].get());
            }
        });
        binders.css = Binder.extend({
            init: function (element, bindings, options) {
                Binder.fn.init.call(this, element, bindings, options);
                this.classes = {};
            },
            refresh: function (className) {
                var element = $(this.element), binding = this.bindings.css[className], hasClass = this.classes[className] = binding.get();
                if (hasClass) {
                    element.addClass(className);
                } else {
                    element.removeClass(className);
                }
            }
        });
        binders.style = Binder.extend({
            refresh: function (key) {
                this.element.style[key] = this.bindings.style[key].get() || '';
            }
        });
        binders.enabled = Binder.extend({
            refresh: function () {
                if (this.bindings.enabled.get()) {
                    this.element.removeAttribute('disabled');
                } else {
                    this.element.setAttribute('disabled', 'disabled');
                }
            }
        });
        binders.readonly = Binder.extend({
            refresh: function () {
                if (this.bindings.readonly.get()) {
                    this.element.setAttribute('readonly', 'readonly');
                } else {
                    this.element.removeAttribute('readonly');
                }
            }
        });
        binders.disabled = Binder.extend({
            refresh: function () {
                if (this.bindings.disabled.get()) {
                    this.element.setAttribute('disabled', 'disabled');
                } else {
                    this.element.removeAttribute('disabled');
                }
            }
        });
        binders.events = Binder.extend({
            init: function (element, bindings, options) {
                Binder.fn.init.call(this, element, bindings, options);
                this.handlers = {};
            },
            refresh: function (key) {
                var element = $(this.element), binding = this.bindings.events[key], handler = this.handlers[key];
                if (handler) {
                    element.off(key, handler);
                }
                handler = this.handlers[key] = binding.get();
                element.on(key, binding.source, handler);
            },
            destroy: function () {
                var element = $(this.element), handler;
                for (handler in this.handlers) {
                    element.off(handler, this.handlers[handler]);
                }
            }
        });
        binders.text = Binder.extend({
            refresh: function () {
                var text = this.bindings.text.get();
                var dataFormat = this.element.getAttribute('data-format') || '';
                if (text == null) {
                    text = '';
                }
                $(this.element).text(kendo.toString(text, dataFormat));
            }
        });
        binders.visible = Binder.extend({
            refresh: function () {
                if (this.bindings.visible.get()) {
                    this.element.style.display = '';
                } else {
                    this.element.style.display = 'none';
                }
            }
        });
        binders.invisible = Binder.extend({
            refresh: function () {
                if (!this.bindings.invisible.get()) {
                    this.element.style.display = '';
                } else {
                    this.element.style.display = 'none';
                }
            }
        });
        binders.html = Binder.extend({
            refresh: function () {
                this.element.innerHTML = this.bindings.html.get();
            }
        });
        binders.value = TypedBinder.extend({
            init: function (element, bindings, options) {
                TypedBinder.fn.init.call(this, element, bindings, options);
                this._change = proxy(this.change, this);
                this.eventName = options.valueUpdate || CHANGE;
                $(this.element).on(this.eventName, this._change);
                this._initChange = false;
            },
            change: function () {
                this._initChange = this.eventName != CHANGE;
                this.bindings[VALUE].set(this.parsedValue());
                this._initChange = false;
            },
            refresh: function () {
                if (!this._initChange) {
                    var value = this.bindings[VALUE].get();
                    if (value == null) {
                        value = '';
                    }
                    var type = this.dataType();
                    if (type == 'date') {
                        value = kendo.toString(value, 'yyyy-MM-dd');
                    } else if (type == 'datetime-local') {
                        value = kendo.toString(value, 'yyyy-MM-ddTHH:mm:ss');
                    }
                    this.element.value = value;
                }
                this._initChange = false;
            },
            destroy: function () {
                $(this.element).off(this.eventName, this._change);
            }
        });
        binders.source = Binder.extend({
            init: function (element, bindings, options) {
                Binder.fn.init.call(this, element, bindings, options);
                var source = this.bindings.source.get();
                if (source instanceof kendo.data.DataSource && options.autoBind !== false) {
                    source.fetch();
                }
            },
            refresh: function (e) {
                var that = this, source = that.bindings.source.get();
                if (source instanceof ObservableArray || source instanceof kendo.data.DataSource) {
                    e = e || {};
                    if (e.action == 'add') {
                        that.add(e.index, e.items);
                    } else if (e.action == 'remove') {
                        that.remove(e.index, e.items);
                    } else if (e.action != 'itemchange') {
                        that.render();
                    }
                } else {
                    that.render();
                }
            },
            container: function () {
                var element = this.element;
                if (element.nodeName.toLowerCase() == 'table') {
                    if (!element.tBodies[0]) {
                        element.appendChild(document.createElement('tbody'));
                    }
                    element = element.tBodies[0];
                }
                return element;
            },
            template: function () {
                var options = this.options, template = options.template, nodeName = this.container().nodeName.toLowerCase();
                if (!template) {
                    if (nodeName == 'select') {
                        if (options.valueField || options.textField) {
                            template = kendo.format('<option value="#:{0}#">#:{1}#</option>', options.valueField || options.textField, options.textField || options.valueField);
                        } else {
                            template = '<option>#:data#</option>';
                        }
                    } else if (nodeName == 'tbody') {
                        template = '<tr><td>#:data#</td></tr>';
                    } else if (nodeName == 'ul' || nodeName == 'ol') {
                        template = '<li>#:data#</li>';
                    } else {
                        template = '#:data#';
                    }
                    template = kendo.template(template);
                }
                return template;
            },
            add: function (index, items) {
                var element = this.container(), parents, idx, length, child, clone = element.cloneNode(false), reference = element.children[index];
                $(clone).html(kendo.render(this.template(), items));
                if (clone.children.length) {
                    parents = this.bindings.source._parents();
                    for (idx = 0, length = items.length; idx < length; idx++) {
                        child = clone.children[0];
                        element.insertBefore(child, reference || null);
                        bindElement(child, items[idx], this.options.roles, [items[idx]].concat(parents));
                    }
                }
            },
            remove: function (index, items) {
                var idx, element = this.container();
                for (idx = 0; idx < items.length; idx++) {
                    var child = element.children[index];
                    unbindElementTree(child, true);
                    if (child.parentNode == element) {
                        element.removeChild(child);
                    }
                }
            },
            render: function () {
                var source = this.bindings.source.get(), parents, idx, length, element = this.container(), template = this.template();
                if (source == null) {
                    return;
                }
                if (source instanceof kendo.data.DataSource) {
                    source = source.view();
                }
                if (!(source instanceof ObservableArray) && toString.call(source) !== '[object Array]') {
                    source = [source];
                }
                if (this.bindings.template) {
                    unbindElementChildren(element, true);
                    $(element).html(this.bindings.template.render(source));
                    if (element.children.length) {
                        parents = this.bindings.source._parents();
                        for (idx = 0, length = source.length; idx < length; idx++) {
                            bindElement(element.children[idx], source[idx], this.options.roles, [source[idx]].concat(parents));
                        }
                    }
                } else {
                    $(element).html(kendo.render(template, source));
                }
            }
        });
        binders.input = {
            checked: TypedBinder.extend({
                init: function (element, bindings, options) {
                    TypedBinder.fn.init.call(this, element, bindings, options);
                    this._change = proxy(this.change, this);
                    $(this.element).change(this._change);
                },
                change: function () {
                    var element = this.element;
                    var value = this.value();
                    if (element.type == 'radio') {
                        value = this.parsedValue();
                        this.bindings[CHECKED].set(value);
                    } else if (element.type == 'checkbox') {
                        var source = this.bindings[CHECKED].get();
                        var index;
                        if (source instanceof ObservableArray) {
                            value = this.parsedValue();
                            if (value instanceof Date) {
                                for (var i = 0; i < source.length; i++) {
                                    if (source[i] instanceof Date && +source[i] === +value) {
                                        index = i;
                                        break;
                                    }
                                }
                            } else {
                                index = source.indexOf(value);
                            }
                            if (index > -1) {
                                source.splice(index, 1);
                            } else {
                                source.push(value);
                            }
                        } else {
                            this.bindings[CHECKED].set(value);
                        }
                    }
                },
                refresh: function () {
                    var value = this.bindings[CHECKED].get(), source = value, type = this.dataType(), element = this.element;
                    if (element.type == 'checkbox') {
                        if (source instanceof ObservableArray) {
                            var index = -1;
                            value = this.parsedValue();
                            if (value instanceof Date) {
                                for (var i = 0; i < source.length; i++) {
                                    if (source[i] instanceof Date && +source[i] === +value) {
                                        index = i;
                                        break;
                                    }
                                }
                            } else {
                                index = source.indexOf(value);
                            }
                            element.checked = index >= 0;
                        } else {
                            element.checked = source;
                        }
                    } else if (element.type == 'radio') {
                        if (type == 'date') {
                            value = kendo.toString(value, 'yyyy-MM-dd');
                        } else if (type == 'datetime-local') {
                            value = kendo.toString(value, 'yyyy-MM-ddTHH:mm:ss');
                        }
                        if (value !== null && typeof value !== 'undefined' && element.value === value.toString()) {
                            element.checked = true;
                        } else {
                            element.checked = false;
                        }
                    }
                },
                value: function () {
                    var element = this.element, value = element.value;
                    if (element.type == 'checkbox') {
                        value = element.checked;
                    }
                    return value;
                },
                destroy: function () {
                    $(this.element).off(CHANGE, this._change);
                }
            })
        };
        binders.select = {
            source: binders.source.extend({
                refresh: function (e) {
                    var that = this, source = that.bindings.source.get();
                    if (source instanceof ObservableArray || source instanceof kendo.data.DataSource) {
                        e = e || {};
                        if (e.action == 'add') {
                            that.add(e.index, e.items);
                        } else if (e.action == 'remove') {
                            that.remove(e.index, e.items);
                        } else if (e.action == 'itemchange' || e.action === undefined) {
                            that.render();
                            if (that.bindings.value) {
                                if (that.bindings.value) {
                                    var val = retrievePrimitiveValues(that.bindings.value.get(), $(that.element).data('valueField'));
                                    if (val === null) {
                                        that.element.selectedIndex = -1;
                                    } else {
                                        that.element.value = val;
                                    }
                                }
                            }
                        }
                    } else {
                        that.render();
                    }
                }
            }),
            value: TypedBinder.extend({
                init: function (target, bindings, options) {
                    TypedBinder.fn.init.call(this, target, bindings, options);
                    this._change = proxy(this.change, this);
                    $(this.element).change(this._change);
                },
                parsedValue: function () {
                    var dataType = this.dataType();
                    var values = [];
                    var value, option, idx, length;
                    for (idx = 0, length = this.element.options.length; idx < length; idx++) {
                        option = this.element.options[idx];
                        if (option.selected) {
                            value = option.attributes.value;
                            if (value && value.specified) {
                                value = option.value;
                            } else {
                                value = option.text;
                            }
                            values.push(this._parseValue(value, dataType));
                        }
                    }
                    return values;
                },
                change: function () {
                    var values = [], element = this.element, source, field = this.options.valueField || this.options.textField, valuePrimitive = this.options.valuePrimitive, option, valueIndex, value, idx, length;
                    for (idx = 0, length = element.options.length; idx < length; idx++) {
                        option = element.options[idx];
                        if (option.selected) {
                            value = option.attributes.value;
                            if (value && value.specified) {
                                value = option.value;
                            } else {
                                value = option.text;
                            }
                            if (field) {
                                values.push(value);
                            } else {
                                values.push(this._parseValue(value, this.dataType()));
                            }
                        }
                    }
                    if (field) {
                        source = this.bindings.source.get();
                        if (source instanceof kendo.data.DataSource) {
                            source = source.view();
                        }
                        for (valueIndex = 0; valueIndex < values.length; valueIndex++) {
                            for (idx = 0, length = source.length; idx < length; idx++) {
                                var sourceValue = source[idx].get(field);
                                var match = String(sourceValue) === values[valueIndex];
                                if (match) {
                                    values[valueIndex] = source[idx];
                                    break;
                                }
                            }
                        }
                    }
                    value = this.bindings[VALUE].get();
                    if (value instanceof ObservableArray) {
                        value.splice.apply(value, [
                            0,
                            value.length
                        ].concat(values));
                    } else if (!valuePrimitive && (value instanceof ObservableObject || value === null || value === undefined || !field)) {
                        this.bindings[VALUE].set(values[0]);
                    } else {
                        this.bindings[VALUE].set(values[0].get(field));
                    }
                },
                refresh: function () {
                    var optionIndex, element = this.element, options = element.options, value = this.bindings[VALUE].get(), values = value, field = this.options.valueField || this.options.textField, found = false, type = this.dataType(), optionValue;
                    if (!(values instanceof ObservableArray)) {
                        values = new ObservableArray([value]);
                    }
                    element.selectedIndex = -1;
                    for (var valueIndex = 0; valueIndex < values.length; valueIndex++) {
                        value = values[valueIndex];
                        if (field && value instanceof ObservableObject) {
                            value = value.get(field);
                        }
                        if (type == 'date') {
                            value = kendo.toString(values[valueIndex], 'yyyy-MM-dd');
                        } else if (type == 'datetime-local') {
                            value = kendo.toString(values[valueIndex], 'yyyy-MM-ddTHH:mm:ss');
                        }
                        for (optionIndex = 0; optionIndex < options.length; optionIndex++) {
                            optionValue = options[optionIndex].value;
                            if (optionValue === '' && value !== '') {
                                optionValue = options[optionIndex].text;
                            }
                            if (value != null && optionValue == value.toString()) {
                                options[optionIndex].selected = true;
                                found = true;
                            }
                        }
                    }
                },
                destroy: function () {
                    $(this.element).off(CHANGE, this._change);
                }
            })
        };
        function dataSourceBinding(bindingName, fieldName, setter) {
            return Binder.extend({
                init: function (widget, bindings, options) {
                    var that = this;
                    Binder.fn.init.call(that, widget.element[0], bindings, options);
                    that.widget = widget;
                    that._dataBinding = proxy(that.dataBinding, that);
                    that._dataBound = proxy(that.dataBound, that);
                    that._itemChange = proxy(that.itemChange, that);
                },
                itemChange: function (e) {
                    bindElement(e.item[0], e.data, this._ns(e.ns), [e.data].concat(this.bindings[bindingName]._parents()));
                },
                dataBinding: function (e) {
                    var idx, length, widget = this.widget, items = e.removedItems || widget.items();
                    for (idx = 0, length = items.length; idx < length; idx++) {
                        unbindElementTree(items[idx], false);
                    }
                },
                _ns: function (ns) {
                    ns = ns || kendo.ui;
                    var all = [
                        kendo.ui,
                        kendo.dataviz.ui,
                        kendo.mobile.ui
                    ];
                    all.splice($.inArray(ns, all), 1);
                    all.unshift(ns);
                    return kendo.rolesFromNamespaces(all);
                },
                dataBound: function (e) {
                    var idx, length, widget = this.widget, items = e.addedItems || widget.items(), dataSource = widget[fieldName], view, parents, hds = kendo.data.HierarchicalDataSource;
                    if (hds && dataSource instanceof hds) {
                        return;
                    }
                    if (items.length) {
                        view = e.addedDataItems || dataSource.flatView();
                        parents = this.bindings[bindingName]._parents();
                        for (idx = 0, length = view.length; idx < length; idx++) {
                            if (items[idx]) {
                                bindElement(items[idx], view[idx], this._ns(e.ns), [view[idx]].concat(parents));
                            }
                        }
                    }
                },
                refresh: function (e) {
                    var that = this, source, widget = that.widget, select, multiselect, dropdowntree;
                    e = e || {};
                    if (!e.action) {
                        that.destroy();
                        widget.bind('dataBinding', that._dataBinding);
                        widget.bind('dataBound', that._dataBound);
                        widget.bind('itemChange', that._itemChange);
                        source = that.bindings[bindingName].get();
                        if (widget[fieldName] instanceof kendo.data.DataSource && widget[fieldName] != source) {
                            if (source instanceof kendo.data.DataSource) {
                                widget[setter](source);
                            } else if (source && source._dataSource) {
                                widget[setter](source._dataSource);
                            } else {
                                select = kendo.ui.Select && widget instanceof kendo.ui.Select;
                                multiselect = kendo.ui.MultiSelect && widget instanceof kendo.ui.MultiSelect;
                                dropdowntree = kendo.ui.DropDownTree && widget instanceof kendo.ui.DropDownTree;
                                if (!dropdowntree) {
                                    widget[fieldName].data(source);
                                } else {
                                    widget.treeview[fieldName].data(source);
                                }
                                if (that.bindings.value && (select || multiselect)) {
                                    widget.value(retrievePrimitiveValues(that.bindings.value.get(), widget.options.dataValueField));
                                }
                            }
                        }
                    }
                },
                destroy: function () {
                    var widget = this.widget;
                    widget.unbind('dataBinding', this._dataBinding);
                    widget.unbind('dataBound', this._dataBound);
                    widget.unbind('itemChange', this._itemChange);
                }
            });
        }
        binders.widget = {
            events: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                    this.handlers = {};
                },
                refresh: function (key) {
                    var binding = this.bindings.events[key], handler = this.handlers[key];
                    if (handler) {
                        this.widget.unbind(key, handler);
                    }
                    handler = binding.get();
                    this.handlers[key] = function (e) {
                        e.data = binding.source;
                        handler(e);
                        if (e.data === binding.source) {
                            delete e.data;
                        }
                    };
                    this.widget.bind(key, this.handlers[key]);
                },
                destroy: function () {
                    var handler;
                    for (handler in this.handlers) {
                        this.widget.unbind(handler, this.handlers[handler]);
                    }
                }
            }),
            checked: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                    this._change = proxy(this.change, this);
                    this.widget.bind(CHANGE, this._change);
                },
                change: function () {
                    this.bindings[CHECKED].set(this.value());
                },
                refresh: function () {
                    this.widget.check(this.bindings[CHECKED].get() === true);
                },
                value: function () {
                    var element = this.element, value = element.value;
                    if (value == 'on' || value == 'off' || this.element.type == 'checkbox') {
                        value = element.checked;
                    }
                    return value;
                },
                destroy: function () {
                    this.widget.unbind(CHANGE, this._change);
                }
            }),
            start: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this._change = proxy(this.change, this);
                    this.widget = widget;
                    this.widget.bind(CHANGE, this._change);
                },
                change: function () {
                    this.bindings.start.set(this.widget.range().start);
                },
                refresh: function () {
                    var that = this;
                    var start = this.bindings.start.get();
                    var end = that.widget._range ? that.widget._range.end : null;
                    this.widget.range({
                        start: start,
                        end: end
                    });
                },
                destroy: function () {
                    this.widget.unbind(CHANGE, this._change);
                }
            }),
            end: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this._change = proxy(this.change, this);
                    this.widget = widget;
                    this.widget.bind(CHANGE, this._change);
                },
                change: function () {
                    this.bindings.end.set(this.widget.range().end);
                },
                refresh: function () {
                    var that = this;
                    var end = this.bindings.end.get();
                    var start = that.widget._range ? that.widget._range.start : null;
                    this.widget.range({
                        start: start,
                        end: end
                    });
                },
                destroy: function () {
                    this.widget.unbind(CHANGE, this._change);
                }
            }),
            visible: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                },
                refresh: function () {
                    var visible = this.bindings.visible.get();
                    this.widget.wrapper[0].style.display = visible ? '' : 'none';
                }
            }),
            invisible: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                },
                refresh: function () {
                    var invisible = this.bindings.invisible.get();
                    this.widget.wrapper[0].style.display = invisible ? 'none' : '';
                }
            }),
            enabled: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                },
                refresh: function () {
                    if (this.widget.enable) {
                        this.widget.enable(this.bindings.enabled.get());
                    }
                }
            }),
            disabled: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                },
                refresh: function () {
                    if (this.widget.enable) {
                        this.widget.enable(!this.bindings.disabled.get());
                    }
                }
            }),
            source: dataSourceBinding('source', 'dataSource', 'setDataSource'),
            value: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                    this._change = $.proxy(this.change, this);
                    this.widget.first(CHANGE, this._change);
                    var value = this.bindings.value.get();
                    this._valueIsObservableObject = !options.valuePrimitive && (value == null || value instanceof ObservableObject);
                    this._valueIsObservableArray = value instanceof ObservableArray;
                    this._initChange = false;
                },
                _source: function () {
                    var source;
                    if (this.widget.dataItem) {
                        source = this.widget.dataItem();
                        if (source && source instanceof ObservableObject) {
                            return [source];
                        }
                    }
                    if (this.bindings.source) {
                        source = this.bindings.source.get();
                    }
                    if (!source || source instanceof kendo.data.DataSource) {
                        source = this.widget.dataSource.flatView();
                    }
                    return source;
                },
                change: function () {
                    var value = this.widget.value(), field = this.options.dataValueField || this.options.dataTextField, isArray = toString.call(value) === '[object Array]', isObservableObject = this._valueIsObservableObject, valueIndex, valueLength, values = [], sourceItem, sourceValue, idx, length, source;
                    this._initChange = true;
                    if (field) {
                        if (value === '' && (isObservableObject || this.options.valuePrimitive)) {
                            value = null;
                        } else {
                            source = this._source();
                            if (isArray) {
                                valueLength = value.length;
                                values = value.slice(0);
                            }
                            for (idx = 0, length = source.length; idx < length; idx++) {
                                sourceItem = source[idx];
                                sourceValue = sourceItem.get(field);
                                if (isArray) {
                                    for (valueIndex = 0; valueIndex < valueLength; valueIndex++) {
                                        if (sourceValue == values[valueIndex]) {
                                            values[valueIndex] = sourceItem;
                                            break;
                                        }
                                    }
                                } else if (sourceValue == value) {
                                    value = isObservableObject ? sourceItem : sourceValue;
                                    break;
                                }
                            }
                            if (values[0]) {
                                if (this._valueIsObservableArray) {
                                    value = values;
                                } else if (isObservableObject || !field) {
                                    value = values[0];
                                } else {
                                    value = values[0].get(field);
                                }
                            }
                        }
                    }
                    this.bindings.value.set(value);
                    this._initChange = false;
                },
                refresh: function () {
                    if (!this._initChange) {
                        var widget = this.widget;
                        var options = widget.options;
                        var textField = options.dataTextField;
                        var valueField = options.dataValueField || textField;
                        var value = this.bindings.value.get();
                        var text = options.text || '';
                        var idx = 0, length;
                        var values = [];
                        if (value === undefined) {
                            value = null;
                        }
                        if (valueField) {
                            if (value instanceof ObservableArray) {
                                for (length = value.length; idx < length; idx++) {
                                    values[idx] = value[idx].get(valueField);
                                }
                                value = values;
                            } else if (value instanceof ObservableObject) {
                                text = value.get(textField);
                                value = value.get(valueField);
                            }
                        }
                        if (options.autoBind === false && !options.cascadeFrom && widget.listView && !widget.listView.bound()) {
                            if (textField === valueField && !text) {
                                text = value;
                            }
                            if (!text && (value || value === 0) && options.valuePrimitive) {
                                widget.value(value);
                            } else {
                                widget._preselect(value, text);
                            }
                        } else {
                            widget.value(value);
                        }
                    }
                    this._initChange = false;
                },
                destroy: function () {
                    this.widget.unbind(CHANGE, this._change);
                }
            }),
            dropdowntree: {
                value: Binder.extend({
                    init: function (widget, bindings, options) {
                        Binder.fn.init.call(this, widget.element[0], bindings, options);
                        this.widget = widget;
                        this._change = $.proxy(this.change, this);
                        this.widget.first(CHANGE, this._change);
                        this._initChange = false;
                    },
                    change: function () {
                        var that = this, oldValues = that.bindings[VALUE].get(), valuePrimitive = that.options.valuePrimitive, selectedNode = that.widget.treeview.select(), nonPrimitiveValues = that.widget._isMultipleSelection() ? that.widget._getAllChecked() : that.widget.treeview.dataItem(selectedNode) || that.widget.value(), newValues = valuePrimitive || that.widget.options.autoBind === false ? that.widget.value() : nonPrimitiveValues;
                        var field = this.options.dataValueField || this.options.dataTextField;
                        newValues = newValues.slice ? newValues.slice(0) : newValues;
                        that._initChange = true;
                        if (oldValues instanceof ObservableArray) {
                            var remove = [];
                            var newLength = newValues.length;
                            var i = 0, j = 0;
                            var old = oldValues[i];
                            var same = false;
                            var removeIndex;
                            var newValue;
                            var found;
                            while (old !== undefined) {
                                found = false;
                                for (j = 0; j < newLength; j++) {
                                    if (valuePrimitive) {
                                        same = newValues[j] == old;
                                    } else {
                                        newValue = newValues[j];
                                        newValue = newValue.get ? newValue.get(field) : newValue;
                                        same = newValue == (old.get ? old.get(field) : old);
                                    }
                                    if (same) {
                                        newValues.splice(j, 1);
                                        newLength -= 1;
                                        found = true;
                                        break;
                                    }
                                }
                                if (!found) {
                                    remove.push(old);
                                    arraySplice(oldValues, i, 1);
                                    removeIndex = i;
                                } else {
                                    i += 1;
                                }
                                old = oldValues[i];
                            }
                            arraySplice(oldValues, oldValues.length, 0, newValues);
                            if (remove.length) {
                                oldValues.trigger('change', {
                                    action: 'remove',
                                    items: remove,
                                    index: removeIndex
                                });
                            }
                            if (newValues.length) {
                                oldValues.trigger('change', {
                                    action: 'add',
                                    items: newValues,
                                    index: oldValues.length - 1
                                });
                            }
                        } else {
                            that.bindings[VALUE].set(newValues);
                        }
                        that._initChange = false;
                    },
                    refresh: function () {
                        if (!this._initChange) {
                            var options = this.options, widget = this.widget, field = options.dataValueField || options.dataTextField, value = this.bindings.value.get(), data = value, idx = 0, length, values = [], selectedValue;
                            if (field) {
                                if (value instanceof ObservableArray) {
                                    for (length = value.length; idx < length; idx++) {
                                        selectedValue = value[idx];
                                        values[idx] = selectedValue.get ? selectedValue.get(field) : selectedValue;
                                    }
                                    value = values;
                                } else if (value instanceof ObservableObject) {
                                    value = value.get(field);
                                }
                            }
                            if (options.autoBind === false && options.valuePrimitive !== true) {
                                widget._preselect(data, value);
                            } else {
                                widget.value(value);
                            }
                        }
                    },
                    destroy: function () {
                        this.widget.unbind(CHANGE, this._change);
                    }
                })
            },
            gantt: { dependencies: dataSourceBinding('dependencies', 'dependencies', 'setDependenciesDataSource') },
            multiselect: {
                value: Binder.extend({
                    init: function (widget, bindings, options) {
                        Binder.fn.init.call(this, widget.element[0], bindings, options);
                        this.widget = widget;
                        this._change = $.proxy(this.change, this);
                        this.widget.first(CHANGE, this._change);
                        this._initChange = false;
                    },
                    change: function () {
                        var that = this, oldValues = that.bindings[VALUE].get(), valuePrimitive = that.options.valuePrimitive, newValues = valuePrimitive ? that.widget.value() : that.widget.dataItems();
                        var field = this.options.dataValueField || this.options.dataTextField;
                        newValues = newValues.slice(0);
                        that._initChange = true;
                        if (oldValues instanceof ObservableArray) {
                            var remove = [];
                            var newLength = newValues.length;
                            var i = 0, j = 0;
                            var old = oldValues[i];
                            var same = false;
                            var removeIndex;
                            var newValue;
                            var found;
                            while (old !== undefined) {
                                found = false;
                                for (j = 0; j < newLength; j++) {
                                    if (valuePrimitive) {
                                        same = newValues[j] == old;
                                    } else {
                                        newValue = newValues[j];
                                        newValue = newValue.get ? newValue.get(field) : newValue;
                                        same = newValue == (old.get ? old.get(field) : old);
                                    }
                                    if (same) {
                                        newValues.splice(j, 1);
                                        newLength -= 1;
                                        found = true;
                                        break;
                                    }
                                }
                                if (!found) {
                                    remove.push(old);
                                    arraySplice(oldValues, i, 1);
                                    removeIndex = i;
                                } else {
                                    i += 1;
                                }
                                old = oldValues[i];
                            }
                            arraySplice(oldValues, oldValues.length, 0, newValues);
                            if (remove.length) {
                                oldValues.trigger('change', {
                                    action: 'remove',
                                    items: remove,
                                    index: removeIndex
                                });
                            }
                            if (newValues.length) {
                                oldValues.trigger('change', {
                                    action: 'add',
                                    items: newValues,
                                    index: oldValues.length - 1
                                });
                            }
                        } else {
                            that.bindings[VALUE].set(newValues);
                        }
                        that._initChange = false;
                    },
                    refresh: function () {
                        if (!this._initChange) {
                            var options = this.options, widget = this.widget, field = options.dataValueField || options.dataTextField, value = this.bindings.value.get(), data = value, idx = 0, length, values = [], selectedValue;
                            if (value === undefined) {
                                value = null;
                            }
                            if (field) {
                                if (value instanceof ObservableArray) {
                                    for (length = value.length; idx < length; idx++) {
                                        selectedValue = value[idx];
                                        values[idx] = selectedValue.get ? selectedValue.get(field) : selectedValue;
                                    }
                                    value = values;
                                } else if (value instanceof ObservableObject) {
                                    value = value.get(field);
                                }
                            }
                            if (options.autoBind === false && options.valuePrimitive !== true && !widget._isBound()) {
                                widget._preselect(data, value);
                            } else {
                                widget.value(value);
                            }
                        }
                    },
                    destroy: function () {
                        this.widget.unbind(CHANGE, this._change);
                    }
                })
            },
            scheduler: {
                source: dataSourceBinding('source', 'dataSource', 'setDataSource').extend({
                    dataBound: function (e) {
                        var idx;
                        var length;
                        var widget = this.widget;
                        var elements = e.addedItems || widget.items();
                        var data, parents;
                        if (elements.length) {
                            data = e.addedDataItems || widget.dataItems();
                            parents = this.bindings.source._parents();
                            for (idx = 0, length = data.length; idx < length; idx++) {
                                bindElement(elements[idx], data[idx], this._ns(e.ns), [data[idx]].concat(parents));
                            }
                        }
                    }
                })
            },
            grid: {
                source: dataSourceBinding('source', 'dataSource', 'setDataSource').extend({
                    dataBound: function (e) {
                        var idx, length, widget = this.widget, elements = e.addedItems || widget.items(), parents, data;
                        if (elements.length) {
                            data = e.addedDataItems || widget.dataItems();
                            parents = this.bindings.source._parents();
                            for (idx = 0, length = data.length; idx < length; idx++) {
                                bindElement(elements[idx], data[idx], this._ns(e.ns), [data[idx]].concat(parents));
                            }
                        }
                    }
                })
            }
        };
        var arraySplice = function (arr, idx, remove, add) {
            add = add || [];
            remove = remove || 0;
            var addLength = add.length;
            var oldLength = arr.length;
            var shifted = [].slice.call(arr, idx + remove);
            var shiftedLength = shifted.length;
            var index;
            if (addLength) {
                addLength = idx + addLength;
                index = 0;
                for (; idx < addLength; idx++) {
                    arr[idx] = add[index];
                    index++;
                }
                arr.length = addLength;
            } else if (remove) {
                arr.length = idx;
                remove += idx;
                while (idx < remove) {
                    delete arr[--remove];
                }
            }
            if (shiftedLength) {
                shiftedLength = idx + shiftedLength;
                index = 0;
                for (; idx < shiftedLength; idx++) {
                    arr[idx] = shifted[index];
                    index++;
                }
                arr.length = shiftedLength;
            }
            idx = arr.length;
            while (idx < oldLength) {
                delete arr[idx];
                idx++;
            }
        };
        var BindingTarget = Class.extend({
            init: function (target, options) {
                this.target = target;
                this.options = options;
                this.toDestroy = [];
            },
            bind: function (bindings) {
                var key, hasValue, hasSource, hasEvents, hasChecked, hasCss, widgetBinding = this instanceof WidgetBindingTarget, specificBinders = this.binders();
                for (key in bindings) {
                    if (key == VALUE) {
                        hasValue = true;
                    } else if (key == SOURCE) {
                        hasSource = true;
                    } else if (key == EVENTS && !widgetBinding) {
                        hasEvents = true;
                    } else if (key == CHECKED) {
                        hasChecked = true;
                    } else if (key == CSS) {
                        hasCss = true;
                    } else {
                        this.applyBinding(key, bindings, specificBinders);
                    }
                }
                if (hasSource) {
                    this.applyBinding(SOURCE, bindings, specificBinders);
                }
                if (hasValue) {
                    this.applyBinding(VALUE, bindings, specificBinders);
                }
                if (hasChecked) {
                    this.applyBinding(CHECKED, bindings, specificBinders);
                }
                if (hasEvents && !widgetBinding) {
                    this.applyBinding(EVENTS, bindings, specificBinders);
                }
                if (hasCss && !widgetBinding) {
                    this.applyBinding(CSS, bindings, specificBinders);
                }
            },
            binders: function () {
                return binders[this.target.nodeName.toLowerCase()] || {};
            },
            applyBinding: function (name, bindings, specificBinders) {
                var binder = specificBinders[name] || binders[name], toDestroy = this.toDestroy, attribute, binding = bindings[name];
                if (binder) {
                    binder = new binder(this.target, bindings, this.options);
                    toDestroy.push(binder);
                    if (binding instanceof Binding) {
                        binder.bind(binding);
                        toDestroy.push(binding);
                    } else {
                        for (attribute in binding) {
                            binder.bind(binding, attribute);
                            toDestroy.push(binding[attribute]);
                        }
                    }
                } else if (name !== 'template') {
                    throw new Error('The ' + name + ' binding is not supported by the ' + this.target.nodeName.toLowerCase() + ' element');
                }
            },
            destroy: function () {
                var idx, length, toDestroy = this.toDestroy;
                for (idx = 0, length = toDestroy.length; idx < length; idx++) {
                    toDestroy[idx].destroy();
                }
            }
        });
        var WidgetBindingTarget = BindingTarget.extend({
            binders: function () {
                return binders.widget[this.target.options.name.toLowerCase()] || {};
            },
            applyBinding: function (name, bindings, specificBinders) {
                var binder = specificBinders[name] || binders.widget[name], toDestroy = this.toDestroy, attribute, binding = bindings[name];
                if (binder) {
                    binder = new binder(this.target, bindings, this.target.options);
                    toDestroy.push(binder);
                    if (binding instanceof Binding) {
                        binder.bind(binding);
                        toDestroy.push(binding);
                    } else {
                        for (attribute in binding) {
                            binder.bind(binding, attribute);
                            toDestroy.push(binding[attribute]);
                        }
                    }
                } else {
                    throw new Error('The ' + name + ' binding is not supported by the ' + this.target.options.name + ' widget');
                }
            }
        });
        function bindingTargetForRole(element, roles) {
            var widget = kendo.initWidget(element, {}, roles);
            if (widget) {
                return new WidgetBindingTarget(widget);
            }
        }
        var keyValueRegExp = /[A-Za-z0-9_\-]+:(\{([^}]*)\}|[^,}]+)/g, whiteSpaceRegExp = /\s/g;
        function parseBindings(bind) {
            var result = {}, idx, length, token, colonIndex, key, value, tokens;
            tokens = bind.match(keyValueRegExp);
            for (idx = 0, length = tokens.length; idx < length; idx++) {
                token = tokens[idx];
                colonIndex = token.indexOf(':');
                key = token.substring(0, colonIndex);
                value = token.substring(colonIndex + 1);
                if (value.charAt(0) == '{') {
                    value = parseBindings(value);
                }
                result[key] = value;
            }
            return result;
        }
        function createBindings(bindings, source, type) {
            var binding, result = {};
            for (binding in bindings) {
                result[binding] = new type(source, bindings[binding]);
            }
            return result;
        }
        function bindElement(element, source, roles, parents) {
            if (!element || element.getAttribute('data-' + kendo.ns + 'stop')) {
                return;
            }
            var role = element.getAttribute('data-' + kendo.ns + 'role'), idx, bind = element.getAttribute('data-' + kendo.ns + 'bind'), childrenCopy = [], deep = true, bindings, options = {}, target;
            parents = parents || [source];
            if (role || bind) {
                unbindElement(element, false);
            }
            if (role) {
                target = bindingTargetForRole(element, roles);
            }
            if (bind) {
                bind = parseBindings(bind.replace(whiteSpaceRegExp, ''));
                if (!target) {
                    options = kendo.parseOptions(element, {
                        textField: '',
                        valueField: '',
                        template: '',
                        valueUpdate: CHANGE,
                        valuePrimitive: false,
                        autoBind: true
                    }, source);
                    options.roles = roles;
                    target = new BindingTarget(element, options);
                }
                target.source = source;
                bindings = createBindings(bind, parents, Binding);
                if (options.template) {
                    bindings.template = new TemplateBinding(parents, '', options.template);
                }
                if (bindings.click) {
                    bind.events = bind.events || {};
                    bind.events.click = bind.click;
                    bindings.click.destroy();
                    delete bindings.click;
                }
                if (bindings.source) {
                    deep = false;
                }
                if (bind.attr) {
                    bindings.attr = createBindings(bind.attr, parents, Binding);
                }
                if (bind.style) {
                    bindings.style = createBindings(bind.style, parents, Binding);
                }
                if (bind.events) {
                    bindings.events = createBindings(bind.events, parents, EventBinding);
                }
                if (bind.css) {
                    bindings.css = createBindings(bind.css, parents, Binding);
                }
                target.bind(bindings);
            }
            if (target) {
                element.kendoBindingTarget = target;
            }
            var children = element.children;
            if (deep && children) {
                for (idx = 0; idx < children.length; idx++) {
                    childrenCopy[idx] = children[idx];
                }
                for (idx = 0; idx < childrenCopy.length; idx++) {
                    bindElement(childrenCopy[idx], source, roles, parents);
                }
            }
        }
        function bind(dom, object) {
            var idx, length, node, roles = kendo.rolesFromNamespaces([].slice.call(arguments, 2));
            object = kendo.observable(object);
            dom = $(dom);
            for (idx = 0, length = dom.length; idx < length; idx++) {
                node = dom[idx];
                if (node.nodeType === 1) {
                    bindElement(node, object, roles);
                }
            }
        }
        function unbindElement(element, destroyWidget) {
            var bindingTarget = element.kendoBindingTarget;
            if (bindingTarget) {
                bindingTarget.destroy();
                if (deleteExpando) {
                    delete element.kendoBindingTarget;
                } else if (element.removeAttribute) {
                    element.removeAttribute('kendoBindingTarget');
                } else {
                    element.kendoBindingTarget = null;
                }
            }
            if (destroyWidget) {
                var widget = kendo.widgetInstance($(element));
                if (widget && typeof widget.destroy === FUNCTION) {
                    widget.destroy();
                }
            }
        }
        function unbindElementTree(element, destroyWidgets) {
            unbindElement(element, destroyWidgets);
            unbindElementChildren(element, destroyWidgets);
        }
        function unbindElementChildren(element, destroyWidgets) {
            var children = element.children;
            if (children) {
                for (var idx = 0, length = children.length; idx < length; idx++) {
                    unbindElementTree(children[idx], destroyWidgets);
                }
            }
        }
        function unbind(dom) {
            var idx, length;
            dom = $(dom);
            for (idx = 0, length = dom.length; idx < length; idx++) {
                unbindElementTree(dom[idx], false);
            }
        }
        function notify(widget, namespace) {
            var element = widget.element, bindingTarget = element[0].kendoBindingTarget;
            if (bindingTarget) {
                bind(element, bindingTarget.source, namespace);
            }
        }
        function retrievePrimitiveValues(value, valueField) {
            var values = [];
            var idx = 0;
            var length;
            var item;
            if (!valueField) {
                return value;
            }
            if (value instanceof ObservableArray) {
                for (length = value.length; idx < length; idx++) {
                    item = value[idx];
                    values[idx] = item.get ? item.get(valueField) : item[valueField];
                }
                value = values;
            } else if (value instanceof ObservableObject) {
                value = value.get(valueField);
            }
            return value;
        }
        kendo.unbind = unbind;
        kendo.bind = bind;
        kendo.data.binders = binders;
        kendo.data.Binder = Binder;
        kendo.notify = notify;
        kendo.observable = function (object) {
            if (!(object instanceof ObservableObject)) {
                object = new ObservableObject(object);
            }
            return object;
        };
        kendo.observableHierarchy = function (array) {
            var dataSource = kendo.data.HierarchicalDataSource.create(array);
            function recursiveRead(data) {
                var i, children;
                for (i = 0; i < data.length; i++) {
                    data[i]._initChildren();
                    children = data[i].children;
                    children.fetch();
                    data[i].items = children.data();
                    recursiveRead(data[i].items);
                }
            }
            dataSource.fetch();
            recursiveRead(dataSource.data());
            dataSource._data._dataSource = dataSource;
            return dataSource._data;
        };
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.fx', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'fx',
        name: 'Effects',
        category: 'framework',
        description: 'Required for animation effects in all Kendo UI widgets.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, fx = kendo.effects, each = $.each, extend = $.extend, proxy = $.proxy, support = kendo.support, browser = support.browser, transforms = support.transforms, transitions = support.transitions, scaleProperties = {
                scale: 0,
                scalex: 0,
                scaley: 0,
                scale3d: 0
            }, translateProperties = {
                translate: 0,
                translatex: 0,
                translatey: 0,
                translate3d: 0
            }, hasZoom = typeof document.documentElement.style.zoom !== 'undefined' && !transforms, matrix3dRegExp = /matrix3?d?\s*\(.*,\s*([\d\.\-]+)\w*?,\s*([\d\.\-]+)\w*?,\s*([\d\.\-]+)\w*?,\s*([\d\.\-]+)\w*?/i, cssParamsRegExp = /^(-?[\d\.\-]+)?[\w\s]*,?\s*(-?[\d\.\-]+)?[\w\s]*/i, translateXRegExp = /translatex?$/i, oldEffectsRegExp = /(zoom|fade|expand)(\w+)/, singleEffectRegExp = /(zoom|fade|expand)/, unitRegExp = /[xy]$/i, transformProps = [
                'perspective',
                'rotate',
                'rotatex',
                'rotatey',
                'rotatez',
                'rotate3d',
                'scale',
                'scalex',
                'scaley',
                'scalez',
                'scale3d',
                'skew',
                'skewx',
                'skewy',
                'translate',
                'translatex',
                'translatey',
                'translatez',
                'translate3d',
                'matrix',
                'matrix3d'
            ], transform2d = [
                'rotate',
                'scale',
                'scalex',
                'scaley',
                'skew',
                'skewx',
                'skewy',
                'translate',
                'translatex',
                'translatey',
                'matrix'
            ], transform2units = {
                'rotate': 'deg',
                scale: '',
                skew: 'px',
                translate: 'px'
            }, cssPrefix = transforms.css, round = Math.round, BLANK = '', PX = 'px', NONE = 'none', AUTO = 'auto', WIDTH = 'width', HEIGHT = 'height', HIDDEN = 'hidden', ORIGIN = 'origin', ABORT_ID = 'abortId', OVERFLOW = 'overflow', TRANSLATE = 'translate', POSITION = 'position', COMPLETE_CALLBACK = 'completeCallback', TRANSITION = cssPrefix + 'transition', TRANSFORM = cssPrefix + 'transform', BACKFACE = cssPrefix + 'backface-visibility', PERSPECTIVE = cssPrefix + 'perspective', DEFAULT_PERSPECTIVE = '1500px', TRANSFORM_PERSPECTIVE = 'perspective(' + DEFAULT_PERSPECTIVE + ')', directions = {
                left: {
                    reverse: 'right',
                    property: 'left',
                    transition: 'translatex',
                    vertical: false,
                    modifier: -1
                },
                right: {
                    reverse: 'left',
                    property: 'left',
                    transition: 'translatex',
                    vertical: false,
                    modifier: 1
                },
                down: {
                    reverse: 'up',
                    property: 'top',
                    transition: 'translatey',
                    vertical: true,
                    modifier: 1
                },
                up: {
                    reverse: 'down',
                    property: 'top',
                    transition: 'translatey',
                    vertical: true,
                    modifier: -1
                },
                top: { reverse: 'bottom' },
                bottom: { reverse: 'top' },
                'in': {
                    reverse: 'out',
                    modifier: -1
                },
                out: {
                    reverse: 'in',
                    modifier: 1
                },
                vertical: { reverse: 'vertical' },
                horizontal: { reverse: 'horizontal' }
            };
        kendo.directions = directions;
        extend($.fn, {
            kendoStop: function (clearQueue, gotoEnd) {
                if (transitions) {
                    return fx.stopQueue(this, clearQueue || false, gotoEnd || false);
                } else {
                    return this.stop(clearQueue, gotoEnd);
                }
            }
        });
        if (transforms && !transitions) {
            each(transform2d, function (idx, value) {
                $.fn[value] = function (val) {
                    if (typeof val == 'undefined') {
                        return animationProperty(this, value);
                    } else {
                        var that = $(this)[0], transformValue = value + '(' + val + transform2units[value.replace(unitRegExp, '')] + ')';
                        if (that.style.cssText.indexOf(TRANSFORM) == -1) {
                            $(this).css(TRANSFORM, transformValue);
                        } else {
                            that.style.cssText = that.style.cssText.replace(new RegExp(value + '\\(.*?\\)', 'i'), transformValue);
                        }
                    }
                    return this;
                };
                $.fx.step[value] = function (fx) {
                    $(fx.elem)[value](fx.now);
                };
            });
            var curProxy = $.fx.prototype.cur;
            $.fx.prototype.cur = function () {
                if (transform2d.indexOf(this.prop) != -1) {
                    return parseFloat($(this.elem)[this.prop]());
                }
                return curProxy.apply(this, arguments);
            };
        }
        kendo.toggleClass = function (element, classes, options, add) {
            if (classes) {
                classes = classes.split(' ');
                if (transitions) {
                    options = extend({
                        exclusive: 'all',
                        duration: 400,
                        ease: 'ease-out'
                    }, options);
                    element.css(TRANSITION, options.exclusive + ' ' + options.duration + 'ms ' + options.ease);
                    setTimeout(function () {
                        element.css(TRANSITION, '').css(HEIGHT);
                    }, options.duration);
                }
                each(classes, function (idx, value) {
                    element.toggleClass(value, add);
                });
            }
            return element;
        };
        kendo.parseEffects = function (input, mirror) {
            var effects = {};
            if (typeof input === 'string') {
                each(input.split(' '), function (idx, value) {
                    var redirectedEffect = !singleEffectRegExp.test(value), resolved = value.replace(oldEffectsRegExp, function (match, $1, $2) {
                            return $1 + ':' + $2.toLowerCase();
                        }), effect = resolved.split(':'), direction = effect[1], effectBody = {};
                    if (effect.length > 1) {
                        effectBody.direction = mirror && redirectedEffect ? directions[direction].reverse : direction;
                    }
                    effects[effect[0]] = effectBody;
                });
            } else {
                each(input, function (idx) {
                    var direction = this.direction;
                    if (direction && mirror && !singleEffectRegExp.test(idx)) {
                        this.direction = directions[direction].reverse;
                    }
                    effects[idx] = this;
                });
            }
            return effects;
        };
        function parseInteger(value) {
            return parseInt(value, 10);
        }
        function parseCSS(element, property) {
            return parseInteger(element.css(property));
        }
        function keys(obj) {
            var acc = [];
            for (var propertyName in obj) {
                acc.push(propertyName);
            }
            return acc;
        }
        function strip3DTransforms(properties) {
            for (var key in properties) {
                if (transformProps.indexOf(key) != -1 && transform2d.indexOf(key) == -1) {
                    delete properties[key];
                }
            }
            return properties;
        }
        function normalizeCSS(element, properties) {
            var transformation = [], cssValues = {}, lowerKey, key, value, isTransformed;
            for (key in properties) {
                lowerKey = key.toLowerCase();
                isTransformed = transforms && transformProps.indexOf(lowerKey) != -1;
                if (!support.hasHW3D && isTransformed && transform2d.indexOf(lowerKey) == -1) {
                    delete properties[key];
                } else {
                    value = properties[key];
                    if (isTransformed) {
                        transformation.push(key + '(' + value + ')');
                    } else {
                        cssValues[key] = value;
                    }
                }
            }
            if (transformation.length) {
                cssValues[TRANSFORM] = transformation.join(' ');
            }
            return cssValues;
        }
        if (transitions) {
            extend(fx, {
                transition: function (element, properties, options) {
                    var css, delay = 0, oldKeys = element.data('keys') || [], timeoutID;
                    options = extend({
                        duration: 200,
                        ease: 'ease-out',
                        complete: null,
                        exclusive: 'all'
                    }, options);
                    var stopTransitionCalled = false;
                    var stopTransition = function () {
                        if (!stopTransitionCalled) {
                            stopTransitionCalled = true;
                            if (timeoutID) {
                                clearTimeout(timeoutID);
                                timeoutID = null;
                            }
                            element.removeData(ABORT_ID).dequeue().css(TRANSITION, '').css(TRANSITION);
                            options.complete.call(element);
                        }
                    };
                    options.duration = $.fx ? $.fx.speeds[options.duration] || options.duration : options.duration;
                    css = normalizeCSS(element, properties);
                    $.merge(oldKeys, keys(css));
                    if ($.hasOwnProperty('uniqueSort')) {
                        element.data('keys', $.uniqueSort(oldKeys)).height();
                    } else {
                        element.data('keys', $.unique(oldKeys)).height();
                    }
                    element.css(TRANSITION, options.exclusive + ' ' + options.duration + 'ms ' + options.ease).css(TRANSITION);
                    element.css(css).css(TRANSFORM);
                    if (transitions.event) {
                        element.one(transitions.event, stopTransition);
                        if (options.duration !== 0) {
                            delay = 500;
                        }
                    }
                    timeoutID = setTimeout(stopTransition, options.duration + delay);
                    element.data(ABORT_ID, timeoutID);
                    element.data(COMPLETE_CALLBACK, stopTransition);
                },
                stopQueue: function (element, clearQueue, gotoEnd) {
                    var cssValues, taskKeys = element.data('keys'), retainPosition = !gotoEnd && taskKeys, completeCallback = element.data(COMPLETE_CALLBACK);
                    if (retainPosition) {
                        cssValues = kendo.getComputedStyles(element[0], taskKeys);
                    }
                    if (completeCallback) {
                        completeCallback();
                    }
                    if (retainPosition) {
                        element.css(cssValues);
                    }
                    return element.removeData('keys').stop(clearQueue);
                }
            });
        }
        function animationProperty(element, property) {
            if (transforms) {
                var transform = element.css(TRANSFORM);
                if (transform == NONE) {
                    return property == 'scale' ? 1 : 0;
                }
                var match = transform.match(new RegExp(property + '\\s*\\(([\\d\\w\\.]+)')), computed = 0;
                if (match) {
                    computed = parseInteger(match[1]);
                } else {
                    match = transform.match(matrix3dRegExp) || [
                        0,
                        0,
                        0,
                        0,
                        0
                    ];
                    property = property.toLowerCase();
                    if (translateXRegExp.test(property)) {
                        computed = parseFloat(match[3] / match[2]);
                    } else if (property == 'translatey') {
                        computed = parseFloat(match[4] / match[2]);
                    } else if (property == 'scale') {
                        computed = parseFloat(match[2]);
                    } else if (property == 'rotate') {
                        computed = parseFloat(Math.atan2(match[2], match[1]));
                    }
                }
                return computed;
            } else {
                return parseFloat(element.css(property));
            }
        }
        var EffectSet = kendo.Class.extend({
            init: function (element, options) {
                var that = this;
                that.element = element;
                that.effects = [];
                that.options = options;
                that.restore = [];
            },
            run: function (effects) {
                var that = this, effect, idx, jdx, length = effects.length, element = that.element, options = that.options, deferred = $.Deferred(), start = {}, end = {}, target, children, childrenLength;
                that.effects = effects;
                deferred.done($.proxy(that, 'complete'));
                element.data('animating', true);
                for (idx = 0; idx < length; idx++) {
                    effect = effects[idx];
                    effect.setReverse(options.reverse);
                    effect.setOptions(options);
                    that.addRestoreProperties(effect.restore);
                    effect.prepare(start, end);
                    children = effect.children();
                    for (jdx = 0, childrenLength = children.length; jdx < childrenLength; jdx++) {
                        children[jdx].duration(options.duration).run();
                    }
                }
                for (var effectName in options.effects) {
                    extend(end, options.effects[effectName].properties);
                }
                if (!element.is(':visible')) {
                    extend(start, { display: element.data('olddisplay') || 'block' });
                }
                if (transforms && !options.reset) {
                    target = element.data('targetTransform');
                    if (target) {
                        start = extend(target, start);
                    }
                }
                start = normalizeCSS(element, start);
                if (transforms && !transitions) {
                    start = strip3DTransforms(start);
                }
                element.css(start).css(TRANSFORM);
                for (idx = 0; idx < length; idx++) {
                    effects[idx].setup();
                }
                if (options.init) {
                    options.init();
                }
                element.data('targetTransform', end);
                fx.animate(element, end, extend({}, options, { complete: deferred.resolve }));
                return deferred.promise();
            },
            stop: function () {
                $(this.element).kendoStop(true, true);
            },
            addRestoreProperties: function (restore) {
                var element = this.element, value, i = 0, length = restore.length;
                for (; i < length; i++) {
                    value = restore[i];
                    this.restore.push(value);
                    if (!element.data(value)) {
                        element.data(value, element.css(value));
                    }
                }
            },
            restoreCallback: function () {
                var element = this.element;
                for (var i = 0, length = this.restore.length; i < length; i++) {
                    var value = this.restore[i];
                    element.css(value, element.data(value));
                }
            },
            complete: function () {
                var that = this, idx = 0, element = that.element, options = that.options, effects = that.effects, length = effects.length;
                element.removeData('animating').dequeue();
                if (options.hide) {
                    element.data('olddisplay', element.css('display')).hide();
                }
                this.restoreCallback();
                if (hasZoom && !transforms) {
                    setTimeout($.proxy(this, 'restoreCallback'), 0);
                }
                for (; idx < length; idx++) {
                    effects[idx].teardown();
                }
                if (options.completeCallback) {
                    options.completeCallback(element);
                }
            }
        });
        fx.promise = function (element, options) {
            var effects = [], effectClass, effectSet = new EffectSet(element, options), parsedEffects = kendo.parseEffects(options.effects), effect;
            options.effects = parsedEffects;
            for (var effectName in parsedEffects) {
                effectClass = fx[capitalize(effectName)];
                if (effectClass) {
                    effect = new effectClass(element, parsedEffects[effectName].direction);
                    effects.push(effect);
                }
            }
            if (effects[0]) {
                effectSet.run(effects);
            } else {
                if (!element.is(':visible')) {
                    element.css({ display: element.data('olddisplay') || 'block' }).css('display');
                }
                if (options.init) {
                    options.init();
                }
                element.dequeue();
                effectSet.complete();
            }
        };
        extend(fx, {
            animate: function (elements, properties, options) {
                var useTransition = options.transition !== false;
                delete options.transition;
                if (transitions && 'transition' in fx && useTransition) {
                    fx.transition(elements, properties, options);
                } else {
                    if (transforms) {
                        elements.animate(strip3DTransforms(properties), {
                            queue: false,
                            show: false,
                            hide: false,
                            duration: options.duration,
                            complete: options.complete
                        });
                    } else {
                        elements.each(function () {
                            var element = $(this), multiple = {};
                            each(transformProps, function (idx, value) {
                                var params, currentValue = properties ? properties[value] + ' ' : null;
                                if (currentValue) {
                                    var single = properties;
                                    if (value in scaleProperties && properties[value] !== undefined) {
                                        params = currentValue.match(cssParamsRegExp);
                                        if (transforms) {
                                            extend(single, { scale: +params[0] });
                                        }
                                    } else {
                                        if (value in translateProperties && properties[value] !== undefined) {
                                            var position = element.css(POSITION), isFixed = position == 'absolute' || position == 'fixed';
                                            if (!element.data(TRANSLATE)) {
                                                if (isFixed) {
                                                    element.data(TRANSLATE, {
                                                        top: parseCSS(element, 'top') || 0,
                                                        left: parseCSS(element, 'left') || 0,
                                                        bottom: parseCSS(element, 'bottom'),
                                                        right: parseCSS(element, 'right')
                                                    });
                                                } else {
                                                    element.data(TRANSLATE, {
                                                        top: parseCSS(element, 'marginTop') || 0,
                                                        left: parseCSS(element, 'marginLeft') || 0
                                                    });
                                                }
                                            }
                                            var originalPosition = element.data(TRANSLATE);
                                            params = currentValue.match(cssParamsRegExp);
                                            if (params) {
                                                var dX = value == TRANSLATE + 'y' ? +null : +params[1], dY = value == TRANSLATE + 'y' ? +params[1] : +params[2];
                                                if (isFixed) {
                                                    if (!isNaN(originalPosition.right)) {
                                                        if (!isNaN(dX)) {
                                                            extend(single, { right: originalPosition.right - dX });
                                                        }
                                                    } else {
                                                        if (!isNaN(dX)) {
                                                            extend(single, { left: originalPosition.left + dX });
                                                        }
                                                    }
                                                    if (!isNaN(originalPosition.bottom)) {
                                                        if (!isNaN(dY)) {
                                                            extend(single, { bottom: originalPosition.bottom - dY });
                                                        }
                                                    } else {
                                                        if (!isNaN(dY)) {
                                                            extend(single, { top: originalPosition.top + dY });
                                                        }
                                                    }
                                                } else {
                                                    if (!isNaN(dX)) {
                                                        extend(single, { marginLeft: originalPosition.left + dX });
                                                    }
                                                    if (!isNaN(dY)) {
                                                        extend(single, { marginTop: originalPosition.top + dY });
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    if (!transforms && value != 'scale' && value in single) {
                                        delete single[value];
                                    }
                                    if (single) {
                                        extend(multiple, single);
                                    }
                                }
                            });
                            if (browser.msie) {
                                delete multiple.scale;
                            }
                            element.animate(multiple, {
                                queue: false,
                                show: false,
                                hide: false,
                                duration: options.duration,
                                complete: options.complete
                            });
                        });
                    }
                }
            }
        });
        fx.animatedPromise = fx.promise;
        var Effect = kendo.Class.extend({
            init: function (element, direction) {
                var that = this;
                that.element = element;
                that._direction = direction;
                that.options = {};
                that._additionalEffects = [];
                if (!that.restore) {
                    that.restore = [];
                }
            },
            reverse: function () {
                this._reverse = true;
                return this.run();
            },
            play: function () {
                this._reverse = false;
                return this.run();
            },
            add: function (additional) {
                this._additionalEffects.push(additional);
                return this;
            },
            direction: function (value) {
                this._direction = value;
                return this;
            },
            duration: function (duration) {
                this._duration = duration;
                return this;
            },
            compositeRun: function () {
                var that = this, effectSet = new EffectSet(that.element, {
                        reverse: that._reverse,
                        duration: that._duration
                    }), effects = that._additionalEffects.concat([that]);
                return effectSet.run(effects);
            },
            run: function () {
                if (this._additionalEffects && this._additionalEffects[0]) {
                    return this.compositeRun();
                }
                var that = this, element = that.element, idx = 0, restore = that.restore, length = restore.length, value, deferred = $.Deferred(), start = {}, end = {}, target, children = that.children(), childrenLength = children.length;
                deferred.done($.proxy(that, '_complete'));
                element.data('animating', true);
                for (idx = 0; idx < length; idx++) {
                    value = restore[idx];
                    if (!element.data(value)) {
                        element.data(value, element.css(value));
                    }
                }
                for (idx = 0; idx < childrenLength; idx++) {
                    children[idx].duration(that._duration).run();
                }
                that.prepare(start, end);
                if (!element.is(':visible')) {
                    extend(start, { display: element.data('olddisplay') || 'block' });
                }
                if (transforms) {
                    target = element.data('targetTransform');
                    if (target) {
                        start = extend(target, start);
                    }
                }
                start = normalizeCSS(element, start);
                if (transforms && !transitions) {
                    start = strip3DTransforms(start);
                }
                element.css(start).css(TRANSFORM);
                that.setup();
                element.data('targetTransform', end);
                fx.animate(element, end, {
                    duration: that._duration,
                    complete: deferred.resolve
                });
                return deferred.promise();
            },
            stop: function () {
                var idx = 0, children = this.children(), childrenLength = children.length;
                for (idx = 0; idx < childrenLength; idx++) {
                    children[idx].stop();
                }
                $(this.element).kendoStop(true, true);
                return this;
            },
            restoreCallback: function () {
                var element = this.element;
                for (var i = 0, length = this.restore.length; i < length; i++) {
                    var value = this.restore[i];
                    element.css(value, element.data(value));
                }
            },
            _complete: function () {
                var that = this, element = that.element;
                element.removeData('animating').dequeue();
                that.restoreCallback();
                if (that.shouldHide()) {
                    element.data('olddisplay', element.css('display')).hide();
                }
                if (hasZoom && !transforms) {
                    setTimeout($.proxy(that, 'restoreCallback'), 0);
                }
                that.teardown();
            },
            setOptions: function (options) {
                extend(true, this.options, options);
            },
            children: function () {
                return [];
            },
            shouldHide: $.noop,
            setup: $.noop,
            prepare: $.noop,
            teardown: $.noop,
            directions: [],
            setReverse: function (reverse) {
                this._reverse = reverse;
                return this;
            }
        });
        function capitalize(word) {
            return word.charAt(0).toUpperCase() + word.substring(1);
        }
        function createEffect(name, definition) {
            var effectClass = Effect.extend(definition), directions = effectClass.prototype.directions;
            fx[capitalize(name)] = effectClass;
            fx.Element.prototype[name] = function (direction, opt1, opt2, opt3) {
                return new effectClass(this.element, direction, opt1, opt2, opt3);
            };
            each(directions, function (idx, theDirection) {
                fx.Element.prototype[name + capitalize(theDirection)] = function (opt1, opt2, opt3) {
                    return new effectClass(this.element, theDirection, opt1, opt2, opt3);
                };
            });
        }
        var FOUR_DIRECTIONS = [
                'left',
                'right',
                'up',
                'down'
            ], IN_OUT = [
                'in',
                'out'
            ];
        createEffect('slideIn', {
            directions: FOUR_DIRECTIONS,
            divisor: function (value) {
                this.options.divisor = value;
                return this;
            },
            prepare: function (start, end) {
                var that = this, tmp, element = that.element, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, direction = directions[that._direction], offset = -direction.modifier * (direction.vertical ? outerHeight(element) : outerWidth(element)), startValue = offset / (that.options && that.options.divisor || 1) + PX, endValue = '0px';
                if (that._reverse) {
                    tmp = start;
                    start = end;
                    end = tmp;
                }
                if (transforms) {
                    start[direction.transition] = startValue;
                    end[direction.transition] = endValue;
                } else {
                    start[direction.property] = startValue;
                    end[direction.property] = endValue;
                }
            }
        });
        createEffect('tile', {
            directions: FOUR_DIRECTIONS,
            init: function (element, direction, previous) {
                Effect.prototype.init.call(this, element, direction);
                this.options = { previous: previous };
            },
            previousDivisor: function (value) {
                this.options.previousDivisor = value;
                return this;
            },
            children: function () {
                var that = this, reverse = that._reverse, previous = that.options.previous, divisor = that.options.previousDivisor || 1, dir = that._direction;
                var children = [kendo.fx(that.element).slideIn(dir).setReverse(reverse)];
                if (previous) {
                    children.push(kendo.fx(previous).slideIn(directions[dir].reverse).divisor(divisor).setReverse(!reverse));
                }
                return children;
            }
        });
        function createToggleEffect(name, property, defaultStart, defaultEnd) {
            createEffect(name, {
                directions: IN_OUT,
                startValue: function (value) {
                    this._startValue = value;
                    return this;
                },
                endValue: function (value) {
                    this._endValue = value;
                    return this;
                },
                shouldHide: function () {
                    return this._shouldHide;
                },
                prepare: function (start, end) {
                    var that = this, startValue, endValue, out = this._direction === 'out', startDataValue = that.element.data(property), startDataValueIsSet = !(isNaN(startDataValue) || startDataValue == defaultStart);
                    if (startDataValueIsSet) {
                        startValue = startDataValue;
                    } else if (typeof this._startValue !== 'undefined') {
                        startValue = this._startValue;
                    } else {
                        startValue = out ? defaultStart : defaultEnd;
                    }
                    if (typeof this._endValue !== 'undefined') {
                        endValue = this._endValue;
                    } else {
                        endValue = out ? defaultEnd : defaultStart;
                    }
                    if (this._reverse) {
                        start[property] = endValue;
                        end[property] = startValue;
                    } else {
                        start[property] = startValue;
                        end[property] = endValue;
                    }
                    that._shouldHide = end[property] === defaultEnd;
                }
            });
        }
        createToggleEffect('fade', 'opacity', 1, 0);
        createToggleEffect('zoom', 'scale', 1, 0.01);
        createEffect('slideMargin', {
            prepare: function (start, end) {
                var that = this, element = that.element, options = that.options, origin = element.data(ORIGIN), offset = options.offset, margin, reverse = that._reverse;
                if (!reverse && origin === null) {
                    element.data(ORIGIN, parseFloat(element.css('margin-' + options.axis)));
                }
                margin = element.data(ORIGIN) || 0;
                end['margin-' + options.axis] = !reverse ? margin + offset : margin;
            }
        });
        createEffect('slideTo', {
            prepare: function (start, end) {
                var that = this, element = that.element, options = that.options, offset = options.offset.split(','), reverse = that._reverse;
                if (transforms) {
                    end.translatex = !reverse ? offset[0] : 0;
                    end.translatey = !reverse ? offset[1] : 0;
                } else {
                    end.left = !reverse ? offset[0] : 0;
                    end.top = !reverse ? offset[1] : 0;
                }
                element.css('left');
            }
        });
        createEffect('expand', {
            directions: [
                'horizontal',
                'vertical'
            ],
            restore: [OVERFLOW],
            prepare: function (start, end) {
                var that = this, element = that.element, options = that.options, reverse = that._reverse, property = that._direction === 'vertical' ? HEIGHT : WIDTH, setLength = element[0].style[property], oldLength = element.data(property), length = parseFloat(oldLength || setLength), realLength = round(element.css(property, AUTO)[property]());
                start.overflow = HIDDEN;
                length = options && options.reset ? realLength || length : length || realLength;
                end[property] = (reverse ? 0 : length) + PX;
                start[property] = (reverse ? length : 0) + PX;
                if (oldLength === undefined) {
                    element.data(property, setLength);
                }
            },
            shouldHide: function () {
                return this._reverse;
            },
            teardown: function () {
                var that = this, element = that.element, property = that._direction === 'vertical' ? HEIGHT : WIDTH, length = element.data(property);
                if (length == AUTO || length === BLANK) {
                    setTimeout(function () {
                        element.css(property, AUTO).css(property);
                    }, 0);
                }
            }
        });
        var TRANSFER_START_STATE = {
            position: 'absolute',
            marginLeft: 0,
            marginTop: 0,
            scale: 1
        };
        createEffect('transfer', {
            init: function (element, target) {
                this.element = element;
                this.options = { target: target };
                this.restore = [];
            },
            setup: function () {
                this.element.appendTo(document.body);
            },
            prepare: function (start, end) {
                var that = this, element = that.element, outerBox = fx.box(element), innerBox = fx.box(that.options.target), currentScale = animationProperty(element, 'scale'), scale = fx.fillScale(innerBox, outerBox), transformOrigin = fx.transformOrigin(innerBox, outerBox);
                extend(start, TRANSFER_START_STATE);
                end.scale = 1;
                element.css(TRANSFORM, 'scale(1)').css(TRANSFORM);
                element.css(TRANSFORM, 'scale(' + currentScale + ')');
                start.top = outerBox.top;
                start.left = outerBox.left;
                start.transformOrigin = transformOrigin.x + PX + ' ' + transformOrigin.y + PX;
                if (that._reverse) {
                    start.scale = scale;
                } else {
                    end.scale = scale;
                }
            }
        });
        var CLIPS = {
            top: 'rect(auto auto $size auto)',
            bottom: 'rect($size auto auto auto)',
            left: 'rect(auto $size auto auto)',
            right: 'rect(auto auto auto $size)'
        };
        var ROTATIONS = {
            top: {
                start: 'rotatex(0deg)',
                end: 'rotatex(180deg)'
            },
            bottom: {
                start: 'rotatex(-180deg)',
                end: 'rotatex(0deg)'
            },
            left: {
                start: 'rotatey(0deg)',
                end: 'rotatey(-180deg)'
            },
            right: {
                start: 'rotatey(180deg)',
                end: 'rotatey(0deg)'
            }
        };
        function clipInHalf(container, direction) {
            var vertical = kendo.directions[direction].vertical, size = container[vertical ? HEIGHT : WIDTH]() / 2 + 'px';
            return CLIPS[direction].replace('$size', size);
        }
        createEffect('turningPage', {
            directions: FOUR_DIRECTIONS,
            init: function (element, direction, container) {
                Effect.prototype.init.call(this, element, direction);
                this._container = container;
            },
            prepare: function (start, end) {
                var that = this, reverse = that._reverse, direction = reverse ? directions[that._direction].reverse : that._direction, rotation = ROTATIONS[direction];
                start.zIndex = 1;
                if (that._clipInHalf) {
                    start.clip = clipInHalf(that._container, kendo.directions[direction].reverse);
                }
                start[BACKFACE] = HIDDEN;
                end[TRANSFORM] = TRANSFORM_PERSPECTIVE + (reverse ? rotation.start : rotation.end);
                start[TRANSFORM] = TRANSFORM_PERSPECTIVE + (reverse ? rotation.end : rotation.start);
            },
            setup: function () {
                this._container.append(this.element);
            },
            face: function (value) {
                this._face = value;
                return this;
            },
            shouldHide: function () {
                var that = this, reverse = that._reverse, face = that._face;
                return reverse && !face || !reverse && face;
            },
            clipInHalf: function (value) {
                this._clipInHalf = value;
                return this;
            },
            temporary: function () {
                this.element.addClass('temp-page');
                return this;
            }
        });
        createEffect('staticPage', {
            directions: FOUR_DIRECTIONS,
            init: function (element, direction, container) {
                Effect.prototype.init.call(this, element, direction);
                this._container = container;
            },
            restore: ['clip'],
            prepare: function (start, end) {
                var that = this, direction = that._reverse ? directions[that._direction].reverse : that._direction;
                start.clip = clipInHalf(that._container, direction);
                start.opacity = 0.999;
                end.opacity = 1;
            },
            shouldHide: function () {
                var that = this, reverse = that._reverse, face = that._face;
                return reverse && !face || !reverse && face;
            },
            face: function (value) {
                this._face = value;
                return this;
            }
        });
        createEffect('pageturn', {
            directions: [
                'horizontal',
                'vertical'
            ],
            init: function (element, direction, face, back) {
                Effect.prototype.init.call(this, element, direction);
                this.options = {};
                this.options.face = face;
                this.options.back = back;
            },
            children: function () {
                var that = this, options = that.options, direction = that._direction === 'horizontal' ? 'left' : 'top', reverseDirection = kendo.directions[direction].reverse, reverse = that._reverse, temp, faceClone = options.face.clone(true).removeAttr('id'), backClone = options.back.clone(true).removeAttr('id'), element = that.element;
                if (reverse) {
                    temp = direction;
                    direction = reverseDirection;
                    reverseDirection = temp;
                }
                return [
                    kendo.fx(options.face).staticPage(direction, element).face(true).setReverse(reverse),
                    kendo.fx(options.back).staticPage(reverseDirection, element).setReverse(reverse),
                    kendo.fx(faceClone).turningPage(direction, element).face(true).clipInHalf(true).temporary().setReverse(reverse),
                    kendo.fx(backClone).turningPage(reverseDirection, element).clipInHalf(true).temporary().setReverse(reverse)
                ];
            },
            prepare: function (start, end) {
                start[PERSPECTIVE] = DEFAULT_PERSPECTIVE;
                start.transformStyle = 'preserve-3d';
                start.opacity = 0.999;
                end.opacity = 1;
            },
            teardown: function () {
                this.element.find('.temp-page').remove();
            }
        });
        createEffect('flip', {
            directions: [
                'horizontal',
                'vertical'
            ],
            init: function (element, direction, face, back) {
                Effect.prototype.init.call(this, element, direction);
                this.options = {};
                this.options.face = face;
                this.options.back = back;
            },
            children: function () {
                var that = this, options = that.options, direction = that._direction === 'horizontal' ? 'left' : 'top', reverseDirection = kendo.directions[direction].reverse, reverse = that._reverse, temp, element = that.element;
                if (reverse) {
                    temp = direction;
                    direction = reverseDirection;
                    reverseDirection = temp;
                }
                return [
                    kendo.fx(options.face).turningPage(direction, element).face(true).setReverse(reverse),
                    kendo.fx(options.back).turningPage(reverseDirection, element).setReverse(reverse)
                ];
            },
            prepare: function (start) {
                start[PERSPECTIVE] = DEFAULT_PERSPECTIVE;
                start.transformStyle = 'preserve-3d';
            }
        });
        var RESTORE_OVERFLOW = !support.mobileOS.android;
        var IGNORE_TRANSITION_EVENT_SELECTOR = '.km-touch-scrollbar, .km-actionsheet-wrapper';
        createEffect('replace', {
            _before: $.noop,
            _after: $.noop,
            init: function (element, previous, transitionClass) {
                Effect.prototype.init.call(this, element);
                this._previous = $(previous);
                this._transitionClass = transitionClass;
            },
            duration: function () {
                throw new Error('The replace effect does not support duration setting; the effect duration may be customized through the transition class rule');
            },
            beforeTransition: function (callback) {
                this._before = callback;
                return this;
            },
            afterTransition: function (callback) {
                this._after = callback;
                return this;
            },
            _both: function () {
                return $().add(this._element).add(this._previous);
            },
            _containerClass: function () {
                var direction = this._direction, containerClass = 'k-fx k-fx-start k-fx-' + this._transitionClass;
                if (direction) {
                    containerClass += ' k-fx-' + direction;
                }
                if (this._reverse) {
                    containerClass += ' k-fx-reverse';
                }
                return containerClass;
            },
            complete: function (e) {
                if (!this.deferred || e && $(e.target).is(IGNORE_TRANSITION_EVENT_SELECTOR)) {
                    return;
                }
                var container = this.container;
                container.removeClass('k-fx-end').removeClass(this._containerClass()).off(transitions.event, this.completeProxy);
                this._previous.hide().removeClass('k-fx-current');
                this.element.removeClass('k-fx-next');
                if (RESTORE_OVERFLOW) {
                    container.css(OVERFLOW, '');
                }
                if (!this.isAbsolute) {
                    this._both().css(POSITION, '');
                }
                this.deferred.resolve();
                delete this.deferred;
            },
            run: function () {
                if (this._additionalEffects && this._additionalEffects[0]) {
                    return this.compositeRun();
                }
                var that = this, element = that.element, previous = that._previous, container = element.parents().filter(previous.parents()).first(), both = that._both(), deferred = $.Deferred(), originalPosition = element.css(POSITION), originalOverflow;
                if (!container.length) {
                    container = element.parent();
                }
                this.container = container;
                this.deferred = deferred;
                this.isAbsolute = originalPosition == 'absolute';
                if (!this.isAbsolute) {
                    both.css(POSITION, 'absolute');
                }
                if (RESTORE_OVERFLOW) {
                    originalOverflow = container.css(OVERFLOW);
                    container.css(OVERFLOW, 'hidden');
                }
                if (!transitions) {
                    this.complete();
                } else {
                    element.addClass('k-fx-hidden');
                    container.addClass(this._containerClass());
                    this.completeProxy = $.proxy(this, 'complete');
                    container.on(transitions.event, this.completeProxy);
                    kendo.animationFrame(function () {
                        element.removeClass('k-fx-hidden').addClass('k-fx-next');
                        previous.css('display', '').addClass('k-fx-current');
                        that._before(previous, element);
                        kendo.animationFrame(function () {
                            container.removeClass('k-fx-start').addClass('k-fx-end');
                            that._after(previous, element);
                        });
                    });
                }
                return deferred.promise();
            },
            stop: function () {
                this.complete();
            }
        });
        var Animation = kendo.Class.extend({
            init: function () {
                var that = this;
                that._tickProxy = proxy(that._tick, that);
                that._started = false;
            },
            tick: $.noop,
            done: $.noop,
            onEnd: $.noop,
            onCancel: $.noop,
            start: function () {
                if (!this.enabled()) {
                    return;
                }
                if (!this.done()) {
                    this._started = true;
                    kendo.animationFrame(this._tickProxy);
                } else {
                    this.onEnd();
                }
            },
            enabled: function () {
                return true;
            },
            cancel: function () {
                this._started = false;
                this.onCancel();
            },
            _tick: function () {
                var that = this;
                if (!that._started) {
                    return;
                }
                that.tick();
                if (!that.done()) {
                    kendo.animationFrame(that._tickProxy);
                } else {
                    that._started = false;
                    that.onEnd();
                }
            }
        });
        var Transition = Animation.extend({
            init: function (options) {
                var that = this;
                extend(that, options);
                Animation.fn.init.call(that);
            },
            done: function () {
                return this.timePassed() >= this.duration;
            },
            timePassed: function () {
                return Math.min(this.duration, new Date() - this.startDate);
            },
            moveTo: function (options) {
                var that = this, movable = that.movable;
                that.initial = movable[that.axis];
                that.delta = options.location - that.initial;
                that.duration = typeof options.duration == 'number' ? options.duration : 300;
                that.tick = that._easeProxy(options.ease);
                that.startDate = new Date();
                that.start();
            },
            _easeProxy: function (ease) {
                var that = this;
                return function () {
                    that.movable.moveAxis(that.axis, ease(that.timePassed(), that.initial, that.delta, that.duration));
                };
            }
        });
        extend(Transition, {
            easeOutExpo: function (t, b, c, d) {
                return t == d ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
            },
            easeOutBack: function (t, b, c, d, s) {
                s = 1.70158;
                return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
            }
        });
        fx.Animation = Animation;
        fx.Transition = Transition;
        fx.createEffect = createEffect;
        fx.box = function (element) {
            element = $(element);
            var result = element.offset();
            result.width = kendo._outerWidth(element);
            result.height = kendo._outerHeight(element);
            return result;
        };
        fx.transformOrigin = function (inner, outer) {
            var x = (inner.left - outer.left) * outer.width / (outer.width - inner.width), y = (inner.top - outer.top) * outer.height / (outer.height - inner.height);
            return {
                x: isNaN(x) ? 0 : x,
                y: isNaN(y) ? 0 : y
            };
        };
        fx.fillScale = function (inner, outer) {
            return Math.min(inner.width / outer.width, inner.height / outer.height);
        };
        fx.fitScale = function (inner, outer) {
            return Math.max(inner.width / outer.width, inner.height / outer.height);
        };
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.view', [
        'kendo.core',
        'kendo.binder',
        'kendo.fx'
    ], f);
}(function () {
    var __meta__ = {
        id: 'view',
        name: 'View',
        category: 'framework',
        description: 'The View class instantiates and handles the events of a certain screen from the application.',
        depends: [
            'core',
            'binder',
            'fx'
        ],
        hidden: false
    };
    (function ($, undefined) {
        var kendo = window.kendo, attr = kendo.attr, ui = kendo.ui, attrValue = kendo.attrValue, directiveSelector = kendo.directiveSelector, Observable = kendo.Observable, Widget = kendo.ui.Widget, roleSelector = kendo.roleSelector, SCRIPT = 'SCRIPT', INIT = 'init', TRANSITION_START = 'transitionStart', TRANSITION_END = 'transitionEnd', SHOW = 'show', HIDE = 'hide', ATTACH = 'attach', DETACH = 'detach', sizzleErrorRegExp = /unrecognized expression/;
        var bodyRegExp = /<body[^>]*>(([\u000a\u000d\u2028\u2029]|.)*)<\/body>/i;
        var LOAD_START = 'loadStart';
        var LOAD_COMPLETE = 'loadComplete';
        var SHOW_START = 'showStart';
        var SAME_VIEW_REQUESTED = 'sameViewRequested';
        var VIEW_SHOW = 'viewShow';
        var VIEW_TYPE_DETERMINED = 'viewTypeDetermined';
        var AFTER = 'after';
        var classNames = {
            content: 'k-content',
            view: 'k-view',
            stretchedView: 'k-stretched-view',
            widget: 'k-widget',
            header: 'k-header',
            footer: 'k-footer'
        };
        var View = kendo.ui.Widget.extend({
            init: function (content, options) {
                var that = this;
                options = options || {};
                that.id = kendo.guid();
                Observable.fn.init.call(that);
                that._initOptions(options);
                that.content = content;
                if (that.options.renderOnInit) {
                    Widget.fn.init.call(that, that._createElement(), options);
                }
                if (that.options.wrapInSections) {
                    that._renderSections();
                }
                that.tagName = options.tagName || 'div';
                that.model = options.model;
                that._wrap = options.wrap !== false;
                this._evalTemplate = options.evalTemplate || false;
                that._fragments = {};
                that.bind([
                    INIT,
                    SHOW,
                    HIDE,
                    TRANSITION_START,
                    TRANSITION_END
                ], options);
            },
            options: {
                name: 'View',
                renderOnInit: false,
                wrapInSections: false,
                detachOnHide: true,
                detachOnDestroy: true
            },
            render: function (container) {
                var that = this, notInitialized = !that.element;
                if (notInitialized) {
                    that.element = that._createElement();
                }
                if (container) {
                    $(container).append(that.element);
                }
                if (notInitialized) {
                    kendo.bind(that.element, that.model);
                    that.trigger(INIT);
                }
                if (container) {
                    that._eachFragment(ATTACH);
                    that.trigger(SHOW);
                }
                return that.element;
            },
            clone: function () {
                return new ViewClone(this);
            },
            triggerBeforeShow: function () {
                return true;
            },
            triggerBeforeHide: function () {
                return true;
            },
            showStart: function () {
                var that = this;
                var element = that.render();
                if (element) {
                    element.css('display', '');
                }
                this.trigger(SHOW, { view: this });
            },
            showEnd: function () {
            },
            hideEnd: function () {
                this.hide();
            },
            beforeTransition: function (type) {
                this.trigger(TRANSITION_START, { type: type });
            },
            afterTransition: function (type) {
                this.trigger(TRANSITION_END, { type: type });
            },
            hide: function () {
                if (this.options.detachOnHide) {
                    this._eachFragment(DETACH);
                    $(this.element).detach();
                }
                this.trigger(HIDE);
            },
            destroy: function () {
                var that = this;
                var element = that.element;
                if (element) {
                    Widget.fn.destroy.call(that);
                    kendo.unbind(element);
                    kendo.destroy(element);
                    if (that.options.detachOnDestroy) {
                        element.remove();
                    }
                }
            },
            purge: function () {
                var that = this;
                that.destroy();
                $(that.element).add(that.content).add(that.wrapper).off().remove();
            },
            fragments: function (fragments) {
                $.extend(this._fragments, fragments);
            },
            _eachFragment: function (methodName) {
                for (var placeholder in this._fragments) {
                    this._fragments[placeholder][methodName](this, placeholder);
                }
            },
            _createElement: function () {
                var that = this, wrapper = '<' + that.tagName + ' />', element, content;
                try {
                    content = $(document.getElementById(that.content) || that.content);
                    if (content[0].tagName === SCRIPT) {
                        content = content.html();
                    }
                } catch (e) {
                    if (sizzleErrorRegExp.test(e.message)) {
                        content = that.content;
                    }
                }
                if (typeof content === 'string') {
                    content = content.replace(/^\s+|\s+$/g, '');
                    if (that._evalTemplate) {
                        content = kendo.template(content)(that.model || {});
                    }
                    element = $(wrapper).append(content);
                    if (!that._wrap) {
                        element = element.contents();
                    }
                } else {
                    element = content;
                    if (that._evalTemplate) {
                        var result = $(kendo.template($('<div />').append(element.clone(true)).html())(that.model || {}));
                        if ($.contains(document, element[0])) {
                            element.replaceWith(result);
                        }
                        element = result;
                    }
                    if (that._wrap) {
                        element = element.wrapAll(wrapper).parent();
                    }
                }
                return element;
            },
            _renderSections: function () {
                var that = this;
                if (that.options.wrapInSections) {
                    that._wrapper();
                    that._createContent();
                    that._createHeader();
                    that._createFooter();
                }
            },
            _wrapper: function () {
                var that = this;
                var content = that.content;
                if (content.is(roleSelector('view'))) {
                    that.wrapper = that.content;
                } else {
                    that.wrapper = content.wrap('<div data-' + kendo.ns + 'stretch="true" data-' + kendo.ns + 'role="view" data-' + kendo.ns + 'init-widgets="false"></div>').parent();
                }
                var wrapper = that.wrapper;
                wrapper.attr('id', that.id);
                wrapper.addClass(classNames.view);
                wrapper.addClass(classNames.widget);
                wrapper.attr('role', 'view');
            },
            _createContent: function () {
                var that = this;
                var wrapper = $(that.wrapper);
                var contentSelector = roleSelector('content');
                if (!wrapper.children(contentSelector)[0]) {
                    var ccontentElements = wrapper.children().filter(function () {
                        var child = $(this);
                        if (!child.is(roleSelector('header')) && !child.is(roleSelector('footer'))) {
                            return child;
                        }
                    });
                    ccontentElements.wrap('<div ' + attr('role') + '="content"></div>');
                }
                this.contentElement = wrapper.children(roleSelector('content'));
                this.contentElement.addClass(classNames.stretchedView).addClass(classNames.content);
            },
            _createHeader: function () {
                var that = this;
                var wrapper = that.wrapper;
                this.header = wrapper.children(roleSelector('header')).addClass(classNames.header);
            },
            _createFooter: function () {
                var that = this;
                var wrapper = that.wrapper;
                this.footer = wrapper.children(roleSelector('footer')).addClass(classNames.footer);
            }
        });
        var ViewClone = kendo.Class.extend({
            init: function (view) {
                $.extend(this, {
                    element: view.element.clone(true),
                    transition: view.transition,
                    id: view.id
                });
                view.element.parent().append(this.element);
            },
            hideEnd: function () {
                this.element.remove();
            },
            beforeTransition: $.noop,
            afterTransition: $.noop
        });
        var Layout = View.extend({
            init: function (content, options) {
                View.fn.init.call(this, content, options);
                this.containers = {};
            },
            container: function (selector) {
                var container = this.containers[selector];
                if (!container) {
                    container = this._createContainer(selector);
                    this.containers[selector] = container;
                }
                return container;
            },
            showIn: function (selector, view, transition) {
                this.container(selector).show(view, transition);
            },
            _createContainer: function (selector) {
                var root = this.render(), element = root.find(selector), container;
                if (!element.length && root.is(selector)) {
                    if (root.is(selector)) {
                        element = root;
                    } else {
                        throw new Error('can\'t find a container with the specified ' + selector + ' selector');
                    }
                }
                container = new ViewContainer(element);
                container.bind('accepted', function (e) {
                    e.view.render(element);
                });
                return container;
            }
        });
        var Fragment = View.extend({
            attach: function (view, placeholder) {
                view.element.find(placeholder).replaceWith(this.render());
            },
            detach: function () {
            }
        });
        var transitionRegExp = /^(\w+)(:(\w+))?( (\w+))?$/;
        function parseTransition(transition) {
            if (!transition) {
                return {};
            }
            var matches = transition.match(transitionRegExp) || [];
            return {
                type: matches[1],
                direction: matches[3],
                reverse: matches[5] === 'reverse'
            };
        }
        var ViewContainer = Observable.extend({
            init: function (container) {
                Observable.fn.init.call(this);
                this.container = container;
                this.history = [];
                this.view = null;
                this.running = false;
            },
            after: function () {
                this.running = false;
                this.trigger('complete', { view: this.view });
                this.trigger('after');
            },
            end: function () {
                this.view.showEnd();
                this.previous.hideEnd();
                this.after();
            },
            show: function (view, transition, locationID) {
                if (!view.triggerBeforeShow() || this.view && !this.view.triggerBeforeHide()) {
                    this.trigger('after');
                    return false;
                }
                locationID = locationID || view.id;
                var that = this, current = view === that.view ? view.clone() : that.view, history = that.history, previousEntry = history[history.length - 2] || {}, back = previousEntry.id === locationID, theTransition = transition || (back ? history[history.length - 1].transition : view.transition), transitionData = parseTransition(theTransition);
                if (that.running) {
                    that.effect.stop();
                }
                if (theTransition === 'none') {
                    theTransition = null;
                }
                that.trigger('accepted', { view: view });
                that.view = view;
                that.previous = current;
                that.running = true;
                if (!back) {
                    history.push({
                        id: locationID,
                        transition: theTransition
                    });
                } else {
                    history.pop();
                }
                if (!current) {
                    view.showStart();
                    view.showEnd();
                    that.after();
                    return true;
                }
                if (!theTransition || !kendo.effects.enabled) {
                    view.showStart();
                    that.end();
                } else {
                    view.element.addClass('k-fx-hidden');
                    view.showStart();
                    if (back && !transition) {
                        transitionData.reverse = !transitionData.reverse;
                    }
                    that.effect = kendo.fx(view.element).replace(current.element, transitionData.type).beforeTransition(function () {
                        view.beforeTransition('show');
                        current.beforeTransition('hide');
                    }).afterTransition(function () {
                        view.afterTransition('show');
                        current.afterTransition('hide');
                    }).direction(transitionData.direction).setReverse(transitionData.reverse);
                    that.effect.run().then(function () {
                        that.end();
                    });
                }
                return true;
            },
            destroy: function () {
                var that = this;
                var view = that.view;
                if (view && view.destroy) {
                    view.destroy();
                }
            }
        });
        var ViewEngine = Observable.extend({
            init: function (options) {
                var that = this, views, container;
                Observable.fn.init.call(that);
                that.options = options;
                $.extend(that, options);
                that.sandbox = $('<div />');
                container = that.container;
                views = that._hideViews(container);
                that.rootView = views.first();
                that.layouts = {};
                that.viewContainer = new kendo.ViewContainer(that.container);
                that.viewContainer.bind('accepted', function (e) {
                    e.view.params = that.params;
                });
                that.viewContainer.bind('complete', function (e) {
                    that.trigger(VIEW_SHOW, { view: e.view });
                });
                that.viewContainer.bind(AFTER, function () {
                    that.trigger(AFTER);
                });
                this.bind(this.events, options);
            },
            events: [
                SHOW_START,
                AFTER,
                VIEW_SHOW,
                LOAD_START,
                LOAD_COMPLETE,
                SAME_VIEW_REQUESTED,
                VIEW_TYPE_DETERMINED
            ],
            destroy: function () {
                var that = this;
                var viewContainer = that.viewContainer;
                kendo.destroy(that.container);
                for (var id in that.layouts) {
                    this.layouts[id].destroy();
                }
                if (viewContainer) {
                    viewContainer.destroy();
                }
            },
            view: function () {
                return this.viewContainer.view;
            },
            showView: function (url, transition, params) {
                url = url.replace(new RegExp('^' + this.remoteViewURLPrefix), '');
                if (url === '' && this.remoteViewURLPrefix) {
                    url = '/';
                }
                if (url.replace(/^#/, '') === this.url) {
                    this.trigger(SAME_VIEW_REQUESTED);
                    return false;
                }
                this.trigger(SHOW_START);
                var that = this, element = that._findViewElement(url), view = kendo.widgetInstance(element);
                that.url = url.replace(/^#/, '');
                that.params = params;
                if (view && view.reload) {
                    view.purge();
                    element = [];
                }
                this.trigger(VIEW_TYPE_DETERMINED, {
                    remote: element.length === 0,
                    url: url
                });
                if (element[0]) {
                    if (!view) {
                        view = that._createView(element);
                    }
                    return that.viewContainer.show(view, transition, url);
                } else {
                    return true;
                }
            },
            append: function (html, url) {
                var sandbox = this.sandbox, urlPath = (url || '').split('?')[0], container = this.container, views, view;
                if (bodyRegExp.test(html)) {
                    html = RegExp.$1;
                }
                sandbox[0].innerHTML = html;
                container.append(sandbox.children('script, style'));
                views = this._hideViews(sandbox);
                view = views.first();
                if (!view.length) {
                    views = view = sandbox.wrapInner('<div data-role=view />').children();
                }
                if (urlPath) {
                    view.hide().attr(attr('url'), urlPath);
                }
                container.append(views);
                return this._createView(view);
            },
            _locate: function (selectors) {
                return this.$angular ? directiveSelector(selectors) : roleSelector(selectors);
            },
            _findViewElement: function (url) {
                var element, urlPath = url.split('?')[0];
                if (!urlPath) {
                    return this.rootView;
                }
                element = this.container.children('[' + attr('url') + '=\'' + urlPath + '\']');
                if (!element[0] && urlPath.indexOf('/') === -1) {
                    element = this.container.children(urlPath.charAt(0) === '#' ? urlPath : '#' + urlPath);
                }
                if (!element[0]) {
                    element = this._findViewElementById(url);
                }
                return element;
            },
            _findViewElementById: function (id) {
                var element = this.container.children('[id=\'' + id + '\']');
                return element;
            },
            _createView: function (element) {
                return this._createSpaView(element);
            },
            _createMobileView: function (element) {
                return kendo.initWidget(element, {
                    defaultTransition: this.transition,
                    loader: this.loader,
                    container: this.container,
                    getLayout: this.getLayoutProxy,
                    modelScope: this.modelScope,
                    reload: attrValue(element, 'reload')
                }, ui.roles);
            },
            _createSpaView: function (element) {
                var viewOptions = (this.options || {}).viewOptions || {};
                return new kendo.View(element, {
                    renderOnInit: viewOptions.renderOnInit,
                    wrap: viewOptions.wrap || false,
                    wrapInSections: viewOptions.wrapInSections,
                    detachOnHide: viewOptions.detachOnHide,
                    detachOnDestroy: viewOptions.detachOnDestroy
                });
            },
            _hideViews: function (container) {
                return container.children(this._locate('view')).hide();
            }
        });
        kendo.ViewEngine = ViewEngine;
        kendo.ViewContainer = ViewContainer;
        kendo.Fragment = Fragment;
        kendo.Layout = Layout;
        kendo.View = View;
        kendo.ViewClone = ViewClone;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dom', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'dom',
        name: 'Virtual DOM',
        category: 'framework',
        depends: ['core'],
        advanced: true
    };
    (function (kendo) {
        function Node() {
            this.node = null;
        }
        Node.prototype = {
            remove: function () {
                if (this.node.parentNode) {
                    this.node.parentNode.removeChild(this.node);
                }
                this.attr = {};
            },
            attr: {},
            text: function () {
                return '';
            }
        };
        function NullNode() {
        }
        NullNode.prototype = {
            nodeName: '#null',
            attr: { style: {} },
            children: [],
            remove: function () {
            }
        };
        var NULL_NODE = new NullNode();
        function Element(nodeName, attr, children) {
            this.nodeName = nodeName;
            this.attr = attr || {};
            this.children = children || [];
        }
        Element.prototype = new Node();
        Element.prototype.appendTo = function (parent) {
            var node = document.createElement(this.nodeName);
            var children = this.children;
            for (var index = 0; index < children.length; index++) {
                children[index].render(node, NULL_NODE);
            }
            parent.appendChild(node);
            return node;
        };
        Element.prototype.render = function (parent, cached) {
            var node;
            if (cached.nodeName !== this.nodeName) {
                cached.remove();
                node = this.appendTo(parent);
            } else {
                node = cached.node;
                var index;
                var children = this.children;
                var length = children.length;
                var cachedChildren = cached.children;
                var cachedLength = cachedChildren.length;
                if (Math.abs(cachedLength - length) > 2) {
                    this.render({
                        appendChild: function (node) {
                            parent.replaceChild(node, cached.node);
                        }
                    }, NULL_NODE);
                    return;
                }
                for (index = 0; index < length; index++) {
                    children[index].render(node, cachedChildren[index] || NULL_NODE);
                }
                for (index = length; index < cachedLength; index++) {
                    cachedChildren[index].remove();
                }
            }
            this.node = node;
            this.syncAttributes(cached.attr);
            this.removeAttributes(cached.attr);
        };
        Element.prototype.syncAttributes = function (cachedAttr) {
            var attr = this.attr;
            for (var name in attr) {
                var value = attr[name];
                var cachedValue = cachedAttr[name];
                if (name === 'style') {
                    this.setStyle(value, cachedValue);
                } else if (value !== cachedValue) {
                    this.setAttribute(name, value, cachedValue);
                }
            }
        };
        Element.prototype.setStyle = function (style, cachedValue) {
            var node = this.node;
            var key;
            if (cachedValue) {
                for (key in style) {
                    if (style[key] !== cachedValue[key]) {
                        node.style[key] = style[key];
                    }
                }
            } else {
                for (key in style) {
                    node.style[key] = style[key];
                }
            }
        };
        Element.prototype.removeStyle = function (cachedStyle) {
            var style = this.attr.style || {};
            var node = this.node;
            for (var key in cachedStyle) {
                if (style[key] === undefined) {
                    node.style[key] = '';
                }
            }
        };
        Element.prototype.removeAttributes = function (cachedAttr) {
            var attr = this.attr;
            for (var name in cachedAttr) {
                if (name === 'style') {
                    this.removeStyle(cachedAttr.style);
                } else if (attr[name] === undefined) {
                    this.removeAttribute(name);
                }
            }
        };
        Element.prototype.removeAttribute = function (name) {
            var node = this.node;
            if (name === 'style') {
                node.style.cssText = '';
            } else if (name === 'className') {
                node.className = '';
            } else {
                node.removeAttribute(name);
            }
        };
        Element.prototype.setAttribute = function (name, value) {
            var node = this.node;
            if (node[name] !== undefined) {
                node[name] = value;
            } else {
                node.setAttribute(name, value);
            }
        };
        Element.prototype.text = function () {
            var str = '';
            for (var i = 0; i < this.children.length; ++i) {
                str += this.children[i].text();
            }
            return str;
        };
        function TextNode(nodeValue) {
            this.nodeValue = String(nodeValue);
        }
        TextNode.prototype = new Node();
        TextNode.prototype.nodeName = '#text';
        TextNode.prototype.render = function (parent, cached) {
            var node;
            if (cached.nodeName !== this.nodeName) {
                cached.remove();
                node = document.createTextNode(this.nodeValue);
                parent.appendChild(node);
            } else {
                node = cached.node;
                if (this.nodeValue !== cached.nodeValue) {
                    if (node.parentNode) {
                        node.nodeValue = this.nodeValue;
                    }
                }
            }
            this.node = node;
        };
        TextNode.prototype.text = function () {
            return this.nodeValue;
        };
        function HtmlNode(html) {
            this.html = html;
        }
        HtmlNode.prototype = {
            nodeName: '#html',
            attr: {},
            remove: function () {
                for (var index = 0; index < this.nodes.length; index++) {
                    var el = this.nodes[index];
                    if (el.parentNode) {
                        el.parentNode.removeChild(el);
                    }
                }
            },
            render: function (parent, cached) {
                if (cached.nodeName !== this.nodeName || cached.html !== this.html) {
                    cached.remove();
                    var lastChild = parent.lastChild;
                    insertHtml(parent, this.html);
                    this.nodes = [];
                    for (var child = lastChild ? lastChild.nextSibling : parent.firstChild; child; child = child.nextSibling) {
                        this.nodes.push(child);
                    }
                } else {
                    this.nodes = cached.nodes.slice(0);
                }
            }
        };
        var HTML_CONTAINER = document.createElement('div');
        function insertHtml(node, html) {
            HTML_CONTAINER.innerHTML = html;
            while (HTML_CONTAINER.firstChild) {
                node.appendChild(HTML_CONTAINER.firstChild);
            }
        }
        function html(value) {
            return new HtmlNode(value);
        }
        function element(nodeName, attrs, children) {
            return new Element(nodeName, attrs, children);
        }
        function text(value) {
            return new TextNode(value);
        }
        function Tree(root) {
            this.root = root;
            this.children = [];
        }
        Tree.prototype = {
            html: html,
            element: element,
            text: text,
            render: function (children) {
                var cachedChildren = this.children;
                var index;
                var length;
                for (index = 0, length = children.length; index < length; index++) {
                    var cached = cachedChildren[index];
                    if (!cached) {
                        cached = NULL_NODE;
                    } else if (!cached.node || !cached.node.parentNode) {
                        cached.remove();
                        cached = NULL_NODE;
                    }
                    children[index].render(this.root, cached);
                }
                for (index = length; index < cachedChildren.length; index++) {
                    cachedChildren[index].remove();
                }
                this.children = children;
            }
        };
        kendo.dom = {
            html: html,
            text: text,
            element: element,
            Tree: Tree,
            Node: Node
        };
    }(window.kendo));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('ooxml/utils', ['kendo.core'], f);
}(function () {
    (function () {
        kendo.ooxml = kendo.ooxml || {};
        kendo.ooxml.createZip = function () {
            if (typeof JSZip === 'undefined') {
                throw new Error('JSZip not found. Check http://docs.telerik.com/kendo-ui/framework/excel/introduction#requirements for more details.');
            }
            return new JSZip();
        };
    }());
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('ooxml/kendo-ooxml', [
        'kendo.core',
        'ooxml/utils'
    ], f);
}(function () {
    (function ($) {
        window.kendo.ooxml = window.kendo.ooxml || {};
        var ooxml = kendo.ooxml;
        var map = $.map;
        var createZip = ooxml.createZip;
        var current = {
            toString: function (value) {
                return value;
            }
        };
        var IntlService = kendo.Class.extend({});
        IntlService.register = function (userImplementation) {
            current = userImplementation;
        };
        IntlService.toString = function (value, format) {
            return current.toString(value, format);
        };
        function dateToJulianDays(y, m, d) {
            return (1461 * (y + 4800 + ((m - 13) / 12 | 0)) / 4 | 0) + (367 * (m - 1 - 12 * ((m - 13) / 12 | 0)) / 12 | 0) - (3 * ((y + 4900 + ((m - 13) / 12 | 0)) / 100 | 0) / 4 | 0) + d - 32075;
        }
        var BASE_DATE = dateToJulianDays(1900, 0, -1);
        function packDate(year, month, date) {
            return dateToJulianDays(year, month, date) - BASE_DATE;
        }
        function packTime(hh, mm, ss, ms) {
            return (hh + (mm + (ss + ms / 1000) / 60) / 60) / 24;
        }
        function dateToSerial(date) {
            var time = packTime(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
            var serial = packDate(date.getFullYear(), date.getMonth(), date.getDate());
            return serial < 0 ? serial - 1 + time : serial + time;
        }
        var MIME_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
        var DATA_URL_PREFIX = 'data:' + MIME_TYPE + ';base64,';
        var DATA_URL_OPTIONS = {
            compression: 'DEFLATE',
            type: 'base64'
        };
        function toDataURI(content) {
            return DATA_URL_PREFIX + content;
        }
        function indexOf(thing, array) {
            return array.indexOf(thing);
        }
        var parseJSON = JSON.parse.bind(JSON);
        function ESC(val) {
            return String(val).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;').replace(/\'/g, '&#39;');
        }
        function repeat(count, func) {
            var str = '';
            for (var i = 0; i < count; ++i) {
                str += func(i);
            }
            return str;
        }
        function foreach(arr, func) {
            var str = '';
            if (arr != null) {
                if (Array.isArray(arr)) {
                    for (var i = 0; i < arr.length; ++i) {
                        str += func(arr[i], i);
                    }
                } else if (typeof arr == 'object') {
                    Object.keys(arr).forEach(function (key, i) {
                        str += func(arr[key], key, i);
                    });
                }
            }
            return str;
        }
        var XMLHEAD = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r';
        var RELS = XMLHEAD + '\n            <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">\n               <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>\n               <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>\n               <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>\n            </Relationships>';
        var CORE = function (ref) {
            var creator = ref.creator;
            var lastModifiedBy = ref.lastModifiedBy;
            var created = ref.created;
            var modified = ref.modified;
            return XMLHEAD + '\n <cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"\n   xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/"\n   xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\n   <dc:creator>' + ESC(creator) + '</dc:creator>\n   <cp:lastModifiedBy>' + ESC(lastModifiedBy) + '</cp:lastModifiedBy>\n   <dcterms:created xsi:type="dcterms:W3CDTF">' + ESC(created) + '</dcterms:created>\n   <dcterms:modified xsi:type="dcterms:W3CDTF">' + ESC(modified) + '</dcterms:modified>\n</cp:coreProperties>';
        };
        var APP = function (ref) {
            var sheets = ref.sheets;
            return XMLHEAD + '\n<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">\n  <Application>Microsoft Excel</Application>\n  <DocSecurity>0</DocSecurity>\n  <ScaleCrop>false</ScaleCrop>\n  <HeadingPairs>\n    <vt:vector size="2" baseType="variant">\n      <vt:variant>\n        <vt:lpstr>Worksheets</vt:lpstr>\n      </vt:variant>\n      <vt:variant>\n        <vt:i4>' + sheets.length + '</vt:i4>\n      </vt:variant>\n    </vt:vector>\n  </HeadingPairs>\n  <TitlesOfParts>\n    <vt:vector size="' + sheets.length + '" baseType="lpstr">' + foreach(sheets, function (sheet, i) {
                return sheet.options.title ? '<vt:lpstr>' + ESC(sheet.options.title) + '</vt:lpstr>' : '<vt:lpstr>Sheet' + (i + 1) + '</vt:lpstr>';
            }) + '</vt:vector>\n  </TitlesOfParts>\n  <LinksUpToDate>false</LinksUpToDate>\n  <SharedDoc>false</SharedDoc>\n  <HyperlinksChanged>false</HyperlinksChanged>\n  <AppVersion>14.0300</AppVersion>\n</Properties>';
        };
        var CONTENT_TYPES = function (ref) {
            var sheetCount = ref.sheetCount;
            var commentFiles = ref.commentFiles;
            var drawingFiles = ref.drawingFiles;
            return XMLHEAD + '\n<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">\n  <Default Extension="png" ContentType="image/png"/>\n  <Default Extension="gif" ContentType="image/gif"/>\n  <Default Extension="jpg" ContentType="image/jpeg"/>\n  <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />\n  <Default Extension="xml" ContentType="application/xml" />\n  <Default Extension="vml" ContentType="application/vnd.openxmlformats-officedocument.vmlDrawing"/>\n  <Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" />\n  <Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>\n  <Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>\n  ' + repeat(sheetCount, function (idx) {
                return '<Override PartName="/xl/worksheets/sheet' + (idx + 1) + '.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" />';
            }) + '\n  ' + foreach(commentFiles, function (filename) {
                return '<Override PartName="/xl/' + filename + '" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"/>';
            }) + '\n  ' + foreach(drawingFiles, function (filename) {
                return '<Override PartName="/xl/drawings/' + filename + '" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
            }) + '\n  <Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml" />\n  <Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" />\n</Types>';
        };
        var WORKBOOK = function (ref) {
            var sheets = ref.sheets;
            var filterNames = ref.filterNames;
            var userNames = ref.userNames;
            return XMLHEAD + '\n<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">\n  <fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="9303" />\n  <workbookPr defaultThemeVersion="124226" />\n  <bookViews>\n    <workbookView xWindow="240" yWindow="45" windowWidth="18195" windowHeight="7995" />\n  </bookViews>\n  <sheets>\n  ' + foreach(sheets, function (ref, i) {
                var options = ref.options;
                var name = options.name || options.title || 'Sheet' + (i + 1);
                return '<sheet name="' + ESC(name) + '" sheetId="' + (i + 1) + '" r:id="rId' + (i + 1) + '" />';
            }) + '\n  </sheets>\n  ' + (filterNames.length || userNames.length ? '\n    <definedNames>\n      ' + foreach(filterNames, function (f) {
                return '\n         <definedName name="_xlnm._FilterDatabase" hidden="1" localSheetId="' + f.localSheetId + '">' + ESC(f.name) + '!' + ESC(f.from) + ':' + ESC(f.to) + '</definedName>';
            }) + '\n      ' + foreach(userNames, function (f) {
                return '\n         <definedName name="' + f.name + '" hidden="' + (f.hidden ? 1 : 0) + '" ' + (f.localSheetId != null ? 'localSheetId="' + f.localSheetId + '"' : '') + '>' + ESC(f.value) + '</definedName>';
            }) + '\n    </definedNames>' : '') + '\n  <calcPr fullCalcOnLoad="1" calcId="145621" />\n</workbook>';
        };
        var WORKSHEET = function (ref) {
            var frozenColumns = ref.frozenColumns;
            var frozenRows = ref.frozenRows;
            var columns = ref.columns;
            var defaults = ref.defaults;
            var data = ref.data;
            var index = ref.index;
            var mergeCells = ref.mergeCells;
            var autoFilter = ref.autoFilter;
            var filter = ref.filter;
            var showGridLines = ref.showGridLines;
            var hyperlinks = ref.hyperlinks;
            var validations = ref.validations;
            var defaultCellStyleId = ref.defaultCellStyleId;
            var rtl = ref.rtl;
            var legacyDrawing = ref.legacyDrawing;
            var drawing = ref.drawing;
            var lastRow = ref.lastRow;
            return XMLHEAD + '\n<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" mc:Ignorable="x14ac">\n   <dimension ref="A1:A' + lastRow + '" />\n\n   <sheetViews>\n     <sheetView ' + (rtl ? 'rightToLeft="1"' : '') + ' ' + (index === 0 ? 'tabSelected="1"' : '') + ' workbookViewId="0" ' + (showGridLines === false ? 'showGridLines="0"' : '') + '>\n     ' + (frozenRows || frozenColumns ? '\n       <pane state="frozen"\n         ' + (frozenColumns ? 'xSplit="' + frozenColumns + '"' : '') + '\n         ' + (frozenRows ? 'ySplit="' + frozenRows + '"' : '') + '\n         topLeftCell="' + (String.fromCharCode(65 + (frozenColumns || 0)) + ((frozenRows || 0) + 1)) + '"\n       />' : '') + '\n     </sheetView>\n   </sheetViews>\n\n   <sheetFormatPr x14ac:dyDescent="0.25" customHeight="1" defaultRowHeight="' + (defaults.rowHeight ? defaults.rowHeight * 0.75 : 15) + '"\n     ' + (defaults.columnWidth ? 'defaultColWidth="' + toWidth(defaults.columnWidth) + '"' : '') + ' />\n\n   ' + (defaultCellStyleId != null || columns && columns.length > 0 ? '\n     <cols>\n       ' + (!columns || !columns.length ? '\n         <col min="1" max="16384" style="' + defaultCellStyleId + '"\n              ' + (defaults.columnWidth ? 'width="' + toWidth(defaults.columnWidth) + '"' : '') + ' /> ' : '') + '\n       ' + foreach(columns, function (column, ci) {
                var columnIndex = typeof column.index === 'number' ? column.index + 1 : ci + 1;
                if (column.width === 0) {
                    return '<col ' + (defaultCellStyleId != null ? 'style="' + defaultCellStyleId + '"' : '') + '\n                        min="' + columnIndex + '" max="' + columnIndex + '" hidden="1" customWidth="1" />';
                }
                return '<col ' + (defaultCellStyleId != null ? 'style="' + defaultCellStyleId + '"' : '') + '\n                      min="' + columnIndex + '" max="' + columnIndex + '" customWidth="1"\n                      ' + (column.autoWidth ? 'width="' + (column.width * 7 + 5) / 7 * 256 / 256 + '" bestFit="1"' : 'width="' + toWidth(column.width) + '"') + ' />';
            }) + '\n     </cols>' : '') + '\n\n   <sheetData>\n     ' + foreach(data, function (row, ri) {
                var rowIndex = typeof row.index === 'number' ? row.index + 1 : ri + 1;
                return '\n         <row r="' + rowIndex + '" x14ac:dyDescent="0.25"\n              ' + (row.level ? 'outlineLevel="' + row.level + '"' : '') + '\n              ' + (row.height === 0 ? 'hidden="1"' : row.height ? 'ht="' + toHeight(row.height) + '" customHeight="1"' : '') + '>\n           ' + foreach(row.data, function (cell) {
                    return '\n             <c r="' + cell.ref + '" ' + (cell.style ? 's="' + cell.style + '"' : '') + ' ' + (cell.type ? 't="' + cell.type + '"' : '') + '>\n               ' + (cell.formula != null ? writeFormula(cell.formula) : '') + '\n               ' + (cell.value != null ? '<v>' + ESC(cell.value) + '</v>' : '') + '\n             </c>';
                }) + '\n         </row>\n       ';
            }) + '\n   </sheetData>\n\n   ' + (autoFilter ? '<autoFilter ref="' + autoFilter.from + ':' + autoFilter.to + '"/>' : filter ? spreadsheetFilters(filter) : '') + '\n\n   ' + (mergeCells.length ? '\n     <mergeCells count="' + mergeCells.length + '">\n       ' + foreach(mergeCells, function (ref) {
                return '<mergeCell ref="' + ref + '"/>';
            }) + '\n     </mergeCells>' : '') + '\n\n   ' + (validations.length ? '\n     <dataValidations>\n       ' + foreach(validations, function (val) {
                return '\n         <dataValidation sqref="' + val.sqref.join(' ') + '"\n                         showErrorMessage="' + val.showErrorMessage + '"\n                         type="' + ESC(val.type) + '"\n                         ' + (val.type !== 'list' ? 'operator="' + ESC(val.operator) + '"' : '') + '\n                         allowBlank="' + val.allowBlank + '"\n                         showDropDown="' + val.showDropDown + '"\n                         ' + (val.error ? 'error="' + ESC(val.error) + '"' : '') + '\n                         ' + (val.errorTitle ? 'errorTitle="' + ESC(val.errorTitle) + '"' : '') + '>\n           ' + (val.formula1 ? '<formula1>' + ESC(val.formula1) + '</formula1>' : '') + '\n           ' + (val.formula2 ? '<formula2>' + ESC(val.formula2) + '</formula2>' : '') + '\n         </dataValidation>';
            }) + '\n     </dataValidations>' : '') + '\n\n   ' + (hyperlinks.length ? '\n     <hyperlinks>\n       ' + foreach(hyperlinks, function (link) {
                return '\n         <hyperlink ref="' + link.ref + '" r:id="' + link.rId + '"/>';
            }) + '\n     </hyperlinks>' : '') + '\n\n   <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3" />\n   ' + (legacyDrawing ? '<legacyDrawing r:id="' + legacyDrawing + '"/>' : '') + '\n   ' + (drawing ? '<drawing r:id="' + drawing + '"/>' : '') + '\n</worksheet>';
        };
        var WORKBOOK_RELS = function (ref) {
            var count = ref.count;
            return XMLHEAD + '\n<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">\n  ' + repeat(count, function (idx) {
                return '\n    <Relationship Id="rId' + (idx + 1) + '" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet' + (idx + 1) + '.xml" />';
            }) + '\n  <Relationship Id="rId' + (count + 1) + '" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml" />\n  <Relationship Id="rId' + (count + 2) + '" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml" />\n</Relationships>';
        };
        var WORKSHEET_RELS = function (ref) {
            var hyperlinks = ref.hyperlinks;
            var comments = ref.comments;
            var sheetIndex = ref.sheetIndex;
            var drawings = ref.drawings;
            return XMLHEAD + '\n<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">\n  ' + foreach(hyperlinks, function (link) {
                return '\n    <Relationship Id="' + link.rId + '" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="' + ESC(link.target) + '" TargetMode="External" />';
            }) + '\n  ' + (!comments.length ? '' : '\n    <Relationship Id="comment' + sheetIndex + '" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" Target="../comments' + sheetIndex + '.xml"/>\n    <Relationship Id="vml' + sheetIndex + '" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing" Target="../drawings/vmlDrawing' + sheetIndex + '.vml"/>') + '\n  ' + (!drawings.length ? '' : '\n    <Relationship Id="drw' + sheetIndex + '" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing" Target="../drawings/drawing' + sheetIndex + '.xml"/>') + '\n</Relationships>';
        };
        var COMMENTS_XML = function (ref) {
            var comments = ref.comments;
            return XMLHEAD + '\n<comments xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">\n  <authors>\n    <author></author>\n  </authors>\n  <commentList>\n    ' + foreach(comments, function (comment) {
                return '\n      <comment ref="' + comment.ref + '" authorId="0">\n        <text>\n          <r>\n            <rPr>\n              <sz val="8"/>\n              <color indexed="81"/>\n              <rFont val="Tahoma"/>\n              <charset val="1"/>\n            </rPr>\n            <t>' + ESC(comment.text) + '</t>\n          </r>\n        </text>\n      </comment>';
            }) + '\n  </commentList>\n</comments>';
        };
        var LEGACY_DRAWING = function (ref) {
            var comments = ref.comments;
            return '<xml xmlns:v="urn:schemas-microsoft-com:vml"\n     xmlns:o="urn:schemas-microsoft-com:office:office"\n     xmlns:x="urn:schemas-microsoft-com:office:excel">\n  <v:shapetype id="_x0000_t202" path="m,l,21600r21600,l21600,xe"></v:shapetype>\n  ' + foreach(comments, function (comment) {
                return '\n    <v:shape type="#_x0000_t202" style="visibility: hidden" fillcolor="#ffffe1" o:insetmode="auto">\n      <v:shadow on="t" color="black" obscured="t"/>\n      <x:ClientData ObjectType="Note">\n        <x:MoveWithCells/>\n        <x:SizeWithCells/>\n        <x:Anchor>' + comment.anchor + '</x:Anchor>\n        <x:AutoFill>False</x:AutoFill>\n        <x:Row>' + comment.row + '</x:Row>\n        <x:Column>' + comment.col + '</x:Column>\n      </x:ClientData>\n    </v:shape>';
            }) + '\n</xml>';
        };
        var DRAWINGS_XML = function (drawings) {
            return XMLHEAD + '\n<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"\n          xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"\n          xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">\n  ' + foreach(drawings, function (drawing, index) {
                return '\n    <xdr:oneCellAnchor editAs="oneCell">\n      <xdr:from>\n        <xdr:col>' + drawing.col + '</xdr:col>\n        <xdr:colOff>' + drawing.colOffset + '</xdr:colOff>\n        <xdr:row>' + drawing.row + '</xdr:row>\n        <xdr:rowOff>' + drawing.rowOffset + '</xdr:rowOff>\n      </xdr:from>\n      <xdr:ext cx="' + drawing.width + '" cy="' + drawing.height + '" />\n      <xdr:pic>\n        <xdr:nvPicPr>\n          <xdr:cNvPr id="' + (index + 1) + '" name="Picture ' + (index + 1) + '"/>\n          <xdr:cNvPicPr/>\n        </xdr:nvPicPr>\n        <xdr:blipFill>\n          <a:blip r:embed="' + drawing.imageId + '"/>\n          <a:stretch>\n            <a:fillRect/>\n          </a:stretch>\n        </xdr:blipFill>\n        <xdr:spPr>\n          <a:prstGeom prst="rect">\n            <a:avLst/>\n          </a:prstGeom>\n        </xdr:spPr>\n      </xdr:pic>\n      <xdr:clientData/>\n    </xdr:oneCellAnchor>';
            }) + '\n</xdr:wsDr>';
        };
        var DRAWINGS_RELS_XML = function (rels) {
            return XMLHEAD + '\n<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">\n  ' + foreach(rels, function (rel) {
                return '\n    <Relationship Id="' + rel.rId + '" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="' + rel.target + '"/>';
            }) + '\n</Relationships>';
        };
        var SHARED_STRINGS = function (ref) {
            var count = ref.count;
            var uniqueCount = ref.uniqueCount;
            var indexes = ref.indexes;
            return XMLHEAD + '\n<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="' + count + '" uniqueCount="' + uniqueCount + '">\n  ' + foreach(Object.keys(indexes), function (index) {
                return '\n    <si><t xml:space="preserve">' + ESC(index.substring(1)) + '</t></si>';
            }) + '\n</sst>';
        };
        var STYLES = function (ref) {
            var formats = ref.formats;
            var fonts = ref.fonts;
            var fills = ref.fills;
            var borders = ref.borders;
            var styles = ref.styles;
            return XMLHEAD + '\n<styleSheet\n    xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"\n    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\n    mc:Ignorable="x14ac"\n    xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">\n  <numFmts count="' + formats.length + '">\n  ' + foreach(formats, function (format, fi) {
                return '\n    <numFmt formatCode="' + ESC(format.format) + '" numFmtId="' + (165 + fi) + '" />';
            }) + '\n  </numFmts>\n  <fonts count="' + (fonts.length + 1) + '" x14ac:knownFonts="1">\n    <font>\n       <sz val="11" />\n       <color theme="1" />\n       <name val="Calibri" />\n       <family val="2" />\n       <scheme val="minor" />\n    </font>\n    ' + foreach(fonts, function (font) {
                return '\n    <font>\n      <sz val="' + (font.fontSize || 11) + '" />\n      ' + (font.bold ? '<b/>' : '') + '\n      ' + (font.italic ? '<i/>' : '') + '\n      ' + (font.underline ? '<u/>' : '') + '\n      ' + (font.color ? '<color rgb="' + ESC(font.color) + '" />' : '<color theme="1" />') + '\n      ' + (font.fontFamily ? '\n        <name val="' + ESC(font.fontFamily) + '" />\n        <family val="2" />\n      ' : '\n        <name val="Calibri" />\n        <family val="2" />\n        <scheme val="minor" />\n      ') + '\n    </font>';
            }) + '\n  </fonts>\n  <fills count="' + (fills.length + 2) + '">\n      <fill><patternFill patternType="none"/></fill>\n      <fill><patternFill patternType="gray125"/></fill>\n    ' + foreach(fills, function (fill) {
                return '\n      ' + (fill.background ? '\n        <fill>\n          <patternFill patternType="solid">\n              <fgColor rgb="' + ESC(fill.background) + '"/>\n          </patternFill>\n        </fill>\n      ' : '');
            }) + '\n  </fills>\n  <borders count="' + (borders.length + 1) + '">\n    <border><left/><right/><top/><bottom/><diagonal/></border>\n    ' + foreach(borders, borderTemplate) + '\n  </borders>\n  <cellStyleXfs count="1">\n    <xf borderId="0" fillId="0" fontId="0" />\n  </cellStyleXfs>\n  <cellXfs count="' + (styles.length + 1) + '">\n    <xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0" />\n    ' + foreach(styles, function (style) {
                return '\n      <xf xfId="0"\n          ' + (style.fontId ? 'fontId="' + style.fontId + '" applyFont="1"' : '') + '\n          ' + (style.fillId ? 'fillId="' + style.fillId + '" applyFill="1"' : '') + '\n          ' + (style.numFmtId ? 'numFmtId="' + style.numFmtId + '" applyNumberFormat="1"' : '') + '\n          ' + (style.textAlign || style.verticalAlign || style.wrap ? 'applyAlignment="1"' : '') + '\n          ' + (style.borderId ? 'borderId="' + style.borderId + '" applyBorder="1"' : '') + '>\n        ' + (style.textAlign || style.verticalAlign || style.wrap ? '\n        <alignment\n          ' + (style.textAlign ? 'horizontal="' + ESC(style.textAlign) + '"' : '') + '\n          ' + (style.verticalAlign ? 'vertical="' + ESC(style.verticalAlign) + '"' : '') + '\n          ' + (style.indent ? 'indent="' + ESC(style.indent) + '"' : '') + '\n          ' + (style.wrap ? 'wrapText="1"' : '') + ' />\n        ' : '') + '\n      </xf>\n    ';
            }) + '\n  </cellXfs>\n  <cellStyles count="1">\n    <cellStyle name="Normal" xfId="0" builtinId="0"/>\n  </cellStyles>\n  <dxfs count="0" />\n  <tableStyles count="0" defaultTableStyle="TableStyleMedium2" defaultPivotStyle="PivotStyleMedium9" />\n</styleSheet>';
        };
        function writeFormula(formula) {
            if (typeof formula == 'string') {
                return '<f>' + ESC(formula) + '</f>';
            }
            return '<f t="array" ref="' + formula.ref + '">' + ESC(formula.src) + '</f>';
        }
        function numChar(colIndex) {
            var letter = Math.floor(colIndex / 26) - 1;
            return (letter >= 0 ? numChar(letter) : '') + String.fromCharCode(65 + colIndex % 26);
        }
        function ref(rowIndex, colIndex) {
            return numChar(colIndex) + (rowIndex + 1);
        }
        function $ref(rowIndex, colIndex) {
            return '$' + numChar(colIndex) + '$' + (rowIndex + 1);
        }
        function filterRowIndex(options) {
            var frozenRows = options.frozenRows || (options.freezePane || {}).rowSplit || 1;
            return frozenRows - 1;
        }
        function toWidth(px) {
            var maximumDigitWidth = 7;
            return px / maximumDigitWidth - Math.floor(128 / maximumDigitWidth) / 256;
        }
        function toHeight(px) {
            return px * 0.75;
        }
        function stripFunnyChars(value) {
            return String(value).replace(/[\x00-\x09\x0B\x0C\x0E-\x1F]/g, '').replace(/\r?\n/g, '\r\n');
        }
        var Worksheet = kendo.Class.extend({
            init: function (options, sharedStrings, styles, borders) {
                this.options = options;
                this._strings = sharedStrings;
                this._styles = styles;
                this._borders = borders;
                this._validations = {};
                this._comments = [];
                this._drawings = options.drawings || [];
                this._hyperlinks = (this.options.hyperlinks || []).map(function (link, i) {
                    return $.extend({}, link, { rId: 'link' + i });
                });
            },
            relsToXML: function () {
                var hyperlinks = this._hyperlinks;
                var comments = this._comments;
                var drawings = this._drawings;
                if (hyperlinks.length || comments.length || drawings.length) {
                    return WORKSHEET_RELS({
                        hyperlinks: hyperlinks,
                        comments: comments,
                        sheetIndex: this.options.sheetIndex,
                        drawings: drawings
                    });
                }
            },
            toXML: function (index) {
                var this$1 = this;
                var mergeCells = this.options.mergedCells || [];
                var rows = this.options.rows || [];
                var data = inflate(rows, mergeCells);
                this._readCells(data);
                var autoFilter = this.options.filter;
                var filter;
                if (autoFilter && typeof autoFilter.from === 'number' && typeof autoFilter.to === 'number') {
                    autoFilter = {
                        from: ref(filterRowIndex(this.options), autoFilter.from),
                        to: ref(filterRowIndex(this.options), autoFilter.to)
                    };
                } else if (autoFilter && autoFilter.ref && autoFilter.columns) {
                    filter = autoFilter;
                    autoFilter = null;
                }
                var validations = [];
                for (var i in this._validations) {
                    if (Object.prototype.hasOwnProperty.call(this$1._validations, i)) {
                        validations.push(this$1._validations[i]);
                    }
                }
                var defaultCellStyleId = null;
                if (this.options.defaultCellStyle) {
                    defaultCellStyleId = this._lookupStyle(this.options.defaultCellStyle);
                }
                var freezePane = this.options.freezePane || {};
                var defaults = this.options.defaults || {};
                var lastRow = this.options.rows ? this._getLastRow() : 1;
                return WORKSHEET({
                    frozenColumns: this.options.frozenColumns || freezePane.colSplit,
                    frozenRows: this.options.frozenRows || freezePane.rowSplit,
                    columns: this.options.columns,
                    defaults: defaults,
                    data: data,
                    index: index,
                    mergeCells: mergeCells,
                    autoFilter: autoFilter,
                    filter: filter,
                    showGridLines: this.options.showGridLines,
                    hyperlinks: this._hyperlinks,
                    validations: validations,
                    defaultCellStyleId: defaultCellStyleId,
                    rtl: this.options.rtl !== undefined ? this.options.rtl : defaults.rtl,
                    legacyDrawing: this._comments.length ? 'vml' + this.options.sheetIndex : null,
                    drawing: this._drawings.length ? 'drw' + this.options.sheetIndex : null,
                    lastRow: lastRow
                });
            },
            commentsXML: function () {
                if (this._comments.length) {
                    return COMMENTS_XML({ comments: this._comments });
                }
            },
            drawingsXML: function (images) {
                if (this._drawings.length) {
                    var rels = {};
                    var main = this._drawings.map(function (drw) {
                        var ref = parseRef(drw.topLeftCell);
                        var img = rels[drw.image];
                        if (!img) {
                            img = rels[drw.image] = {
                                rId: 'img' + drw.image,
                                target: images[drw.image].target
                            };
                        }
                        return {
                            col: ref.col,
                            colOffset: pixelsToExcel(drw.offsetX),
                            row: ref.row,
                            rowOffset: pixelsToExcel(drw.offsetY),
                            width: pixelsToExcel(drw.width),
                            height: pixelsToExcel(drw.height),
                            imageId: img.rId
                        };
                    });
                    return {
                        main: DRAWINGS_XML(main),
                        rels: DRAWINGS_RELS_XML(rels)
                    };
                }
            },
            legacyDrawing: function () {
                if (this._comments.length) {
                    return LEGACY_DRAWING({ comments: this._comments });
                }
            },
            _lookupString: function (value) {
                var key = '$' + value;
                var index = this._strings.indexes[key];
                var result;
                if (index !== undefined) {
                    result = index;
                } else {
                    result = this._strings.indexes[key] = this._strings.uniqueCount;
                    this._strings.uniqueCount++;
                }
                this._strings.count++;
                return result;
            },
            _lookupStyle: function (style) {
                var json = JSON.stringify(style);
                if (json === '{}') {
                    return 0;
                }
                var index = indexOf(json, this._styles);
                if (index < 0) {
                    index = this._styles.push(json) - 1;
                }
                return index + 1;
            },
            _lookupBorder: function (border) {
                var json = JSON.stringify(border);
                if (json === '{}') {
                    return;
                }
                var index = indexOf(json, this._borders);
                if (index < 0) {
                    index = this._borders.push(json) - 1;
                }
                return index + 1;
            },
            _readCells: function (rowData) {
                var this$1 = this;
                for (var i = 0; i < rowData.length; i++) {
                    var row = rowData[i];
                    var cells = row.cells;
                    row.data = [];
                    for (var j = 0; j < cells.length; j++) {
                        var cellData = this$1._cell(cells[j], row.index, j);
                        if (cellData) {
                            row.data.push(cellData);
                        }
                    }
                }
            },
            _cell: function (data, rowIndex, cellIndex) {
                if (!data || data === EMPTY_CELL) {
                    return null;
                }
                var value = data.value;
                var border = {};
                if (data.borderLeft) {
                    border.left = data.borderLeft;
                }
                if (data.borderRight) {
                    border.right = data.borderRight;
                }
                if (data.borderTop) {
                    border.top = data.borderTop;
                }
                if (data.borderBottom) {
                    border.bottom = data.borderBottom;
                }
                border = this._lookupBorder(border);
                var defStyle = this.options.defaultCellStyle || {};
                var style = { borderId: border };
                (function (add) {
                    add('color');
                    add('background');
                    add('bold');
                    add('italic');
                    add('underline');
                    if (!add('fontFamily')) {
                        add('fontName', 'fontFamily');
                    }
                    add('fontSize');
                    add('format');
                    if (!add('textAlign')) {
                        add('hAlign', 'textAlign');
                    }
                    if (!add('verticalAlign')) {
                        add('vAlign', 'verticalAlign');
                    }
                    add('wrap');
                    add('indent');
                }(function (prop, target) {
                    var val = data[prop];
                    if (val === undefined) {
                        val = defStyle[prop];
                    }
                    if (val !== undefined) {
                        style[target || prop] = val;
                        return true;
                    }
                }));
                var columns = this.options.columns || [];
                var column = columns[cellIndex];
                var type = typeof value;
                if (column && column.autoWidth) {
                    var displayValue = value;
                    if (type === 'number') {
                        displayValue = IntlService.toString(value, data.format);
                    }
                    column.width = Math.max(column.width || 0, String(displayValue).length);
                }
                if (type === 'string') {
                    value = stripFunnyChars(value);
                    value = this._lookupString(value);
                    type = 's';
                } else if (type === 'number') {
                    type = 'n';
                } else if (type === 'boolean') {
                    type = 'b';
                    value = Number(value);
                } else if (value && value.getTime) {
                    type = null;
                    value = dateToSerial(value);
                    if (!style.format) {
                        style.format = 'mm-dd-yy';
                    }
                } else {
                    type = null;
                    value = null;
                }
                style = this._lookupStyle(style);
                var cellName = ref(rowIndex, cellIndex);
                if (data.validation) {
                    this._addValidation(data.validation, cellName);
                }
                if (data.comment) {
                    var anchor = [
                        cellIndex + 1,
                        15,
                        rowIndex,
                        10,
                        cellIndex + 3,
                        15,
                        rowIndex + 3,
                        4
                    ];
                    this._comments.push({
                        ref: cellName,
                        text: data.comment,
                        row: rowIndex,
                        col: cellIndex,
                        anchor: anchor.join(', ')
                    });
                }
                return {
                    value: value,
                    formula: data.formula,
                    type: type,
                    style: style,
                    ref: cellName
                };
            },
            _addValidation: function (v, ref) {
                var tmp = {
                    showErrorMessage: v.type === 'reject' ? 1 : 0,
                    formula1: v.from,
                    formula2: v.to,
                    type: MAP_EXCEL_TYPE[v.dataType] || v.dataType,
                    operator: MAP_EXCEL_OPERATOR[v.comparerType] || v.comparerType,
                    allowBlank: v.allowNulls ? 1 : 0,
                    showDropDown: v.showButton ? 0 : 1,
                    error: v.messageTemplate,
                    errorTitle: v.titleTemplate
                };
                var json = JSON.stringify(tmp);
                if (!this._validations[json]) {
                    this._validations[json] = tmp;
                    tmp.sqref = [];
                }
                this._validations[json].sqref.push(ref);
            },
            _getLastRow: function () {
                var rows = this.options.rows;
                var lastRow = rows.length;
                rows.forEach(function (row) {
                    if (row.index && row.index >= lastRow) {
                        lastRow = row.index + 1;
                    }
                });
                return lastRow;
            }
        });
        var MAP_EXCEL_OPERATOR = {
            greaterThanOrEqualTo: 'greaterThanOrEqual',
            lessThanOrEqualTo: 'lessThanOrEqual'
        };
        var MAP_EXCEL_TYPE = { number: 'decimal' };
        var defaultFormats = {
            'General': 0,
            '0': 1,
            '0.00': 2,
            '#,##0': 3,
            '#,##0.00': 4,
            '0%': 9,
            '0.00%': 10,
            '0.00E+00': 11,
            '# ?/?': 12,
            '# ??/??': 13,
            'mm-dd-yy': 14,
            'd-mmm-yy': 15,
            'd-mmm': 16,
            'mmm-yy': 17,
            'h:mm AM/PM': 18,
            'h:mm:ss AM/PM': 19,
            'h:mm': 20,
            'h:mm:ss': 21,
            'm/d/yy h:mm': 22,
            '#,##0 ;(#,##0)': 37,
            '#,##0 ;[Red](#,##0)': 38,
            '#,##0.00;(#,##0.00)': 39,
            '#,##0.00;[Red](#,##0.00)': 40,
            'mm:ss': 45,
            '[h]:mm:ss': 46,
            'mmss.0': 47,
            '##0.0E+0': 48,
            '@': 49,
            '[$-404]e/m/d': 27,
            'm/d/yy': 30,
            't0': 59,
            't0.00': 60,
            't#,##0': 61,
            't#,##0.00': 62,
            't0%': 67,
            't0.00%': 68,
            't# ?/?': 69,
            't# ??/??': 70
        };
        function convertColor(value) {
            var color = value;
            if (color.length < 6) {
                color = color.replace(/(\w)/g, function ($0, $1) {
                    return $1 + $1;
                });
            }
            color = color.substring(1).toUpperCase();
            if (color.length < 8) {
                color = 'FF' + color;
            }
            return color;
        }
        var Workbook = kendo.Class.extend({
            init: function (options) {
                var this$1 = this;
                this.options = options || {};
                this._strings = {
                    indexes: {},
                    count: 0,
                    uniqueCount: 0
                };
                this._styles = [];
                this._borders = [];
                this._images = this.options.images;
                this._imgId = 0;
                this._sheets = map(this.options.sheets || [], function (options, i) {
                    options.defaults = this$1.options;
                    options.sheetIndex = i + 1;
                    return new Worksheet(options, this$1._strings, this$1._styles, this$1._borders);
                });
            },
            imageFilename: function (mimeType) {
                var id = ++this._imgId;
                switch (mimeType) {
                case 'image/jpg':
                case 'image/jpeg':
                    return 'image' + id + '.jpg';
                case 'image/png':
                    return 'image' + id + '.png';
                case 'image/gif':
                    return 'image' + id + '.gif';
                default:
                    return 'image' + id + '.bin';
                }
            },
            toZIP: function () {
                var this$1 = this;
                var zip = createZip();
                var docProps = zip.folder('docProps');
                docProps.file('core.xml', CORE({
                    creator: this.options.creator || 'Kendo UI',
                    lastModifiedBy: this.options.creator || 'Kendo UI',
                    created: this.options.date || new Date().toJSON(),
                    modified: this.options.date || new Date().toJSON()
                }));
                var sheetCount = this._sheets.length;
                docProps.file('app.xml', APP({ sheets: this._sheets }));
                var rels = zip.folder('_rels');
                rels.file('.rels', RELS);
                var xl = zip.folder('xl');
                var xlRels = xl.folder('_rels');
                xlRels.file('workbook.xml.rels', WORKBOOK_RELS({ count: sheetCount }));
                if (this._images) {
                    var media = xl.folder('media');
                    Object.keys(this._images).forEach(function (id) {
                        var img = this$1._images[id];
                        var filename = this$1.imageFilename(img.type);
                        media.file(filename, img.data);
                        img.target = '../media/' + filename;
                    });
                }
                var sheetIds = {};
                xl.file('workbook.xml', WORKBOOK({
                    sheets: this._sheets,
                    filterNames: map(this._sheets, function (sheet, index) {
                        var options = sheet.options;
                        var sheetName = options.name || options.title || 'Sheet' + (index + 1);
                        sheetIds[sheetName.toLowerCase()] = index;
                        var filter = options.filter;
                        if (filter) {
                            if (filter.ref) {
                                var a = filter.ref.split(':');
                                var from = parseRef(a[0]);
                                var to = parseRef(a[1]);
                                return {
                                    localSheetId: index,
                                    name: sheetName,
                                    from: $ref(from.row, from.col),
                                    to: $ref(to.row, to.col)
                                };
                            } else if (typeof filter.from !== 'undefined' && typeof filter.to !== 'undefined') {
                                return {
                                    localSheetId: index,
                                    name: sheetName,
                                    from: $ref(filterRowIndex(options), filter.from),
                                    to: $ref(filterRowIndex(options), filter.to)
                                };
                            }
                        }
                    }),
                    userNames: map(this.options.names || [], function (def) {
                        return {
                            name: def.localName,
                            localSheetId: def.sheet ? sheetIds[def.sheet.toLowerCase()] : null,
                            value: def.value,
                            hidden: def.hidden
                        };
                    })
                }));
                var worksheets = xl.folder('worksheets');
                var drawings = xl.folder('drawings');
                var drawingsRels = drawings.folder('_rels');
                var sheetRels = worksheets.folder('_rels');
                var commentFiles = [];
                var drawingFiles = [];
                for (var idx = 0; idx < sheetCount; idx++) {
                    var sheet = this$1._sheets[idx];
                    var sheetName = 'sheet' + (idx + 1) + '.xml';
                    var sheetXML = sheet.toXML(idx);
                    var relsXML = sheet.relsToXML();
                    var commentsXML = sheet.commentsXML();
                    var legacyDrawing = sheet.legacyDrawing();
                    var drawingsXML = sheet.drawingsXML(this$1._images);
                    if (relsXML) {
                        sheetRels.file(sheetName + '.rels', relsXML);
                    }
                    if (commentsXML) {
                        var name = 'comments' + sheet.options.sheetIndex + '.xml';
                        xl.file(name, commentsXML);
                        commentFiles.push(name);
                    }
                    if (legacyDrawing) {
                        drawings.file('vmlDrawing' + sheet.options.sheetIndex + '.vml', legacyDrawing);
                    }
                    if (drawingsXML) {
                        var name$1 = 'drawing' + sheet.options.sheetIndex + '.xml';
                        drawings.file(name$1, drawingsXML.main);
                        drawingsRels.file(name$1 + '.rels', drawingsXML.rels);
                        drawingFiles.push(name$1);
                    }
                    worksheets.file(sheetName, sheetXML);
                }
                var borders = map(this._borders, parseJSON);
                var styles = map(this._styles, parseJSON);
                var hasFont = function (style) {
                    return style.underline || style.bold || style.italic || style.color || style.fontFamily || style.fontSize;
                };
                var convertFontSize = function (value) {
                    var fontInPx = Number(value);
                    var fontInPt;
                    if (fontInPx) {
                        fontInPt = fontInPx * 3 / 4;
                    }
                    return fontInPt;
                };
                var fonts = map(styles, function (style) {
                    if (style.fontSize) {
                        style.fontSize = convertFontSize(style.fontSize);
                    }
                    if (style.color) {
                        style.color = convertColor(style.color);
                    }
                    if (hasFont(style)) {
                        return style;
                    }
                });
                var formats = map(styles, function (style) {
                    if (style.format && defaultFormats[style.format] === undefined) {
                        return style;
                    }
                });
                var fills = map(styles, function (style) {
                    if (style.background) {
                        style.background = convertColor(style.background);
                        return style;
                    }
                });
                xl.file('styles.xml', STYLES({
                    fonts: fonts,
                    fills: fills,
                    formats: formats,
                    borders: borders,
                    styles: map(styles, function (style) {
                        var result = {};
                        if (hasFont(style)) {
                            result.fontId = indexOf(style, fonts) + 1;
                        }
                        if (style.background) {
                            result.fillId = indexOf(style, fills) + 2;
                        }
                        result.textAlign = style.textAlign;
                        result.indent = style.indent;
                        result.verticalAlign = style.verticalAlign;
                        result.wrap = style.wrap;
                        result.borderId = style.borderId;
                        if (style.format) {
                            if (defaultFormats[style.format] !== undefined) {
                                result.numFmtId = defaultFormats[style.format];
                            } else {
                                result.numFmtId = 165 + indexOf(style, formats);
                            }
                        }
                        return result;
                    })
                }));
                xl.file('sharedStrings.xml', SHARED_STRINGS(this._strings));
                zip.file('[Content_Types].xml', CONTENT_TYPES({
                    sheetCount: sheetCount,
                    commentFiles: commentFiles,
                    drawingFiles: drawingFiles
                }));
                return zip;
            },
            toDataURL: function () {
                var zip = this.toZIP();
                return zip.generateAsync ? zip.generateAsync(DATA_URL_OPTIONS).then(toDataURI) : toDataURI(zip.generate(DATA_URL_OPTIONS));
            },
            toBlob: function () {
                var zip = this.toZIP();
                if (zip.generateAsync) {
                    return zip.generateAsync({ type: 'blob' });
                }
                return new Blob([zip.generate({ type: 'arraybuffer' })], { type: MIME_TYPE });
            }
        });
        function borderStyle(width) {
            var alias = 'thin';
            if (width === 2) {
                alias = 'medium';
            } else if (width === 3) {
                alias = 'thick';
            }
            return alias;
        }
        function borderSideTemplate(name, style) {
            var result = '';
            if (style) {
                result += '<' + name + ' style="' + borderStyle(style.size) + '">';
                if (style.color) {
                    result += '<color rgb="' + convertColor(style.color) + '"/>';
                }
                result += '</' + name + '>';
            }
            return result;
        }
        function borderTemplate(border) {
            return '<border>' + borderSideTemplate('left', border.left) + borderSideTemplate('right', border.right) + borderSideTemplate('top', border.top) + borderSideTemplate('bottom', border.bottom) + '</border>';
        }
        var EMPTY_CELL = {};
        function inflate(rows, mergedCells) {
            var rowData = [];
            var rowsByIndex = [];
            indexRows(rows, function (row, index) {
                var data = {
                    _source: row,
                    index: index,
                    height: row.height,
                    level: row.level,
                    cells: []
                };
                rowData.push(data);
                rowsByIndex[index] = data;
            });
            var sorted = sortByIndex(rowData).slice(0);
            var ctx = {
                rowData: rowData,
                rowsByIndex: rowsByIndex,
                mergedCells: mergedCells
            };
            for (var i = 0; i < sorted.length; i++) {
                fillCells(sorted[i], ctx);
                delete sorted[i]._source;
            }
            return sortByIndex(rowData);
        }
        function indexRows(rows, callback) {
            for (var i = 0; i < rows.length; i++) {
                var row = rows[i];
                if (!row) {
                    continue;
                }
                var index = row.index;
                if (typeof index !== 'number') {
                    index = i;
                }
                callback(row, index);
            }
        }
        function sortByIndex(items) {
            return items.sort(function (a, b) {
                return a.index - b.index;
            });
        }
        function pushUnique(array, el) {
            if (array.indexOf(el) < 0) {
                array.push(el);
            }
        }
        function getSpan(mergedCells, ref) {
            for (var i = 0; i < mergedCells.length; ++i) {
                var range = mergedCells[i];
                var a = range.split(':');
                var topLeft = a[0];
                if (topLeft === ref) {
                    var bottomRight = a[1];
                    topLeft = parseRef(topLeft);
                    bottomRight = parseRef(bottomRight);
                    return {
                        rowSpan: bottomRight.row - topLeft.row + 1,
                        colSpan: bottomRight.col - topLeft.col + 1
                    };
                }
            }
        }
        function parseRef(ref) {
            function getcol(str) {
                var upperStr = str.toUpperCase();
                var col = 0;
                for (var i = 0; i < upperStr.length; ++i) {
                    col = col * 26 + upperStr.charCodeAt(i) - 64;
                }
                return col - 1;
            }
            function getrow(str) {
                return parseInt(str, 10) - 1;
            }
            var m = /^([a-z]+)(\d+)$/i.exec(ref);
            return {
                row: getrow(m[2]),
                col: getcol(m[1])
            };
        }
        function pixelsToExcel(px) {
            return Math.round(px * 9525);
        }
        function fillCells(data, ctx) {
            var row = data._source;
            var rowIndex = data.index;
            var cells = row.cells;
            var cellData = data.cells;
            if (!cells) {
                return;
            }
            for (var i = 0; i < cells.length; i++) {
                var cell = cells[i] || EMPTY_CELL;
                var rowSpan = cell.rowSpan || 1;
                var colSpan = cell.colSpan || 1;
                var cellIndex = insertCell(cellData, cell);
                var topLeftRef = ref(rowIndex, cellIndex);
                if (rowSpan === 1 && colSpan === 1) {
                    var tmp = getSpan(ctx.mergedCells, topLeftRef);
                    if (tmp) {
                        colSpan = tmp.colSpan;
                        rowSpan = tmp.rowSpan;
                    }
                }
                spanCell(cell, cellData, cellIndex, colSpan);
                if (rowSpan > 1 || colSpan > 1) {
                    pushUnique(ctx.mergedCells, topLeftRef + ':' + ref(rowIndex + rowSpan - 1, cellIndex + colSpan - 1));
                }
                if (rowSpan > 1) {
                    for (var ri = rowIndex + 1; ri < rowIndex + rowSpan; ri++) {
                        var nextRow = ctx.rowsByIndex[ri];
                        if (!nextRow) {
                            nextRow = ctx.rowsByIndex[ri] = {
                                index: ri,
                                cells: []
                            };
                            ctx.rowData.push(nextRow);
                        }
                        spanCell(cell, nextRow.cells, cellIndex - 1, colSpan + 1);
                    }
                }
            }
        }
        function insertCell(data, cell) {
            var index;
            if (typeof cell.index === 'number') {
                index = cell.index;
                insertCellAt(data, cell, cell.index);
            } else {
                index = appendCell(data, cell);
            }
            return index;
        }
        function insertCellAt(data, cell, index) {
            data[index] = cell;
        }
        function appendCell(data, cell) {
            var index = data.length;
            for (var i = 0; i < data.length + 1; i++) {
                if (!data[i]) {
                    data[i] = cell;
                    index = i;
                    break;
                }
            }
            return index;
        }
        function spanCell(cell, row, startIndex, colSpan) {
            for (var i = 1; i < colSpan; i++) {
                var tmp = {
                    borderTop: cell.borderTop,
                    borderRight: cell.borderRight,
                    borderBottom: cell.borderBottom,
                    borderLeft: cell.borderLeft
                };
                insertCellAt(row, tmp, startIndex + i);
            }
        }
        var SPREADSHEET_FILTERS = function (ref$1) {
            var ref = ref$1.ref;
            var columns = ref$1.columns;
            var generators = ref$1.generators;
            return '\n<autoFilter ref="' + ref + '">\n  ' + foreach(columns, function (col) {
                return '\n    <filterColumn colId="' + col.index + '">\n      ' + generators[col.filter](col) + '\n    </filterColumn>\n  ';
            }) + '\n</autoFilter>';
        };
        var SPREADSHEET_CUSTOM_FILTER = function (ref) {
            var logic = ref.logic;
            var criteria = ref.criteria;
            return '\n<customFilters ' + (logic === 'and' ? 'and="1"' : '') + '>\n' + foreach(criteria, function (f) {
                var op = spreadsheetFilters.customOperator(f);
                var val = spreadsheetFilters.customValue(f);
                return '<customFilter ' + (op ? 'operator="' + op + '"' : '') + ' val="' + val + '"/>';
            }) + '\n</customFilters>';
        };
        var SPREADSHEET_DYNAMIC_FILTER = function (ref) {
            var type = ref.type;
            return '<dynamicFilter type="' + spreadsheetFilters.dynamicFilterType(type) + '" />';
        };
        var SPREADSHEET_TOP_FILTER = function (ref) {
            var type = ref.type;
            var value = ref.value;
            return '<top10 percent="' + (/percent$/i.test(type) ? 1 : 0) + '"\n       top="' + (/^top/i.test(type) ? 1 : 0) + '"\n       val="' + value + '" />';
        };
        var SPREADSHEET_VALUE_FILTER = function (ref) {
            var blanks = ref.blanks;
            var values = ref.values;
            return '<filters ' + (blanks ? 'blank="1"' : '') + '>\n    ' + foreach(values, function (value) {
                return '\n      <filter val="' + value + '" />';
            }) + '\n  </filters>';
        };
        function spreadsheetFilters(filter) {
            return SPREADSHEET_FILTERS({
                ref: filter.ref,
                columns: filter.columns,
                generators: {
                    custom: SPREADSHEET_CUSTOM_FILTER,
                    dynamic: SPREADSHEET_DYNAMIC_FILTER,
                    top: SPREADSHEET_TOP_FILTER,
                    value: SPREADSHEET_VALUE_FILTER
                }
            });
        }
        spreadsheetFilters.customOperator = function (f) {
            return {
                eq: 'equal',
                gt: 'greaterThan',
                gte: 'greaterThanOrEqual',
                lt: 'lessThan',
                lte: 'lessThanOrEqual',
                ne: 'notEqual',
                doesnotstartwith: 'notEqual',
                doesnotendwith: 'notEqual',
                doesnotcontain: 'notEqual',
                doesnotmatch: 'notEqual'
            }[f.operator.toLowerCase()];
        };
        spreadsheetFilters.customValue = function (f) {
            function esc(str) {
                return str.replace(/([*?])/g, '~$1');
            }
            switch (f.operator.toLowerCase()) {
            case 'startswith':
            case 'doesnotstartwith':
                return esc(f.value) + '*';
            case 'endswith':
            case 'doesnotendwith':
                return '*' + esc(f.value);
            case 'contains':
            case 'doesnotcontain':
                return '*' + esc(f.value) + '*';
            default:
                return f.value;
            }
        };
        spreadsheetFilters.dynamicFilterType = function (type) {
            return {
                quarter1: 'Q1',
                quarter2: 'Q2',
                quarter3: 'Q3',
                quarter4: 'Q4',
                january: 'M1',
                february: 'M2',
                march: 'M3',
                april: 'M4',
                may: 'M5',
                june: 'M6',
                july: 'M7',
                august: 'M8',
                september: 'M9',
                october: 'M10',
                november: 'M11',
                december: 'M12'
            }[type.toLowerCase()] || type;
        };
        kendo.deepExtend(kendo.ooxml, {
            IntlService: IntlService,
            Workbook: Workbook,
            Worksheet: Worksheet
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('ooxml/main', [
        'kendo.core',
        'ooxml/kendo-ooxml'
    ], f);
}(function () {
    (function ($) {
        var Workbook = kendo.ooxml.Workbook;
        kendo.ooxml.IntlService.register({ toString: kendo.toString });
        kendo.ooxml.Workbook = Workbook.extend({
            toDataURL: function () {
                var result = Workbook.fn.toDataURL.call(this);
                if (typeof result !== 'string') {
                    throw new Error('The toDataURL method can be used only with jsZip 2. Either include jsZip 2 or use the toDataURLAsync method.');
                }
                return result;
            },
            toDataURLAsync: function () {
                var deferred = $.Deferred();
                var result = Workbook.fn.toDataURL.call(this);
                if (typeof result === 'string') {
                    result = deferred.resolve(result);
                } else if (result && result.then) {
                    result.then(function (dataURI) {
                        deferred.resolve(dataURI);
                    }, function () {
                        deferred.reject();
                    });
                }
                return deferred.promise();
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.ooxml', ['ooxml/main'], f);
}(function () {
    var __meta__ = {
        id: 'ooxml',
        name: 'XLSX generation',
        category: 'framework',
        advanced: true,
        depends: ['core']
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('excel/kendo-excel', ['kendo.core'], f);
}(function () {
    (function ($) {
        window.kendo.excel = window.kendo.excel || {};
        var getter = kendo.getter;
        var map = $.map;
        var current = {
            compile: function (template) {
                return template;
            }
        };
        var TemplateService = kendo.Class.extend({});
        TemplateService.register = function (userImplementation) {
            current = userImplementation;
        };
        TemplateService.compile = function (template) {
            return current.compile(template);
        };
        function defaultGroupHeaderTemplate(data) {
            return data.title + ': ' + data.value;
        }
        function createArray(length, callback) {
            var result = [];
            for (var idx = 0; idx < length; idx++) {
                result.push(callback(idx));
            }
            return result;
        }
        var ExcelExporter = kendo.Class.extend({
            init: function (options) {
                options.columns = this._trimColumns(options.columns || []);
                this.allColumns = map(this._leafColumns(options.columns || []), this._prepareColumn);
                this.columns = this.allColumns.filter(function (column) {
                    return !column.hidden;
                });
                this.options = options;
                this.data = options.data || [];
                this.aggregates = options.aggregates || {};
                this.groups = [].concat(options.groups || []);
                this.hierarchy = options.hierarchy;
            },
            workbook: function () {
                var workbook = {
                    sheets: [{
                            columns: this._columns(),
                            rows: this.hierarchy ? this._hierarchyRows() : this._rows(),
                            freezePane: this._freezePane(),
                            filter: this._filter()
                        }]
                };
                return workbook;
            },
            _trimColumns: function (columns) {
                var this$1 = this;
                return columns.filter(function (column) {
                    var result = Boolean(column.field);
                    if (!result && column.columns) {
                        result = this$1._trimColumns(column.columns).length > 0;
                    }
                    return result;
                });
            },
            _leafColumns: function (columns) {
                var this$1 = this;
                var result = [];
                for (var idx = 0; idx < columns.length; idx++) {
                    if (!columns[idx].columns) {
                        result.push(columns[idx]);
                    } else {
                        result = result.concat(this$1._leafColumns(columns[idx].columns));
                    }
                }
                return result;
            },
            _prepareColumn: function (column) {
                if (!column.field) {
                    return null;
                }
                var value = function (dataItem) {
                    return getter(column.field, true)(dataItem);
                };
                var values = null;
                if (column.values) {
                    values = {};
                    column.values.forEach(function (item) {
                        values[item.value] = item.text;
                    });
                    value = function (dataItem) {
                        return values[getter(column.field, true)(dataItem)];
                    };
                }
                return $.extend({}, column, {
                    value: value,
                    values: values,
                    groupHeaderTemplate: column.groupHeaderTemplate ? TemplateService.compile(column.groupHeaderTemplate) : defaultGroupHeaderTemplate,
                    groupFooterTemplate: column.groupFooterTemplate ? TemplateService.compile(column.groupFooterTemplate) : null,
                    footerTemplate: column.footerTemplate ? TemplateService.compile(column.footerTemplate) : null
                });
            },
            _filter: function () {
                if (!this.options.filterable) {
                    return null;
                }
                var depth = this._depth();
                return {
                    from: depth,
                    to: depth + this.columns.length - 1
                };
            },
            _createPaddingCells: function (length) {
                var this$1 = this;
                return createArray(length, function () {
                    return $.extend({
                        background: '#dfdfdf',
                        color: '#333'
                    }, this$1.options.paddingCellOptions);
                });
            },
            _dataRow: function (dataItem, level, depth) {
                var this$1 = this;
                var cells = this._createPaddingCells(level);
                if (depth && dataItem.items) {
                    var column = this.allColumns.filter(function (column) {
                        return column.field === dataItem.field;
                    })[0];
                    var title = column && column.title ? column.title : dataItem.field;
                    var template = column ? column.groupHeaderTemplate : null;
                    var group = $.extend({
                        title: title,
                        field: dataItem.field,
                        value: column && column.values ? column.values[dataItem.value] : dataItem.value,
                        aggregates: dataItem.aggregates,
                        items: dataItem.items
                    }, dataItem.aggregates[dataItem.field]);
                    var value = title + ': ' + dataItem.value;
                    if (template) {
                        value = template(group);
                    }
                    cells.push($.extend({
                        value: value,
                        background: '#dfdfdf',
                        color: '#333',
                        colSpan: this.columns.length + depth - level
                    }, (column || {}).groupHeaderCellOptions));
                    var rows = this._dataRows(dataItem.items, level + 1);
                    rows.unshift({
                        type: 'group-header',
                        cells: cells,
                        level: this.options.collapsible ? level : null
                    });
                    return rows.concat(this._footer(dataItem, level));
                }
                var dataCells = [];
                for (var cellIdx = 0; cellIdx < this.columns.length; cellIdx++) {
                    dataCells[cellIdx] = this$1._cell(dataItem, this$1.columns[cellIdx]);
                }
                if (this.hierarchy) {
                    dataCells[0].colSpan = depth - level + 1;
                }
                return [{
                        type: 'data',
                        cells: cells.concat(dataCells),
                        level: this.options.collapsible ? level : null
                    }];
            },
            _dataRows: function (dataItems, level) {
                var this$1 = this;
                var depth = this._depth();
                var rows = [];
                for (var idx = 0; idx < dataItems.length; idx++) {
                    rows.push.apply(rows, this$1._dataRow(dataItems[idx], level, depth));
                }
                return rows;
            },
            _hierarchyRows: function () {
                var this$1 = this;
                var depth = this._depth();
                var data = this.data;
                var itemLevel = this.hierarchy.itemLevel;
                var hasFooter = this._hasFooterTemplate();
                var rows = [];
                var parents = [];
                var previousLevel = 0;
                var previousItemId;
                for (var idx = 0; idx < data.length; idx++) {
                    var item = data[idx];
                    var level = itemLevel(item);
                    if (hasFooter) {
                        if (level > previousLevel) {
                            parents.push({
                                id: previousItemId,
                                level: previousLevel
                            });
                        } else if (level < previousLevel) {
                            rows.push.apply(rows, this$1._hierarchyFooterRows(parents, level, depth));
                        }
                        previousLevel = level;
                        previousItemId = item.id;
                    }
                    rows.push.apply(rows, this$1._dataRow(item, level + 1, depth));
                }
                if (hasFooter) {
                    rows.push.apply(rows, this._hierarchyFooterRows(parents, 0, depth));
                    var rootAggregate = data.length ? this.aggregates[data[0].parentId] : {};
                    rows.push(this._hierarchyFooter(rootAggregate, 0, depth));
                }
                this._prependHeaderRows(rows);
                return rows;
            },
            _hierarchyFooterRows: function (parents, currentLevel, depth) {
                var this$1 = this;
                var rows = [];
                while (parents.length && parents[parents.length - 1].level >= currentLevel) {
                    var parent = parents.pop();
                    rows.push(this$1._hierarchyFooter(this$1.aggregates[parent.id], parent.level + 1, depth));
                }
                return rows;
            },
            _hasFooterTemplate: function () {
                var columns = this.columns;
                for (var idx = 0; idx < columns.length; idx++) {
                    if (columns[idx].footerTemplate) {
                        return true;
                    }
                }
            },
            _hierarchyFooter: function (aggregates, level, depth) {
                var cells = this.columns.map(function (column, index) {
                    var colSpan = index ? 1 : depth - level + 1;
                    if (column.footerTemplate) {
                        return $.extend({
                            background: '#dfdfdf',
                            color: '#333',
                            colSpan: colSpan,
                            value: column.footerTemplate($.extend({}, (aggregates || {})[column.field]))
                        }, column.footerCellOptions);
                    }
                    return $.extend({
                        background: '#dfdfdf',
                        color: '#333',
                        colSpan: colSpan
                    }, column.footerCellOptions);
                });
                return {
                    type: 'footer',
                    cells: this._createPaddingCells(level).concat(cells)
                };
            },
            _footer: function (dataItem, level) {
                var rows = [];
                var footer = this.columns.some(function (column) {
                    return column.groupFooterTemplate;
                });
                var templateData, group;
                if (footer) {
                    group = {
                        group: {
                            items: dataItem.items,
                            field: dataItem.field,
                            value: dataItem.value
                        }
                    };
                    templateData = {};
                    Object.keys(dataItem.aggregates).forEach(function (key) {
                        templateData[key] = $.extend({}, dataItem.aggregates[key], group);
                    });
                }
                var cells = this.columns.map(function (column) {
                    if (column.groupFooterTemplate) {
                        var data = $.extend({}, templateData, dataItem.aggregates[column.field], group);
                        return $.extend({
                            background: '#dfdfdf',
                            color: '#333',
                            value: column.groupFooterTemplate(data)
                        }, column.groupFooterCellOptions);
                    }
                    return $.extend({
                        background: '#dfdfdf',
                        color: '#333'
                    }, column.groupFooterCellOptions);
                });
                if (footer) {
                    rows.push({
                        type: 'group-footer',
                        cells: this._createPaddingCells(this.groups.length).concat(cells),
                        level: this.options.collapsible ? level : null
                    });
                }
                return rows;
            },
            _isColumnVisible: function (column) {
                return this._visibleColumns([column]).length > 0 && (column.field || column.columns);
            },
            _visibleColumns: function (columns) {
                var this$1 = this;
                return columns.filter(function (column) {
                    var result = !column.hidden;
                    if (result && column.columns) {
                        result = this$1._visibleColumns(column.columns).length > 0;
                    }
                    return result;
                });
            },
            _headerRow: function (row, groups) {
                var this$1 = this;
                var headers = row.cells.map(function (cell) {
                    return $.extend(cell, {
                        colSpan: cell.colSpan > 1 ? cell.colSpan : 1,
                        rowSpan: row.rowSpan > 1 && !cell.colSpan ? row.rowSpan : 1
                    });
                });
                if (this.hierarchy) {
                    headers[0].colSpan = this._depth() + 1;
                }
                return {
                    type: 'header',
                    cells: createArray(groups.length, function () {
                        return $.extend({
                            background: '#7a7a7a',
                            color: '#fff'
                        }, this$1.options.headerPaddingCellOptions);
                    }).concat(headers)
                };
            },
            _prependHeaderRows: function (rows) {
                var this$1 = this;
                var groups = this.groups;
                var headerRows = [{
                        rowSpan: 1,
                        cells: [],
                        index: 0
                    }];
                this._prepareHeaderRows(headerRows, this.options.columns);
                for (var idx = headerRows.length - 1; idx >= 0; idx--) {
                    rows.unshift(this$1._headerRow(headerRows[idx], groups));
                }
            },
            _prepareHeaderRows: function (rows, columns, parentCell, parentRow) {
                var this$1 = this;
                var row = parentRow || rows[rows.length - 1];
                var childRow = rows[row.index + 1];
                var totalColSpan = 0;
                for (var idx = 0; idx < columns.length; idx++) {
                    var column = columns[idx];
                    if (this$1._isColumnVisible(column)) {
                        var cell = $.extend({
                            background: '#7a7a7a',
                            color: '#fff',
                            value: column.title || column.field,
                            colSpan: 0
                        }, column.headerCellOptions);
                        row.cells.push(cell);
                        if (column.columns && column.columns.length) {
                            if (!childRow) {
                                childRow = {
                                    rowSpan: 0,
                                    cells: [],
                                    index: rows.length
                                };
                                rows.push(childRow);
                            }
                            cell.colSpan = this$1._trimColumns(this$1._visibleColumns(column.columns)).length;
                            this$1._prepareHeaderRows(rows, column.columns, cell, childRow);
                            totalColSpan += cell.colSpan - 1;
                            row.rowSpan = rows.length - row.index;
                        }
                    }
                }
                if (parentCell) {
                    parentCell.colSpan += totalColSpan;
                }
            },
            _rows: function () {
                var this$1 = this;
                var rows = this._dataRows(this.data, 0);
                if (this.columns.length) {
                    this._prependHeaderRows(rows);
                    var footer = false;
                    var cells = this.columns.map(function (column) {
                        if (column.footerTemplate) {
                            footer = true;
                            return $.extend({
                                background: '#dfdfdf',
                                color: '#333',
                                value: column.footerTemplate($.extend({}, this$1.aggregates, this$1.aggregates[column.field]))
                            }, column.footerCellOptions);
                        }
                        return $.extend({
                            background: '#dfdfdf',
                            color: '#333'
                        }, column.footerCellOptions);
                    });
                    if (footer) {
                        rows.push({
                            type: 'footer',
                            cells: this._createPaddingCells(this.groups.length).concat(cells)
                        });
                    }
                }
                return rows;
            },
            _headerDepth: function (columns) {
                var this$1 = this;
                var result = 1;
                var max = 0;
                for (var idx = 0; idx < columns.length; idx++) {
                    if (columns[idx].columns) {
                        var temp = this$1._headerDepth(columns[idx].columns);
                        if (temp > max) {
                            max = temp;
                        }
                    }
                }
                return result + max;
            },
            _freezePane: function () {
                var columns = this._visibleColumns(this.options.columns || []);
                var colSplit = this._visibleColumns(this._trimColumns(this._leafColumns(columns.filter(function (column) {
                    return column.locked;
                })))).length;
                return {
                    rowSplit: this._headerDepth(columns),
                    colSplit: colSplit ? colSplit + this.groups.length : 0
                };
            },
            _cell: function (dataItem, column) {
                return $.extend({ value: column.value(dataItem) }, column.cellOptions);
            },
            _depth: function () {
                var depth = 0;
                if (this.hierarchy) {
                    depth = this.hierarchy.depth;
                } else {
                    depth = this.groups.length;
                }
                return depth;
            },
            _columns: function () {
                var depth = this._depth();
                var columns = createArray(depth, function () {
                    return { width: 20 };
                });
                return columns.concat(this.columns.map(function (column) {
                    return {
                        width: parseInt(column.width, 10),
                        autoWidth: column.width ? false : true
                    };
                }));
            }
        });
        kendo.deepExtend(kendo.excel, {
            ExcelExporter: ExcelExporter,
            TemplateService: TemplateService
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('excel/main', [
        'kendo.core',
        'kendo.data',
        'excel/kendo-excel'
    ], f);
}(function () {
    (function ($, kendo) {
        var ExcelExporter = kendo.excel.ExcelExporter;
        var extend = $.extend;
        kendo.excel.TemplateService.register({ compile: kendo.template });
        kendo.ExcelExporter = kendo.Class.extend({
            init: function (options) {
                this.options = options;
                var dataSource = options.dataSource;
                if (dataSource instanceof kendo.data.DataSource) {
                    if (!dataSource.filter()) {
                        dataSource.options.filter = undefined;
                    }
                    this.dataSource = new dataSource.constructor(extend({}, dataSource.options, {
                        page: options.allPages ? 0 : dataSource.page(),
                        filter: dataSource.filter(),
                        pageSize: options.allPages ? dataSource.total() : dataSource.pageSize() || dataSource.total(),
                        sort: dataSource.sort(),
                        group: dataSource.group(),
                        aggregate: dataSource.aggregate()
                    }));
                    var data = dataSource.data();
                    if (data.length > 0) {
                        if (options.hierarchy) {
                            for (var i = 0; i < data.length; i++) {
                                if (data[i].expanded === false || data[i].expanded === undefined) {
                                    data[i].expanded = true;
                                }
                            }
                        }
                        this.dataSource._data = data;
                        var transport = this.dataSource.transport;
                        if (dataSource._isServerGrouped() && transport.options && transport.options.data) {
                            transport.options.data = null;
                        }
                    }
                } else {
                    this.dataSource = kendo.data.DataSource.create(dataSource);
                }
            },
            _hierarchy: function () {
                var hierarchy = this.options.hierarchy;
                var dataSource = this.dataSource;
                if (hierarchy && dataSource.level) {
                    hierarchy = {
                        itemLevel: function (item) {
                            return dataSource.level(item);
                        }
                    };
                    var view = dataSource.view();
                    var depth = 0;
                    var level;
                    for (var idx = 0; idx < view.length; idx++) {
                        level = dataSource.level(view[idx]);
                        if (level > depth) {
                            depth = level;
                        }
                    }
                    hierarchy.depth = depth + 1;
                } else {
                    hierarchy = false;
                }
                return { hierarchy: hierarchy };
            },
            workbook: function () {
                return $.Deferred($.proxy(function (d) {
                    this.dataSource.fetch().then($.proxy(function () {
                        var workbook = new ExcelExporter(extend({}, this.options, this._hierarchy(), {
                            data: this.dataSource.view(),
                            groups: this.dataSource.group(),
                            aggregates: this.dataSource.aggregates()
                        })).workbook();
                        d.resolve(workbook, this.dataSource.view());
                    }, this));
                }, this)).promise();
            }
        });
    }(kendo.jQuery, kendo));
    return kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('excel/mixins', [
        'excel/main',
        'kendo.ooxml'
    ], f);
}(function () {
    (function ($, kendo) {
        kendo.ExcelMixin = {
            extend: function (proto) {
                proto.events.push('excelExport');
                proto.options.excel = $.extend(proto.options.excel, this.options);
                proto.saveAsExcel = this.saveAsExcel;
            },
            options: {
                proxyURL: '',
                allPages: false,
                filterable: false,
                fileName: 'Export.xlsx',
                collapsible: false
            },
            saveAsExcel: function () {
                var excel = this.options.excel || {};
                var exporter = new kendo.ExcelExporter({
                    columns: this.columns,
                    dataSource: this.dataSource,
                    allPages: excel.allPages,
                    filterable: excel.filterable,
                    hierarchy: excel.hierarchy,
                    collapsible: excel.collapsible
                });
                exporter.workbook().then($.proxy(function (book, data) {
                    if (!this.trigger('excelExport', {
                            workbook: book,
                            data: data
                        })) {
                        var workbook = new kendo.ooxml.Workbook(book);
                        workbook.toDataURLAsync().then(function (dataURI) {
                            kendo.saveAs({
                                dataURI: dataURI,
                                fileName: book.fileName || excel.fileName,
                                proxyURL: excel.proxyURL,
                                forceProxy: excel.forceProxy
                            });
                        });
                    }
                }, this));
            }
        };
    }(kendo.jQuery, kendo));
    return kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.excel', [
        'excel/main',
        'excel/mixins'
    ], f);
}(function () {
    var __meta__ = {
        id: 'excel',
        name: 'Excel export',
        category: 'framework',
        advanced: true,
        mixin: true,
        depends: [
            'data',
            'ooxml'
        ]
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.data.signalr', ['kendo.data'], f);
}(function () {
    var __meta__ = {
        id: 'data.signalr',
        name: 'SignalR',
        category: 'framework',
        depends: ['data'],
        hidden: true
    };
    (function ($) {
        var kendo = window.kendo;
        var isFunction = kendo.isFunction;
        function isJQueryPromise(promise) {
            return promise && isFunction(promise.done) && isFunction(promise.fail);
        }
        function isNativePromise(promise) {
            return promise && isFunction(promise.then) && isFunction(promise.catch);
        }
        var transport = kendo.data.RemoteTransport.extend({
            init: function (options) {
                var signalr = options && options.signalr ? options.signalr : {};
                var promise = signalr.promise;
                if (!promise) {
                    throw new Error('The "promise" option must be set.');
                }
                if (!isJQueryPromise(promise) && !isNativePromise(promise)) {
                    throw new Error('The "promise" option must be a Promise.');
                }
                this.promise = promise;
                var hub = signalr.hub;
                if (!hub) {
                    throw new Error('The "hub" option must be set.');
                }
                if (typeof hub.on != 'function' || typeof hub.invoke != 'function') {
                    throw new Error('The "hub" option is not a valid SignalR hub proxy.');
                }
                this.hub = hub;
                kendo.data.RemoteTransport.fn.init.call(this, options);
            },
            push: function (callbacks) {
                var client = this.options.signalr.client || {};
                if (client.create) {
                    this.hub.on(client.create, callbacks.pushCreate);
                }
                if (client.update) {
                    this.hub.on(client.update, callbacks.pushUpdate);
                }
                if (client.destroy) {
                    this.hub.on(client.destroy, callbacks.pushDestroy);
                }
            },
            _crud: function (options, type) {
                var hub = this.hub;
                var promise = this.promise;
                var server = this.options.signalr.server;
                if (!server || !server[type]) {
                    throw new Error(kendo.format('The "server.{0}" option must be set.', type));
                }
                var args = [server[type]];
                var data = this.parameterMap(options.data, type);
                if (!$.isEmptyObject(data)) {
                    args.push(data);
                }
                if (isJQueryPromise(promise)) {
                    promise.done(function () {
                        hub.invoke.apply(hub, args).done(options.success).fail(options.error);
                    });
                } else if (isNativePromise(promise)) {
                    promise.then(function () {
                        hub.invoke.apply(hub, args).then(options.success).catch(options.error);
                    });
                }
            },
            read: function (options) {
                this._crud(options, 'read');
            },
            create: function (options) {
                this._crud(options, 'create');
            },
            update: function (options) {
                this._crud(options, 'update');
            },
            destroy: function (options) {
                this._crud(options, 'destroy');
            }
        });
        $.extend(true, kendo.data, { transports: { signalr: transport } });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/util', ['kendo.core'], f);
}(function () {
    (function ($) {
        function createPromise() {
            return $.Deferred();
        }
        function promiseAll(promises) {
            return $.when.apply($, promises);
        }
        kendo.drawing.util = kendo.drawing.util || {};
        kendo.deepExtend(kendo.drawing.util, {
            createPromise: createPromise,
            promiseAll: promiseAll
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.color', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'color',
        name: 'Color utils',
        category: 'framework',
        advanced: true,
        description: 'Color utilities used across components',
        depends: ['core']
    };
    window.kendo = window.kendo || {};
    var Class = kendo.Class;
    var support = kendo.support;
    var namedColors = {
        aliceblue: 'f0f8ff',
        antiquewhite: 'faebd7',
        aqua: '00ffff',
        aquamarine: '7fffd4',
        azure: 'f0ffff',
        beige: 'f5f5dc',
        bisque: 'ffe4c4',
        black: '000000',
        blanchedalmond: 'ffebcd',
        blue: '0000ff',
        blueviolet: '8a2be2',
        brown: 'a52a2a',
        burlywood: 'deb887',
        cadetblue: '5f9ea0',
        chartreuse: '7fff00',
        chocolate: 'd2691e',
        coral: 'ff7f50',
        cornflowerblue: '6495ed',
        cornsilk: 'fff8dc',
        crimson: 'dc143c',
        cyan: '00ffff',
        darkblue: '00008b',
        darkcyan: '008b8b',
        darkgoldenrod: 'b8860b',
        darkgray: 'a9a9a9',
        darkgrey: 'a9a9a9',
        darkgreen: '006400',
        darkkhaki: 'bdb76b',
        darkmagenta: '8b008b',
        darkolivegreen: '556b2f',
        darkorange: 'ff8c00',
        darkorchid: '9932cc',
        darkred: '8b0000',
        darksalmon: 'e9967a',
        darkseagreen: '8fbc8f',
        darkslateblue: '483d8b',
        darkslategray: '2f4f4f',
        darkslategrey: '2f4f4f',
        darkturquoise: '00ced1',
        darkviolet: '9400d3',
        deeppink: 'ff1493',
        deepskyblue: '00bfff',
        dimgray: '696969',
        dimgrey: '696969',
        dodgerblue: '1e90ff',
        firebrick: 'b22222',
        floralwhite: 'fffaf0',
        forestgreen: '228b22',
        fuchsia: 'ff00ff',
        gainsboro: 'dcdcdc',
        ghostwhite: 'f8f8ff',
        gold: 'ffd700',
        goldenrod: 'daa520',
        gray: '808080',
        grey: '808080',
        green: '008000',
        greenyellow: 'adff2f',
        honeydew: 'f0fff0',
        hotpink: 'ff69b4',
        indianred: 'cd5c5c',
        indigo: '4b0082',
        ivory: 'fffff0',
        khaki: 'f0e68c',
        lavender: 'e6e6fa',
        lavenderblush: 'fff0f5',
        lawngreen: '7cfc00',
        lemonchiffon: 'fffacd',
        lightblue: 'add8e6',
        lightcoral: 'f08080',
        lightcyan: 'e0ffff',
        lightgoldenrodyellow: 'fafad2',
        lightgray: 'd3d3d3',
        lightgrey: 'd3d3d3',
        lightgreen: '90ee90',
        lightpink: 'ffb6c1',
        lightsalmon: 'ffa07a',
        lightseagreen: '20b2aa',
        lightskyblue: '87cefa',
        lightslategray: '778899',
        lightslategrey: '778899',
        lightsteelblue: 'b0c4de',
        lightyellow: 'ffffe0',
        lime: '00ff00',
        limegreen: '32cd32',
        linen: 'faf0e6',
        magenta: 'ff00ff',
        maroon: '800000',
        mediumaquamarine: '66cdaa',
        mediumblue: '0000cd',
        mediumorchid: 'ba55d3',
        mediumpurple: '9370d8',
        mediumseagreen: '3cb371',
        mediumslateblue: '7b68ee',
        mediumspringgreen: '00fa9a',
        mediumturquoise: '48d1cc',
        mediumvioletred: 'c71585',
        midnightblue: '191970',
        mintcream: 'f5fffa',
        mistyrose: 'ffe4e1',
        moccasin: 'ffe4b5',
        navajowhite: 'ffdead',
        navy: '000080',
        oldlace: 'fdf5e6',
        olive: '808000',
        olivedrab: '6b8e23',
        orange: 'ffa500',
        orangered: 'ff4500',
        orchid: 'da70d6',
        palegoldenrod: 'eee8aa',
        palegreen: '98fb98',
        paleturquoise: 'afeeee',
        palevioletred: 'd87093',
        papayawhip: 'ffefd5',
        peachpuff: 'ffdab9',
        peru: 'cd853f',
        pink: 'ffc0cb',
        plum: 'dda0dd',
        powderblue: 'b0e0e6',
        purple: '800080',
        red: 'ff0000',
        rosybrown: 'bc8f8f',
        royalblue: '4169e1',
        saddlebrown: '8b4513',
        salmon: 'fa8072',
        sandybrown: 'f4a460',
        seagreen: '2e8b57',
        seashell: 'fff5ee',
        sienna: 'a0522d',
        silver: 'c0c0c0',
        skyblue: '87ceeb',
        slateblue: '6a5acd',
        slategray: '708090',
        slategrey: '708090',
        snow: 'fffafa',
        springgreen: '00ff7f',
        steelblue: '4682b4',
        tan: 'd2b48c',
        teal: '008080',
        thistle: 'd8bfd8',
        tomato: 'ff6347',
        turquoise: '40e0d0',
        violet: 'ee82ee',
        wheat: 'f5deb3',
        white: 'ffffff',
        whitesmoke: 'f5f5f5',
        yellow: 'ffff00',
        yellowgreen: '9acd32'
    };
    var browser = support.browser;
    var matchNamedColor = function (color) {
        var colorNames = Object.keys(namedColors);
        colorNames.push('transparent');
        var regexp = new RegExp('^(' + colorNames.join('|') + ')(\\W|$)', 'i');
        matchNamedColor = function (color) {
            return regexp.exec(color);
        };
        return regexp.exec(color);
    };
    var BaseColor = Class.extend({
        init: function () {
        },
        toHSV: function () {
            return this;
        },
        toRGB: function () {
            return this;
        },
        toHex: function () {
            return this.toBytes().toHex();
        },
        toBytes: function () {
            return this;
        },
        toCss: function () {
            return '#' + this.toHex();
        },
        toCssRgba: function () {
            var rgb = this.toBytes();
            return 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + parseFloat(Number(this.a).toFixed(3)) + ')';
        },
        toDisplay: function () {
            if (browser.msie && browser.version < 9) {
                return this.toCss();
            }
            return this.toCssRgba();
        },
        equals: function (c) {
            return c === this || c !== null && this.toCssRgba() === parseColor(c).toCssRgba();
        },
        diff: function (other) {
            if (other === null) {
                return NaN;
            }
            var c1 = this.toBytes();
            var c2 = other.toBytes();
            return Math.sqrt(Math.pow((c1.r - c2.r) * 0.3, 2) + Math.pow((c1.g - c2.g) * 0.59, 2) + Math.pow((c1.b - c2.b) * 0.11, 2));
        },
        clone: function () {
            var c = this.toBytes();
            if (c === this) {
                c = new Bytes(c.r, c.g, c.b, c.a);
            }
            return c;
        }
    });
    var RGB = BaseColor.extend({
        init: function (r, g, b, a) {
            BaseColor.fn.init.call(this);
            this.r = r;
            this.g = g;
            this.b = b;
            this.a = a;
        },
        toHSV: function () {
            var ref = this;
            var r = ref.r;
            var g = ref.g;
            var b = ref.b;
            var min = Math.min(r, g, b);
            var max = Math.max(r, g, b);
            var delta = max - min;
            var v = max;
            var h, s;
            if (delta === 0) {
                return new HSV(0, 0, v, this.a);
            }
            if (max !== 0) {
                s = delta / max;
                if (r === max) {
                    h = (g - b) / delta;
                } else if (g === max) {
                    h = 2 + (b - r) / delta;
                } else {
                    h = 4 + (r - g) / delta;
                }
                h *= 60;
                if (h < 0) {
                    h += 360;
                }
            } else {
                s = 0;
                h = -1;
            }
            return new HSV(h, s, v, this.a);
        },
        toHSL: function () {
            var ref = this;
            var r = ref.r;
            var g = ref.g;
            var b = ref.b;
            var max = Math.max(r, g, b);
            var min = Math.min(r, g, b);
            var h, s, l = (max + min) / 2;
            if (max === min) {
                h = s = 0;
            } else {
                var d = max - min;
                s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
                switch (max) {
                case r:
                    h = (g - b) / d + (g < b ? 6 : 0);
                    break;
                case g:
                    h = (b - r) / d + 2;
                    break;
                case b:
                    h = (r - g) / d + 4;
                    break;
                default:
                    break;
                }
            }
            return new HSL(h * 60, s * 100, l * 100, this.a);
        },
        toBytes: function () {
            return new Bytes(this.r * 255, this.g * 255, this.b * 255, this.a);
        }
    });
    var Bytes = RGB.extend({
        init: function (r, g, b, a) {
            RGB.fn.init.call(this, Math.round(r), Math.round(g), Math.round(b), a);
        },
        toRGB: function () {
            return new RGB(this.r / 255, this.g / 255, this.b / 255, this.a);
        },
        toHSV: function () {
            return this.toRGB().toHSV();
        },
        toHSL: function () {
            return this.toRGB().toHSL();
        },
        toHex: function () {
            return hex(this.r, 2) + hex(this.g, 2) + hex(this.b, 2);
        },
        toBytes: function () {
            return this;
        }
    });
    function hex(n, width, pad) {
        if (pad === void 0) {
            pad = '0';
        }
        var result = n.toString(16);
        while (width > result.length) {
            result = pad + result;
        }
        return result;
    }
    var HSV = BaseColor.extend({
        init: function (h, s, v, a) {
            BaseColor.fn.init.call(this);
            this.h = h;
            this.s = s;
            this.v = v;
            this.a = a;
        },
        toRGB: function () {
            var ref = this;
            var h = ref.h;
            var s = ref.s;
            var v = ref.v;
            var r, g, b;
            if (s === 0) {
                r = g = b = v;
            } else {
                h /= 60;
                var i = Math.floor(h);
                var f = h - i;
                var p = v * (1 - s);
                var q = v * (1 - s * f);
                var t = v * (1 - s * (1 - f));
                switch (i) {
                case 0:
                    r = v;
                    g = t;
                    b = p;
                    break;
                case 1:
                    r = q;
                    g = v;
                    b = p;
                    break;
                case 2:
                    r = p;
                    g = v;
                    b = t;
                    break;
                case 3:
                    r = p;
                    g = q;
                    b = v;
                    break;
                case 4:
                    r = t;
                    g = p;
                    b = v;
                    break;
                default:
                    r = v;
                    g = p;
                    b = q;
                    break;
                }
            }
            return new RGB(r, g, b, this.a);
        },
        toHSL: function () {
            return this.toRGB().toHSL();
        },
        toBytes: function () {
            return this.toRGB().toBytes();
        }
    });
    var HSL = BaseColor.extend({
        init: function (h, s, l, a) {
            BaseColor.fn.init.call(this);
            this.h = h;
            this.s = s;
            this.l = l;
            this.a = a;
        },
        toRGB: function () {
            var h = this.h / 360;
            var s = this.s / 100;
            var l = this.l / 100;
            var r, g, b;
            if (s === 0) {
                r = g = b = l;
            } else {
                var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
                var p = 2 * l - q;
                r = hue2rgb(p, q, h + 1 / 3);
                g = hue2rgb(p, q, h);
                b = hue2rgb(p, q, h - 1 / 3);
            }
            return new RGB(r, g, b, this.a);
        },
        toHSV: function () {
            return this.toRGB().toHSV();
        },
        toBytes: function () {
            return this.toRGB().toBytes();
        }
    });
    function hue2rgb(p, q, s) {
        var t = s;
        if (t < 0) {
            t += 1;
        }
        if (t > 1) {
            t -= 1;
        }
        if (t < 1 / 6) {
            return p + (q - p) * 6 * t;
        }
        if (t < 1 / 2) {
            return q;
        }
        if (t < 2 / 3) {
            return p + (q - p) * (2 / 3 - t) * 6;
        }
        return p;
    }
    function parseColor(value, safe) {
        var m, ret;
        if (value == null || value === 'none') {
            return null;
        }
        if (value instanceof BaseColor) {
            return value;
        }
        var color = value.toLowerCase();
        if (m = matchNamedColor(color)) {
            if (m[1] === 'transparent') {
                color = new RGB(1, 1, 1, 0);
            } else {
                color = parseColor(namedColors[m[1]], safe);
            }
            color.match = [m[1]];
            return color;
        }
        if (m = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})\b/i.exec(color)) {
            ret = new Bytes(parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16), 1);
        } else if (m = /^#?([0-9a-f])([0-9a-f])([0-9a-f])\b/i.exec(color)) {
            ret = new Bytes(parseInt(m[1] + m[1], 16), parseInt(m[2] + m[2], 16), parseInt(m[3] + m[3], 16), 1);
        } else if (m = /^rgb\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/.exec(color)) {
            ret = new Bytes(parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10), 1);
        } else if (m = /^rgba\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9.]+)\s*\)/.exec(color)) {
            ret = new Bytes(parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10), parseFloat(m[4]));
        } else if (m = /^rgb\(\s*([0-9]*\.?[0-9]+)%\s*,\s*([0-9]*\.?[0-9]+)%\s*,\s*([0-9]*\.?[0-9]+)%\s*\)/.exec(color)) {
            ret = new RGB(parseFloat(m[1]) / 100, parseFloat(m[2]) / 100, parseFloat(m[3]) / 100, 1);
        } else if (m = /^rgba\(\s*([0-9]*\.?[0-9]+)%\s*,\s*([0-9]*\.?[0-9]+)%\s*,\s*([0-9]*\.?[0-9]+)%\s*,\s*([0-9.]+)\s*\)/.exec(color)) {
            ret = new RGB(parseFloat(m[1]) / 100, parseFloat(m[2]) / 100, parseFloat(m[3]) / 100, parseFloat(m[4]));
        }
        if (ret) {
            ret.match = m;
        } else if (!safe) {
            throw new Error('Cannot parse color: ' + color);
        }
        return ret;
    }
    var Color = Class.extend({
        init: function (value) {
            var this$1 = this;
            if (arguments.length === 1) {
                var formats = Color.formats;
                var resolvedColor = this.resolveColor(value);
                for (var idx = 0; idx < formats.length; idx++) {
                    var formatRegex = formats[idx].re;
                    var processor = formats[idx].process;
                    var parts = formatRegex.exec(resolvedColor);
                    if (parts) {
                        var channels = processor(parts);
                        this$1.r = channels[0];
                        this$1.g = channels[1];
                        this$1.b = channels[2];
                    }
                }
            } else {
                this.r = arguments[0];
                this.g = arguments[1];
                this.b = arguments[2];
            }
            this.r = this.normalizeByte(this.r);
            this.g = this.normalizeByte(this.g);
            this.b = this.normalizeByte(this.b);
        },
        toHex: function () {
            var pad = this.padDigit;
            var r = this.r.toString(16);
            var g = this.g.toString(16);
            var b = this.b.toString(16);
            return '#' + pad(r) + pad(g) + pad(b);
        },
        resolveColor: function (value) {
            var color = value || 'black';
            if (color.charAt(0) === '#') {
                color = color.substr(1, 6);
            }
            color = color.replace(/ /g, '');
            color = color.toLowerCase();
            color = Color.namedColors[color] || color;
            return color;
        },
        normalizeByte: function (value) {
            if (value < 0 || isNaN(value)) {
                return 0;
            }
            return value > 255 ? 255 : value;
        },
        padDigit: function (value) {
            return value.length === 1 ? '0' + value : value;
        },
        brightness: function (value) {
            var round = Math.round;
            this.r = round(this.normalizeByte(this.r * value));
            this.g = round(this.normalizeByte(this.g * value));
            this.b = round(this.normalizeByte(this.b * value));
            return this;
        },
        percBrightness: function () {
            return Math.sqrt(0.241 * this.r * this.r + 0.691 * this.g * this.g + 0.068 * this.b * this.b);
        }
    });
    Color.fromBytes = function (r, g, b, a) {
        return new Bytes(r, g, b, a != null ? a : 1);
    };
    Color.fromRGB = function (r, g, b, a) {
        return new RGB(r, g, b, a != null ? a : 1);
    };
    Color.fromHSV = function (h, s, v, a) {
        return new HSV(h, s, v, a != null ? a : 1);
    };
    Color.fromHSL = function (h, s, l, a) {
        return new HSL(h, s, l, a != null ? a : 1);
    };
    Color.formats = [
        {
            re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
            process: function (parts) {
                return [
                    parseInt(parts[1], 10),
                    parseInt(parts[2], 10),
                    parseInt(parts[3], 10)
                ];
            }
        },
        {
            re: /^(\w{2})(\w{2})(\w{2})$/,
            process: function (parts) {
                return [
                    parseInt(parts[1], 16),
                    parseInt(parts[2], 16),
                    parseInt(parts[3], 16)
                ];
            }
        },
        {
            re: /^(\w{1})(\w{1})(\w{1})$/,
            process: function (parts) {
                return [
                    parseInt(parts[1] + parts[1], 16),
                    parseInt(parts[2] + parts[2], 16),
                    parseInt(parts[3] + parts[3], 16)
                ];
            }
        }
    ];
    Color.namedColors = namedColors;
    kendo.deepExtend(kendo, {
        parseColor: parseColor,
        Color: Color
    });
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/text-metrics', ['kendo.core'], f);
}(function () {
    (function ($) {
        window.kendo.util = window.kendo.util || {};
        var LRUCache = kendo.Class.extend({
            init: function (size) {
                this._size = size;
                this._length = 0;
                this._map = {};
            },
            put: function (key, value) {
                var map = this._map;
                var entry = {
                    key: key,
                    value: value
                };
                map[key] = entry;
                if (!this._head) {
                    this._head = this._tail = entry;
                } else {
                    this._tail.newer = entry;
                    entry.older = this._tail;
                    this._tail = entry;
                }
                if (this._length >= this._size) {
                    map[this._head.key] = null;
                    this._head = this._head.newer;
                    this._head.older = null;
                } else {
                    this._length++;
                }
            },
            get: function (key) {
                var entry = this._map[key];
                if (entry) {
                    if (entry === this._head && entry !== this._tail) {
                        this._head = entry.newer;
                        this._head.older = null;
                    }
                    if (entry !== this._tail) {
                        if (entry.older) {
                            entry.older.newer = entry.newer;
                            entry.newer.older = entry.older;
                        }
                        entry.older = this._tail;
                        entry.newer = null;
                        this._tail.newer = entry;
                        this._tail = entry;
                    }
                    return entry.value;
                }
            }
        });
        var REPLACE_REGEX = /\r?\n|\r|\t/g;
        var SPACE = ' ';
        function normalizeText(text) {
            return String(text).replace(REPLACE_REGEX, SPACE);
        }
        function objectKey(object) {
            var parts = [];
            for (var key in object) {
                parts.push(key + object[key]);
            }
            return parts.sort().join('');
        }
        function hashKey(str) {
            var hash = 2166136261;
            for (var i = 0; i < str.length; ++i) {
                hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
                hash ^= str.charCodeAt(i);
            }
            return hash >>> 0;
        }
        function zeroSize() {
            return {
                width: 0,
                height: 0,
                baseline: 0
            };
        }
        var DEFAULT_OPTIONS = { baselineMarkerSize: 1 };
        var defaultMeasureBox;
        if (typeof document !== 'undefined') {
            defaultMeasureBox = document.createElement('div');
            defaultMeasureBox.style.cssText = 'position: absolute !important; top: -4000px !important; width: auto !important; height: auto !important;' + 'padding: 0 !important; margin: 0 !important; border: 0 !important;' + 'line-height: normal !important; visibility: hidden !important; white-space: pre!important;';
        }
        var TextMetrics = kendo.Class.extend({
            init: function (options) {
                this._cache = new LRUCache(1000);
                this.options = $.extend({}, DEFAULT_OPTIONS, options);
            },
            measure: function (text, style, options) {
                if (options === void 0) {
                    options = {};
                }
                if (!text) {
                    return zeroSize();
                }
                var styleKey = objectKey(style);
                var cacheKey = hashKey(text + styleKey);
                var cachedResult = this._cache.get(cacheKey);
                if (cachedResult) {
                    return cachedResult;
                }
                var size = zeroSize();
                var measureBox = options.box || defaultMeasureBox;
                var baselineMarker = this._baselineMarker().cloneNode(false);
                for (var key in style) {
                    var value = style[key];
                    if (typeof value !== 'undefined') {
                        measureBox.style[key] = value;
                    }
                }
                var textStr = options.normalizeText !== false ? normalizeText(text) : String(text);
                measureBox.textContent = textStr;
                measureBox.appendChild(baselineMarker);
                document.body.appendChild(measureBox);
                if (textStr.length) {
                    size.width = measureBox.offsetWidth - this.options.baselineMarkerSize;
                    size.height = measureBox.offsetHeight;
                    size.baseline = baselineMarker.offsetTop + this.options.baselineMarkerSize;
                }
                if (size.width > 0 && size.height > 0) {
                    this._cache.put(cacheKey, size);
                }
                measureBox.parentNode.removeChild(measureBox);
                return size;
            },
            _baselineMarker: function () {
                var marker = document.createElement('div');
                marker.style.cssText = 'display: inline-block; vertical-align: baseline;width: ' + this.options.baselineMarkerSize + 'px; height: ' + this.options.baselineMarkerSize + 'px;overflow: hidden;';
                return marker;
            }
        });
        TextMetrics.current = new TextMetrics();
        function measureText(text, style, measureBox) {
            return TextMetrics.current.measure(text, style, measureBox);
        }
        kendo.deepExtend(kendo.util, {
            LRUCache: LRUCache,
            TextMetrics: TextMetrics,
            measureText: measureText,
            objectKey: objectKey,
            hashKey: hashKey,
            normalizeText: normalizeText
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/kendo-drawing', [
        'drawing/util',
        'kendo.color',
        'util/text-metrics'
    ], f);
}(function () {
    (function ($) {
        window.kendo = window.kendo || {};
        var kendoDrawing = kendo.drawing;
        var kendoDrawingUtil = kendoDrawing.util;
        var Class = kendo.Class;
        var kendoUtil = kendo.util;
        var support = kendo.support;
        var supportBrowser = support.browser;
        var createPromise = kendoDrawingUtil.createPromise;
        var promiseAll = kendoDrawingUtil.promiseAll;
        var ObserversMixin = {
            extend: function (proto) {
                var this$1 = this;
                for (var method in this) {
                    if (method !== 'extend') {
                        proto[method] = this$1[method];
                    }
                }
            },
            observers: function () {
                this._observers = this._observers || [];
                return this._observers;
            },
            addObserver: function (element) {
                if (!this._observers) {
                    this._observers = [element];
                } else {
                    this._observers.push(element);
                }
                return this;
            },
            removeObserver: function (element) {
                var observers = this.observers();
                var index = observers.indexOf(element);
                if (index !== -1) {
                    observers.splice(index, 1);
                }
                return this;
            },
            trigger: function (methodName, event) {
                var observers = this._observers;
                if (observers && !this._suspended) {
                    for (var idx = 0; idx < observers.length; idx++) {
                        var observer = observers[idx];
                        if (observer[methodName]) {
                            observer[methodName](event);
                        }
                    }
                }
                return this;
            },
            optionsChange: function (e) {
                if (e === void 0) {
                    e = {};
                }
                e.element = this;
                this.trigger('optionsChange', e);
            },
            geometryChange: function () {
                this.trigger('geometryChange', { element: this });
            },
            suspend: function () {
                this._suspended = (this._suspended || 0) + 1;
                return this;
            },
            resume: function () {
                this._suspended = Math.max((this._suspended || 0) - 1, 0);
                return this;
            },
            _observerField: function (field, value) {
                if (this[field]) {
                    this[field].removeObserver(this);
                }
                this[field] = value;
                value.addObserver(this);
            }
        };
        function append(first, second) {
            first.push.apply(first, second);
            return first;
        }
        var literals = {
            1: 'i',
            10: 'x',
            100: 'c',
            2: 'ii',
            20: 'xx',
            200: 'cc',
            3: 'iii',
            30: 'xxx',
            300: 'ccc',
            4: 'iv',
            40: 'xl',
            400: 'cd',
            5: 'v',
            50: 'l',
            500: 'd',
            6: 'vi',
            60: 'lx',
            600: 'dc',
            7: 'vii',
            70: 'lxx',
            700: 'dcc',
            8: 'viii',
            80: 'lxxx',
            800: 'dccc',
            9: 'ix',
            90: 'xc',
            900: 'cm',
            1000: 'm'
        };
        function arabicToRoman(n) {
            var values = [
                1000,
                900,
                800,
                700,
                600,
                500,
                400,
                300,
                200,
                100,
                90,
                80,
                70,
                60,
                50,
                40,
                30,
                20,
                10,
                9,
                8,
                7,
                6,
                5,
                4,
                3,
                2,
                1
            ];
            var roman = '';
            while (n > 0) {
                if (n < values[0]) {
                    values.shift();
                } else {
                    roman += literals[values[0]];
                    n -= values[0];
                }
            }
            return roman;
        }
        var UNDEFINED = 'undefined';
        function defined(value) {
            return typeof value !== UNDEFINED;
        }
        var defId = 1;
        function definitionId() {
            return 'kdef' + defId++;
        }
        var DEG_TO_RAD = Math.PI / 180;
        var MAX_NUM = Number.MAX_VALUE;
        var MIN_NUM = -Number.MAX_VALUE;
        function deg(radians) {
            return radians / DEG_TO_RAD;
        }
        var KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        var fromCharCode = String.fromCharCode;
        function encodeUTF8(input) {
            var output = '';
            for (var i = 0; i < input.length; i++) {
                var c = input.charCodeAt(i);
                if (c < 128) {
                    output += fromCharCode(c);
                } else if (c < 2048) {
                    output += fromCharCode(192 | c >>> 6);
                    output += fromCharCode(128 | c & 63);
                } else if (c < 65536) {
                    output += fromCharCode(224 | c >>> 12);
                    output += fromCharCode(128 | c >>> 6 & 63);
                    output += fromCharCode(128 | c & 63);
                }
            }
            return output;
        }
        function encodeBase64(input) {
            var output = '';
            var i = 0;
            var utfInput = encodeUTF8(input);
            while (i < utfInput.length) {
                var chr1 = utfInput.charCodeAt(i++);
                var chr2 = utfInput.charCodeAt(i++);
                var chr3 = utfInput.charCodeAt(i++);
                var enc1 = chr1 >> 2;
                var enc2 = (chr1 & 3) << 4 | chr2 >> 4;
                var enc3 = (chr2 & 15) << 2 | chr3 >> 6;
                var enc4 = chr3 & 63;
                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }
                output = output + KEY_STR.charAt(enc1) + KEY_STR.charAt(enc2) + KEY_STR.charAt(enc3) + KEY_STR.charAt(enc4);
            }
            return output;
        }
        function eventCoordinates(e) {
            if (defined((e.x || {}).location)) {
                return {
                    x: e.x.location,
                    y: e.y.location
                };
            }
            return {
                x: e.pageX || e.clientX || 0,
                y: e.pageY || e.clientY || 0
            };
        }
        function eventElement(e) {
            if (e === void 0) {
                e = {};
            }
            return e.touch ? e.touch.initialTouch : e.target;
        }
        function isTransparent(color) {
            return color === '' || color === null || color === 'none' || color === 'transparent' || !defined(color);
        }
        function last(array) {
            if (array) {
                return array[array.length - 1];
            }
        }
        function limitValue(value, min, max) {
            return Math.max(Math.min(value, max), min);
        }
        function mergeSort(a, cmp) {
            if (a.length < 2) {
                return a.slice();
            }
            function merge(a, b) {
                var r = [], ai = 0, bi = 0, i = 0;
                while (ai < a.length && bi < b.length) {
                    if (cmp(a[ai], b[bi]) <= 0) {
                        r[i++] = a[ai++];
                    } else {
                        r[i++] = b[bi++];
                    }
                }
                if (ai < a.length) {
                    r.push.apply(r, a.slice(ai));
                }
                if (bi < b.length) {
                    r.push.apply(r, b.slice(bi));
                }
                return r;
            }
            return function sort(a) {
                if (a.length <= 1) {
                    return a;
                }
                var m = Math.floor(a.length / 2);
                var left = a.slice(0, m);
                var right = a.slice(m);
                left = sort(left);
                right = sort(right);
                return merge(left, right);
            }(a);
        }
        function rad(degrees) {
            return degrees * DEG_TO_RAD;
        }
        function pow(p) {
            if (p) {
                return Math.pow(10, p);
            }
            return 1;
        }
        function round(value, precision) {
            var power = pow(precision);
            return Math.round(value * power) / power;
        }
        function valueOrDefault(value, defaultValue) {
            return defined(value) ? value : defaultValue;
        }
        function bindEvents(element, events) {
            for (var eventName in events) {
                var eventNames = eventName.trim().split(' ');
                for (var idx = 0; idx < eventNames.length; idx++) {
                    element.addEventListener(eventNames[idx], events[eventName], false);
                }
            }
        }
        function elementOffset(element) {
            var box = element.getBoundingClientRect();
            var documentElement = document.documentElement;
            return {
                top: box.top + (window.pageYOffset || documentElement.scrollTop) - (documentElement.clientTop || 0),
                left: box.left + (window.pageXOffset || documentElement.scrollLeft) - (documentElement.clientLeft || 0)
            };
        }
        function elementStyles(element, styles) {
            var result = {};
            var style = window.getComputedStyle(element) || {};
            var stylesArray = Array.isArray(styles) ? styles : [styles];
            for (var idx = 0; idx < stylesArray.length; idx++) {
                var field = stylesArray[idx];
                result[field] = style[field];
            }
            return result;
        }
        function getPixels(value) {
            if (isNaN(value)) {
                return value;
            }
            return value + 'px';
        }
        function elementSize(element, size) {
            if (size) {
                var width = size.width;
                var height = size.height;
                if (defined(width)) {
                    element.style.width = getPixels(width);
                }
                if (defined(height)) {
                    element.style.height = getPixels(height);
                }
            } else {
                var size$1 = elementStyles(element, [
                    'width',
                    'height'
                ]);
                return {
                    width: parseInt(size$1.width, 10),
                    height: parseInt(size$1.height, 10)
                };
            }
        }
        function unbindEvents(element, events) {
            if (events === void 0) {
                events = {};
            }
            for (var name in events) {
                var eventNames = name.trim().split(' ');
                for (var idx = 0; idx < eventNames.length; idx++) {
                    element.removeEventListener(eventNames[idx], events[name], false);
                }
            }
        }
        var util = {
            append: append,
            arabicToRoman: arabicToRoman,
            createPromise: createPromise,
            defined: defined,
            definitionId: definitionId,
            deg: deg,
            encodeBase64: encodeBase64,
            eventCoordinates: eventCoordinates,
            eventElement: eventElement,
            isTransparent: isTransparent,
            last: last,
            limitValue: limitValue,
            mergeSort: mergeSort,
            promiseAll: promiseAll,
            rad: rad,
            round: round,
            valueOrDefault: valueOrDefault,
            bindEvents: bindEvents,
            elementOffset: elementOffset,
            elementSize: elementSize,
            elementStyles: elementStyles,
            unbindEvents: unbindEvents,
            DEG_TO_RAD: DEG_TO_RAD,
            MAX_NUM: MAX_NUM,
            MIN_NUM: MIN_NUM
        };
        var toString = {}.toString;
        var OptionsStore = Class.extend({
            init: function (options, prefix) {
                var this$1 = this;
                if (prefix === void 0) {
                    prefix = '';
                }
                this.prefix = prefix;
                for (var field in options) {
                    var member = options[field];
                    member = this$1._wrap(member, field);
                    this$1[field] = member;
                }
            },
            get: function (field) {
                var parts = field.split('.');
                var result = this;
                while (parts.length && result) {
                    var part = parts.shift();
                    result = result[part];
                }
                return result;
            },
            set: function (field, value) {
                var current = this.get(field);
                if (current !== value) {
                    this._set(field, this._wrap(value, field));
                    this.optionsChange({
                        field: this.prefix + field,
                        value: value
                    });
                }
            },
            _set: function (field, value) {
                var this$1 = this;
                var composite = field.indexOf('.') >= 0;
                var parentObj = this;
                var fieldName = field;
                if (composite) {
                    var parts = fieldName.split('.');
                    var prefix = this.prefix;
                    while (parts.length > 1) {
                        fieldName = parts.shift();
                        prefix += fieldName + '.';
                        var obj = parentObj[fieldName];
                        if (!obj) {
                            obj = new OptionsStore({}, prefix);
                            obj.addObserver(this$1);
                            parentObj[fieldName] = obj;
                        }
                        parentObj = obj;
                    }
                    fieldName = parts[0];
                }
                parentObj._clear(fieldName);
                parentObj[fieldName] = value;
            },
            _clear: function (field) {
                var current = this[field];
                if (current && current.removeObserver) {
                    current.removeObserver(this);
                }
            },
            _wrap: function (object, field) {
                var type = toString.call(object);
                var wrapped = object;
                if (wrapped !== null && defined(wrapped) && type === '[object Object]') {
                    if (!(object instanceof OptionsStore) && !(object instanceof Class)) {
                        wrapped = new OptionsStore(wrapped, this.prefix + field + '.');
                    }
                    wrapped.addObserver(this);
                }
                return wrapped;
            }
        });
        ObserversMixin.extend(OptionsStore.prototype);
        function setAccessor(field) {
            return function (value) {
                if (this[field] !== value) {
                    this[field] = value;
                    this.geometryChange();
                }
                return this;
            };
        }
        function getAccessor(field) {
            return function () {
                return this[field];
            };
        }
        function defineAccessors(fn, fields) {
            for (var i = 0; i < fields.length; i++) {
                var name = fields[i];
                var capitalized = name.charAt(0).toUpperCase() + name.substring(1, name.length);
                fn['set' + capitalized] = setAccessor(name);
                fn['get' + capitalized] = getAccessor(name);
            }
        }
        var Matrix = Class.extend({
            init: function (a, b, c, d, e, f) {
                if (a === void 0) {
                    a = 0;
                }
                if (b === void 0) {
                    b = 0;
                }
                if (c === void 0) {
                    c = 0;
                }
                if (d === void 0) {
                    d = 0;
                }
                if (e === void 0) {
                    e = 0;
                }
                if (f === void 0) {
                    f = 0;
                }
                this.a = a;
                this.b = b;
                this.c = c;
                this.d = d;
                this.e = e;
                this.f = f;
            },
            multiplyCopy: function (matrix) {
                return new Matrix(this.a * matrix.a + this.c * matrix.b, this.b * matrix.a + this.d * matrix.b, this.a * matrix.c + this.c * matrix.d, this.b * matrix.c + this.d * matrix.d, this.a * matrix.e + this.c * matrix.f + this.e, this.b * matrix.e + this.d * matrix.f + this.f);
            },
            invert: function () {
                var ref = this;
                var a = ref.a;
                var b = ref.b;
                var d = ref.c;
                var e = ref.d;
                var g = ref.e;
                var h = ref.f;
                var det = a * e - b * d;
                if (det === 0) {
                    return null;
                }
                return new Matrix(e / det, -b / det, -d / det, a / det, (d * h - e * g) / det, (b * g - a * h) / det);
            },
            clone: function () {
                return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
            },
            equals: function (other) {
                if (!other) {
                    return false;
                }
                return this.a === other.a && this.b === other.b && this.c === other.c && this.d === other.d && this.e === other.e && this.f === other.f;
            },
            round: function (precision) {
                this.a = round(this.a, precision);
                this.b = round(this.b, precision);
                this.c = round(this.c, precision);
                this.d = round(this.d, precision);
                this.e = round(this.e, precision);
                this.f = round(this.f, precision);
                return this;
            },
            toArray: function (precision) {
                var result = [
                    this.a,
                    this.b,
                    this.c,
                    this.d,
                    this.e,
                    this.f
                ];
                if (defined(precision)) {
                    for (var i = 0; i < result.length; i++) {
                        result[i] = round(result[i], precision);
                    }
                }
                return result;
            },
            toString: function (precision, separator) {
                if (separator === void 0) {
                    separator = ',';
                }
                return this.toArray(precision).join(separator);
            }
        });
        Matrix.translate = function (x, y) {
            return new Matrix(1, 0, 0, 1, x, y);
        };
        Matrix.unit = function () {
            return new Matrix(1, 0, 0, 1, 0, 0);
        };
        Matrix.rotate = function (angle, x, y) {
            var matrix = new Matrix();
            matrix.a = Math.cos(rad(angle));
            matrix.b = Math.sin(rad(angle));
            matrix.c = -matrix.b;
            matrix.d = matrix.a;
            matrix.e = x - x * matrix.a + y * matrix.b || 0;
            matrix.f = y - y * matrix.a - x * matrix.b || 0;
            return matrix;
        };
        Matrix.scale = function (scaleX, scaleY) {
            return new Matrix(scaleX, 0, 0, scaleY, 0, 0);
        };
        Matrix.IDENTITY = Matrix.unit();
        function toMatrix(transformation) {
            if (transformation && typeof transformation.matrix === 'function') {
                return transformation.matrix();
            }
            return transformation;
        }
        var Point = Class.extend({
            init: function (x, y) {
                this.x = x || 0;
                this.y = y || 0;
            },
            equals: function (other) {
                return other && other.x === this.x && other.y === this.y;
            },
            clone: function () {
                return new Point(this.x, this.y);
            },
            rotate: function (angle, origin) {
                var originPoint = Point.create(origin) || Point.ZERO;
                return this.transform(Matrix.rotate(angle, originPoint.x, originPoint.y));
            },
            translate: function (x, y) {
                this.x += x;
                this.y += y;
                this.geometryChange();
                return this;
            },
            translateWith: function (point) {
                return this.translate(point.x, point.y);
            },
            move: function (x, y) {
                this.x = this.y = 0;
                return this.translate(x, y);
            },
            scale: function (scaleX, scaleY) {
                if (scaleY === void 0) {
                    scaleY = scaleX;
                }
                this.x *= scaleX;
                this.y *= scaleY;
                this.geometryChange();
                return this;
            },
            scaleCopy: function (scaleX, scaleY) {
                return this.clone().scale(scaleX, scaleY);
            },
            transform: function (transformation) {
                var matrix = toMatrix(transformation);
                var ref = this;
                var x = ref.x;
                var y = ref.y;
                this.x = matrix.a * x + matrix.c * y + matrix.e;
                this.y = matrix.b * x + matrix.d * y + matrix.f;
                this.geometryChange();
                return this;
            },
            transformCopy: function (transformation) {
                var point = this.clone();
                if (transformation) {
                    point.transform(transformation);
                }
                return point;
            },
            distanceTo: function (point) {
                var dx = this.x - point.x;
                var dy = this.y - point.y;
                return Math.sqrt(dx * dx + dy * dy);
            },
            round: function (digits) {
                this.x = round(this.x, digits);
                this.y = round(this.y, digits);
                this.geometryChange();
                return this;
            },
            toArray: function (digits) {
                var doRound = defined(digits);
                var x = doRound ? round(this.x, digits) : this.x;
                var y = doRound ? round(this.y, digits) : this.y;
                return [
                    x,
                    y
                ];
            },
            toString: function (digits, separator) {
                if (separator === void 0) {
                    separator = ' ';
                }
                var ref = this;
                var x = ref.x;
                var y = ref.y;
                if (defined(digits)) {
                    x = round(x, digits);
                    y = round(y, digits);
                }
                return x + separator + y;
            }
        });
        Point.create = function (arg0, arg1) {
            if (defined(arg0)) {
                if (arg0 instanceof Point) {
                    return arg0;
                } else if (arguments.length === 1 && arg0.length === 2) {
                    return new Point(arg0[0], arg0[1]);
                }
                return new Point(arg0, arg1);
            }
        };
        Point.min = function () {
            var arguments$1 = arguments;
            var minX = MAX_NUM;
            var minY = MAX_NUM;
            for (var i = 0; i < arguments.length; i++) {
                var point = arguments$1[i];
                minX = Math.min(point.x, minX);
                minY = Math.min(point.y, minY);
            }
            return new Point(minX, minY);
        };
        Point.max = function () {
            var arguments$1 = arguments;
            var maxX = MIN_NUM;
            var maxY = MIN_NUM;
            for (var i = 0; i < arguments.length; i++) {
                var point = arguments$1[i];
                maxX = Math.max(point.x, maxX);
                maxY = Math.max(point.y, maxY);
            }
            return new Point(maxX, maxY);
        };
        Point.minPoint = function () {
            return new Point(MIN_NUM, MIN_NUM);
        };
        Point.maxPoint = function () {
            return new Point(MAX_NUM, MAX_NUM);
        };
        if (Object.defineProperties) {
            Object.defineProperties(Point, {
                ZERO: {
                    get: function () {
                        return new Point(0, 0);
                    }
                }
            });
        }
        defineAccessors(Point.prototype, [
            'x',
            'y'
        ]);
        ObserversMixin.extend(Point.prototype);
        var Size = Class.extend({
            init: function (width, height) {
                this.width = width || 0;
                this.height = height || 0;
            },
            equals: function (other) {
                return other && other.width === this.width && other.height === this.height;
            },
            clone: function () {
                return new Size(this.width, this.height);
            },
            toArray: function (digits) {
                var doRound = defined(digits);
                var width = doRound ? round(this.width, digits) : this.width;
                var height = doRound ? round(this.height, digits) : this.height;
                return [
                    width,
                    height
                ];
            }
        });
        Size.create = function (arg0, arg1) {
            if (defined(arg0)) {
                if (arg0 instanceof Size) {
                    return arg0;
                } else if (arguments.length === 1 && arg0.length === 2) {
                    return new Size(arg0[0], arg0[1]);
                }
                return new Size(arg0, arg1);
            }
        };
        if (Object.defineProperties) {
            Object.defineProperties(Size, {
                ZERO: {
                    get: function () {
                        return new Size(0, 0);
                    }
                }
            });
        }
        defineAccessors(Size.prototype, [
            'width',
            'height'
        ]);
        ObserversMixin.extend(Size.prototype);
        var Rect = Class.extend({
            init: function (origin, size) {
                if (origin === void 0) {
                    origin = new Point();
                }
                if (size === void 0) {
                    size = new Size();
                }
                this.setOrigin(origin);
                this.setSize(size);
            },
            clone: function () {
                return new Rect(this.origin.clone(), this.size.clone());
            },
            equals: function (other) {
                return other && other.origin.equals(this.origin) && other.size.equals(this.size);
            },
            setOrigin: function (value) {
                this._observerField('origin', Point.create(value));
                this.geometryChange();
                return this;
            },
            getOrigin: function () {
                return this.origin;
            },
            setSize: function (value) {
                this._observerField('size', Size.create(value));
                this.geometryChange();
                return this;
            },
            getSize: function () {
                return this.size;
            },
            width: function () {
                return this.size.width;
            },
            height: function () {
                return this.size.height;
            },
            topLeft: function () {
                return this.origin.clone();
            },
            bottomRight: function () {
                return this.origin.clone().translate(this.width(), this.height());
            },
            topRight: function () {
                return this.origin.clone().translate(this.width(), 0);
            },
            bottomLeft: function () {
                return this.origin.clone().translate(0, this.height());
            },
            center: function () {
                return this.origin.clone().translate(this.width() / 2, this.height() / 2);
            },
            bbox: function (matrix) {
                var tl = this.topLeft().transformCopy(matrix);
                var tr = this.topRight().transformCopy(matrix);
                var br = this.bottomRight().transformCopy(matrix);
                var bl = this.bottomLeft().transformCopy(matrix);
                return Rect.fromPoints(tl, tr, br, bl);
            },
            transformCopy: function (m) {
                return Rect.fromPoints(this.topLeft().transform(m), this.bottomRight().transform(m));
            },
            expand: function (x, y) {
                if (y === void 0) {
                    y = x;
                }
                this.size.width += 2 * x;
                this.size.height += 2 * y;
                this.origin.translate(-x, -y);
                return this;
            },
            expandCopy: function (x, y) {
                return this.clone().expand(x, y);
            },
            containsPoint: function (point) {
                var origin = this.origin;
                var bottomRight = this.bottomRight();
                return !(point.x < origin.x || point.y < origin.y || bottomRight.x < point.x || bottomRight.y < point.y);
            },
            _isOnPath: function (point, width) {
                var rectOuter = this.expandCopy(width, width);
                var rectInner = this.expandCopy(-width, -width);
                return rectOuter.containsPoint(point) && !rectInner.containsPoint(point);
            }
        });
        Rect.fromPoints = function () {
            var topLeft = Point.min.apply(null, arguments);
            var bottomRight = Point.max.apply(null, arguments);
            var size = new Size(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y);
            return new Rect(topLeft, size);
        };
        Rect.union = function (a, b) {
            return Rect.fromPoints(Point.min(a.topLeft(), b.topLeft()), Point.max(a.bottomRight(), b.bottomRight()));
        };
        Rect.intersect = function (a, b) {
            var rect1 = {
                left: a.topLeft().x,
                top: a.topLeft().y,
                right: a.bottomRight().x,
                bottom: a.bottomRight().y
            };
            var rect2 = {
                left: b.topLeft().x,
                top: b.topLeft().y,
                right: b.bottomRight().x,
                bottom: b.bottomRight().y
            };
            if (rect1.left <= rect2.right && rect2.left <= rect1.right && rect1.top <= rect2.bottom && rect2.top <= rect1.bottom) {
                return Rect.fromPoints(new Point(Math.max(rect1.left, rect2.left), Math.max(rect1.top, rect2.top)), new Point(Math.min(rect1.right, rect2.right), Math.min(rect1.bottom, rect2.bottom)));
            }
        };
        ObserversMixin.extend(Rect.prototype);
        var Transformation = Class.extend({
            init: function (matrix) {
                if (matrix === void 0) {
                    matrix = Matrix.unit();
                }
                this._matrix = matrix;
            },
            clone: function () {
                return new Transformation(this._matrix.clone());
            },
            equals: function (other) {
                return other && other._matrix.equals(this._matrix);
            },
            translate: function (x, y) {
                this._matrix = this._matrix.multiplyCopy(Matrix.translate(x, y));
                this._optionsChange();
                return this;
            },
            scale: function (scaleX, scaleY, origin) {
                if (scaleY === void 0) {
                    scaleY = scaleX;
                }
                if (origin === void 0) {
                    origin = null;
                }
                var originPoint = origin;
                if (originPoint) {
                    originPoint = Point.create(originPoint);
                    this._matrix = this._matrix.multiplyCopy(Matrix.translate(originPoint.x, originPoint.y));
                }
                this._matrix = this._matrix.multiplyCopy(Matrix.scale(scaleX, scaleY));
                if (originPoint) {
                    this._matrix = this._matrix.multiplyCopy(Matrix.translate(-originPoint.x, -originPoint.y));
                }
                this._optionsChange();
                return this;
            },
            rotate: function (angle, origin) {
                var originPoint = Point.create(origin) || Point.ZERO;
                this._matrix = this._matrix.multiplyCopy(Matrix.rotate(angle, originPoint.x, originPoint.y));
                this._optionsChange();
                return this;
            },
            multiply: function (transformation) {
                var matrix = toMatrix(transformation);
                this._matrix = this._matrix.multiplyCopy(matrix);
                this._optionsChange();
                return this;
            },
            matrix: function (value) {
                if (value) {
                    this._matrix = value;
                    this._optionsChange();
                    return this;
                }
                return this._matrix;
            },
            _optionsChange: function () {
                this.optionsChange({
                    field: 'transform',
                    value: this
                });
            }
        });
        ObserversMixin.extend(Transformation.prototype);
        function transform(matrix) {
            if (matrix === null) {
                return null;
            }
            if (matrix instanceof Transformation) {
                return matrix;
            }
            return new Transformation(matrix);
        }
        var Element$1 = Class.extend({
            init: function (options) {
                this._initOptions(options);
            },
            _initOptions: function (options) {
                if (options === void 0) {
                    options = {};
                }
                var clip = options.clip;
                var transform$$1 = options.transform;
                if (transform$$1) {
                    options.transform = transform(transform$$1);
                }
                if (clip && !clip.id) {
                    clip.id = definitionId();
                }
                this.options = new OptionsStore(options);
                this.options.addObserver(this);
            },
            transform: function (value) {
                if (defined(value)) {
                    this.options.set('transform', transform(value));
                } else {
                    return this.options.get('transform');
                }
            },
            parentTransform: function () {
                var element = this;
                var parentMatrix;
                while (element.parent) {
                    element = element.parent;
                    var transformation = element.transform();
                    if (transformation) {
                        parentMatrix = transformation.matrix().multiplyCopy(parentMatrix || Matrix.unit());
                    }
                }
                if (parentMatrix) {
                    return transform(parentMatrix);
                }
            },
            currentTransform: function (parentTransform) {
                if (parentTransform === void 0) {
                    parentTransform = this.parentTransform();
                }
                var elementTransform = this.transform();
                var elementMatrix = toMatrix(elementTransform);
                var parentMatrix = toMatrix(parentTransform);
                var combinedMatrix;
                if (elementMatrix && parentMatrix) {
                    combinedMatrix = parentMatrix.multiplyCopy(elementMatrix);
                } else {
                    combinedMatrix = elementMatrix || parentMatrix;
                }
                if (combinedMatrix) {
                    return transform(combinedMatrix);
                }
            },
            visible: function (value) {
                if (defined(value)) {
                    this.options.set('visible', value);
                    return this;
                }
                return this.options.get('visible') !== false;
            },
            clip: function (value) {
                var options = this.options;
                if (defined(value)) {
                    if (value && !value.id) {
                        value.id = definitionId();
                    }
                    options.set('clip', value);
                    return this;
                }
                return options.get('clip');
            },
            opacity: function (value) {
                if (defined(value)) {
                    this.options.set('opacity', value);
                    return this;
                }
                return valueOrDefault(this.options.get('opacity'), 1);
            },
            clippedBBox: function (transformation) {
                var bbox = this._clippedBBox(transformation);
                if (bbox) {
                    var clip = this.clip();
                    return clip ? Rect.intersect(bbox, clip.bbox(transformation)) : bbox;
                }
            },
            containsPoint: function (point, parentTransform) {
                if (this.visible()) {
                    var transform$$1 = this.currentTransform(parentTransform);
                    var transformedPoint = point;
                    if (transform$$1) {
                        transformedPoint = point.transformCopy(transform$$1.matrix().invert());
                    }
                    return this._hasFill() && this._containsPoint(transformedPoint) || this._isOnPath && this._hasStroke() && this._isOnPath(transformedPoint);
                }
                return false;
            },
            _hasFill: function () {
                var fill = this.options.fill;
                return fill && !isTransparent(fill.color);
            },
            _hasStroke: function () {
                var stroke = this.options.stroke;
                return stroke && stroke.width > 0 && !isTransparent(stroke.color);
            },
            _clippedBBox: function (transformation) {
                return this.bbox(transformation);
            }
        });
        Element$1.prototype.nodeType = 'Element';
        ObserversMixin.extend(Element$1.prototype);
        function ellipseExtremeAngles(center, rx, ry, matrix) {
            var extremeX = 0;
            var extremeY = 0;
            if (matrix) {
                extremeX = Math.atan2(matrix.c * ry, matrix.a * rx);
                if (matrix.b !== 0) {
                    extremeY = Math.atan2(matrix.d * ry, matrix.b * rx);
                }
            }
            return {
                x: extremeX,
                y: extremeY
            };
        }
        var PI_DIV_2 = Math.PI / 2;
        var Circle$2 = Class.extend({
            init: function (center, radius) {
                if (center === void 0) {
                    center = new Point();
                }
                if (radius === void 0) {
                    radius = 0;
                }
                this.setCenter(center);
                this.setRadius(radius);
            },
            setCenter: function (value) {
                this._observerField('center', Point.create(value));
                this.geometryChange();
                return this;
            },
            getCenter: function () {
                return this.center;
            },
            equals: function (other) {
                return other && other.center.equals(this.center) && other.radius === this.radius;
            },
            clone: function () {
                return new Circle$2(this.center.clone(), this.radius);
            },
            pointAt: function (angle) {
                return this._pointAt(rad(angle));
            },
            bbox: function (matrix) {
                var this$1 = this;
                var extremeAngles = ellipseExtremeAngles(this.center, this.radius, this.radius, matrix);
                var minPoint = Point.maxPoint();
                var maxPoint = Point.minPoint();
                for (var i = 0; i < 4; i++) {
                    var currentPointX = this$1._pointAt(extremeAngles.x + i * PI_DIV_2).transformCopy(matrix);
                    var currentPointY = this$1._pointAt(extremeAngles.y + i * PI_DIV_2).transformCopy(matrix);
                    var currentPoint = new Point(currentPointX.x, currentPointY.y);
                    minPoint = Point.min(minPoint, currentPoint);
                    maxPoint = Point.max(maxPoint, currentPoint);
                }
                return Rect.fromPoints(minPoint, maxPoint);
            },
            _pointAt: function (angle) {
                var ref = this;
                var center = ref.center;
                var radius = ref.radius;
                return new Point(center.x + radius * Math.cos(angle), center.y + radius * Math.sin(angle));
            },
            containsPoint: function (point) {
                var ref = this;
                var center = ref.center;
                var radius = ref.radius;
                var inCircle = Math.pow(point.x - center.x, 2) + Math.pow(point.y - center.y, 2) <= Math.pow(radius, 2);
                return inCircle;
            },
            _isOnPath: function (point, width) {
                var ref = this;
                var center = ref.center;
                var radius = ref.radius;
                var pointDistance = center.distanceTo(point);
                return radius - width <= pointDistance && pointDistance <= radius + width;
            }
        });
        defineAccessors(Circle$2.prototype, ['radius']);
        ObserversMixin.extend(Circle$2.prototype);
        var GRADIENT = 'Gradient';
        var Paintable = {
            extend: function (proto) {
                proto.fill = this.fill;
                proto.stroke = this.stroke;
            },
            fill: function (color, opacity) {
                var options = this.options;
                if (defined(color)) {
                    if (color && color.nodeType !== GRADIENT) {
                        var newFill = { color: color };
                        if (defined(opacity)) {
                            newFill.opacity = opacity;
                        }
                        options.set('fill', newFill);
                    } else {
                        options.set('fill', color);
                    }
                    return this;
                }
                return options.get('fill');
            },
            stroke: function (color, width, opacity) {
                if (defined(color)) {
                    this.options.set('stroke.color', color);
                    if (defined(width)) {
                        this.options.set('stroke.width', width);
                    }
                    if (defined(opacity)) {
                        this.options.set('stroke.opacity', opacity);
                    }
                    return this;
                }
                return this.options.get('stroke');
            }
        };
        var IDENTITY_MATRIX_HASH = Matrix.IDENTITY.toString();
        var Measurable = {
            extend: function (proto) {
                proto.bbox = this.bbox;
                proto.geometryChange = this.geometryChange;
            },
            bbox: function (transformation) {
                var combinedMatrix = toMatrix(this.currentTransform(transformation));
                var matrixHash = combinedMatrix ? combinedMatrix.toString() : IDENTITY_MATRIX_HASH;
                var bbox;
                if (this._bboxCache && this._matrixHash === matrixHash) {
                    bbox = this._bboxCache.clone();
                } else {
                    bbox = this._bbox(combinedMatrix);
                    this._bboxCache = bbox ? bbox.clone() : null;
                    this._matrixHash = matrixHash;
                }
                var strokeWidth = this.options.get('stroke.width');
                if (strokeWidth && bbox) {
                    bbox.expand(strokeWidth / 2);
                }
                return bbox;
            },
            geometryChange: function () {
                delete this._bboxCache;
                this.trigger('geometryChange', { element: this });
            }
        };
        function geometryAccessor(name) {
            var fieldName = '_' + name;
            return function (value) {
                if (defined(value)) {
                    this._observerField(fieldName, value);
                    this.geometryChange();
                    return this;
                }
                return this[fieldName];
            };
        }
        function defineGeometryAccessors(fn, names) {
            for (var i = 0; i < names.length; i++) {
                fn[names[i]] = geometryAccessor(names[i]);
            }
        }
        var DEFAULT_STROKE = '#000';
        var Circle = Element$1.extend({
            init: function (geometry, options) {
                if (geometry === void 0) {
                    geometry = new Circle$2();
                }
                if (options === void 0) {
                    options = {};
                }
                Element$1.fn.init.call(this, options);
                this.geometry(geometry);
                if (!defined(this.options.stroke)) {
                    this.stroke(DEFAULT_STROKE);
                }
            },
            rawBBox: function () {
                return this._geometry.bbox();
            },
            _bbox: function (matrix) {
                return this._geometry.bbox(matrix);
            },
            _containsPoint: function (point) {
                return this.geometry().containsPoint(point);
            },
            _isOnPath: function (point) {
                return this.geometry()._isOnPath(point, this.options.stroke.width / 2);
            }
        });
        Circle.prototype.nodeType = 'Circle';
        Paintable.extend(Circle.prototype);
        Measurable.extend(Circle.prototype);
        defineGeometryAccessors(Circle.prototype, ['geometry']);
        var PRECISION = 10;
        function close(a, b, tolerance) {
            if (tolerance === void 0) {
                tolerance = PRECISION;
            }
            return round(Math.abs(a - b), tolerance) === 0;
        }
        function closeOrLess(a, b, tolerance) {
            return a < b || close(a, b, tolerance);
        }
        function lineIntersection(p0, p1, p2, p3) {
            var s1x = p1.x - p0.x;
            var s2x = p3.x - p2.x;
            var s1y = p1.y - p0.y;
            var s2y = p3.y - p2.y;
            var nx = p0.x - p2.x;
            var ny = p0.y - p2.y;
            var d = s1x * s2y - s2x * s1y;
            var s = (s1x * ny - s1y * nx) / d;
            var t = (s2x * ny - s2y * nx) / d;
            if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
                return new Point(p0.x + t * s1x, p0.y + t * s1y);
            }
        }
        var MAX_INTERVAL = 45;
        var pow$1 = Math.pow;
        var Arc$2 = Class.extend({
            init: function (center, options) {
                if (center === void 0) {
                    center = new Point();
                }
                if (options === void 0) {
                    options = {};
                }
                this.setCenter(center);
                this.radiusX = options.radiusX;
                this.radiusY = options.radiusY || options.radiusX;
                this.startAngle = options.startAngle;
                this.endAngle = options.endAngle;
                this.anticlockwise = options.anticlockwise || false;
                this.xRotation = options.xRotation;
            },
            clone: function () {
                return new Arc$2(this.center, {
                    radiusX: this.radiusX,
                    radiusY: this.radiusY,
                    startAngle: this.startAngle,
                    endAngle: this.endAngle,
                    anticlockwise: this.anticlockwise
                });
            },
            setCenter: function (value) {
                this._observerField('center', Point.create(value));
                this.geometryChange();
                return this;
            },
            getCenter: function () {
                return this.center;
            },
            pointAt: function (angle) {
                var center = this.center;
                var radian = rad(angle);
                return new Point(center.x + this.radiusX * Math.cos(radian), center.y + this.radiusY * Math.sin(radian));
            },
            curvePoints: function () {
                var this$1 = this;
                var startAngle = this.startAngle;
                var dir = this.anticlockwise ? -1 : 1;
                var curvePoints = [this.pointAt(startAngle)];
                var interval = this._arcInterval();
                var intervalAngle = interval.endAngle - interval.startAngle;
                var subIntervalsCount = Math.ceil(intervalAngle / MAX_INTERVAL);
                var subIntervalAngle = intervalAngle / subIntervalsCount;
                var currentAngle = startAngle;
                var transformation;
                if (this.xRotation) {
                    transformation = transform().rotate(this.xRotation, this.center);
                }
                for (var i = 1; i <= subIntervalsCount; i++) {
                    var nextAngle = currentAngle + dir * subIntervalAngle;
                    var points = this$1._intervalCurvePoints(currentAngle, nextAngle, transformation);
                    curvePoints.push(points.cp1, points.cp2, points.p2);
                    currentAngle = nextAngle;
                }
                return curvePoints;
            },
            bbox: function (matrix) {
                var this$1 = this;
                var interval = this._arcInterval();
                var startAngle = interval.startAngle;
                var endAngle = interval.endAngle;
                var extremeAngles = ellipseExtremeAngles(this.center, this.radiusX, this.radiusY, matrix);
                var extremeX = deg(extremeAngles.x);
                var extremeY = deg(extremeAngles.y);
                var endPoint = this.pointAt(endAngle).transformCopy(matrix);
                var currentAngleX = bboxStartAngle(extremeX, startAngle);
                var currentAngleY = bboxStartAngle(extremeY, startAngle);
                var currentPoint = this.pointAt(startAngle).transformCopy(matrix);
                var minPoint = Point.min(currentPoint, endPoint);
                var maxPoint = Point.max(currentPoint, endPoint);
                while (currentAngleX < endAngle || currentAngleY < endAngle) {
                    var currentPointX = void 0;
                    if (currentAngleX < endAngle) {
                        currentPointX = this$1.pointAt(currentAngleX).transformCopy(matrix);
                        currentAngleX += 90;
                    }
                    var currentPointY = void 0;
                    if (currentAngleY < endAngle) {
                        currentPointY = this$1.pointAt(currentAngleY).transformCopy(matrix);
                        currentAngleY += 90;
                    }
                    currentPoint = new Point(currentPointX.x, currentPointY.y);
                    minPoint = Point.min(minPoint, currentPoint);
                    maxPoint = Point.max(maxPoint, currentPoint);
                }
                return Rect.fromPoints(minPoint, maxPoint);
            },
            _arcInterval: function () {
                var ref = this;
                var startAngle = ref.startAngle;
                var endAngle = ref.endAngle;
                var anticlockwise = ref.anticlockwise;
                if (anticlockwise) {
                    var oldStart = startAngle;
                    startAngle = endAngle;
                    endAngle = oldStart;
                }
                if (startAngle > endAngle || anticlockwise && startAngle === endAngle) {
                    endAngle += 360;
                }
                return {
                    startAngle: startAngle,
                    endAngle: endAngle
                };
            },
            _intervalCurvePoints: function (startAngle, endAngle, transformation) {
                var p1 = this.pointAt(startAngle);
                var p2 = this.pointAt(endAngle);
                var p1Derivative = this._derivativeAt(startAngle);
                var p2Derivative = this._derivativeAt(endAngle);
                var t = (rad(endAngle) - rad(startAngle)) / 3;
                var cp1 = new Point(p1.x + t * p1Derivative.x, p1.y + t * p1Derivative.y);
                var cp2 = new Point(p2.x - t * p2Derivative.x, p2.y - t * p2Derivative.y);
                if (transformation) {
                    p1.transform(transformation);
                    p2.transform(transformation);
                    cp1.transform(transformation);
                    cp2.transform(transformation);
                }
                return {
                    p1: p1,
                    cp1: cp1,
                    cp2: cp2,
                    p2: p2
                };
            },
            _derivativeAt: function (angle) {
                var radian = rad(angle);
                return new Point(-this.radiusX * Math.sin(radian), this.radiusY * Math.cos(radian));
            },
            containsPoint: function (point) {
                var interval = this._arcInterval();
                var intervalAngle = interval.endAngle - interval.startAngle;
                var ref = this;
                var center = ref.center;
                var radiusX = ref.radiusX;
                var radiusY = ref.radiusY;
                var distance = center.distanceTo(point);
                var angleRad = Math.atan2(point.y - center.y, point.x - center.x);
                var pointRadius = radiusX * radiusY / Math.sqrt(pow$1(radiusX, 2) * pow$1(Math.sin(angleRad), 2) + pow$1(radiusY, 2) * pow$1(Math.cos(angleRad), 2));
                var startPoint = this.pointAt(this.startAngle).round(PRECISION);
                var endPoint = this.pointAt(this.endAngle).round(PRECISION);
                var intersection = lineIntersection(center, point.round(PRECISION), startPoint, endPoint);
                var containsPoint;
                if (intervalAngle < 180) {
                    containsPoint = intersection && closeOrLess(center.distanceTo(intersection), distance) && closeOrLess(distance, pointRadius);
                } else {
                    var angle = calculateAngle(center.x, center.y, radiusX, radiusY, point.x, point.y);
                    if (angle !== 360) {
                        angle = (360 + angle) % 360;
                    }
                    var inAngleRange = interval.startAngle <= angle && angle <= interval.endAngle;
                    containsPoint = inAngleRange && closeOrLess(distance, pointRadius) || !inAngleRange && (!intersection || intersection.equals(point));
                }
                return containsPoint;
            },
            _isOnPath: function (point, width) {
                var interval = this._arcInterval();
                var center = this.center;
                var angle = calculateAngle(center.x, center.y, this.radiusX, this.radiusY, point.x, point.y);
                if (angle !== 360) {
                    angle = (360 + angle) % 360;
                }
                var inAngleRange = interval.startAngle <= angle && angle <= interval.endAngle;
                return inAngleRange && this.pointAt(angle).distanceTo(point) <= width;
            }
        });
        Arc$2.fromPoints = function (start, end, rx, ry, largeArc, swipe, rotation) {
            var arcParameters = normalizeArcParameters({
                x1: start.x,
                y1: start.y,
                x2: end.x,
                y2: end.y,
                rx: rx,
                ry: ry,
                largeArc: largeArc,
                swipe: swipe,
                rotation: rotation
            });
            return new Arc$2(arcParameters.center, {
                startAngle: arcParameters.startAngle,
                endAngle: arcParameters.endAngle,
                radiusX: arcParameters.radiusX,
                radiusY: arcParameters.radiusY,
                xRotation: arcParameters.xRotation,
                anticlockwise: swipe === 0
            });
        };
        defineAccessors(Arc$2.prototype, [
            'radiusX',
            'radiusY',
            'startAngle',
            'endAngle',
            'anticlockwise'
        ]);
        ObserversMixin.extend(Arc$2.prototype);
        function calculateAngle(cx, cy, rx, ry, x, y) {
            var cos = round((x - cx) / rx, 3);
            var sin = round((y - cy) / ry, 3);
            return round(deg(Math.atan2(sin, cos)));
        }
        function normalizeArcParameters(parameters) {
            var x1 = parameters.x1;
            var y1 = parameters.y1;
            var x2 = parameters.x2;
            var y2 = parameters.y2;
            var rx = parameters.rx;
            var ry = parameters.ry;
            var largeArc = parameters.largeArc;
            var swipe = parameters.swipe;
            var rotation = parameters.rotation;
            if (rotation === void 0) {
                rotation = 0;
            }
            var radians = rad(rotation);
            var cosine = Math.cos(radians);
            var sine = Math.sin(radians);
            var xT = cosine * (x1 - x2) / 2 + sine * (y1 - y2) / 2;
            var yT = -sine * (x1 - x2) / 2 + cosine * (y1 - y2) / 2;
            var sign = largeArc !== swipe ? 1 : -1;
            var xt2 = Math.pow(xT, 2);
            var yt2 = Math.pow(yT, 2);
            var rx2 = Math.pow(rx, 2);
            var ry2 = Math.pow(ry, 2);
            var delta = xt2 / rx2 + yt2 / ry2;
            if (delta > 1) {
                delta = Math.sqrt(xt2 / rx2 + yt2 / ry2);
                rx = delta * rx;
                rx2 = Math.pow(rx, 2);
                ry = delta * ry;
                ry2 = Math.pow(ry, 2);
            }
            var constT = sign * Math.sqrt((rx2 * ry2 - rx2 * yt2 - ry2 * xt2) / (rx2 * yt2 + ry2 * xt2));
            if (isNaN(constT)) {
                constT = 0;
            }
            var cxT = constT * (rx * yT) / ry;
            var cyT = -constT * (ry * xT) / rx;
            var cx = cosine * cxT - sine * cyT + (x1 + x2) / 2;
            var cy = sine * cxT + cosine * cyT + (y1 + y2) / 2;
            var uX = (xT - cxT) / rx;
            var uY = (yT - cyT) / ry;
            var vX = -(xT + cxT) / rx;
            var vY = -(yT + cyT) / ry;
            var startAngle = (uY >= 0 ? 1 : -1) * deg(Math.acos(uX / Math.sqrt(uX * uX + uY * uY)));
            var angleCosine = round((uX * vX + uY * vY) / (Math.sqrt(uX * uX + uY * uY) * Math.sqrt(vX * vX + vY * vY)), 10);
            var angle = (uX * vY - uY * vX >= 0 ? 1 : -1) * deg(Math.acos(angleCosine));
            if (!swipe && angle > 0) {
                angle -= 360;
            }
            if (swipe && angle < 0) {
                angle += 360;
            }
            var endAngle = startAngle + angle;
            var signEndAngle = endAngle >= 0 ? 1 : -1;
            endAngle = Math.abs(endAngle) % 360 * signEndAngle;
            return {
                center: new Point(cx, cy),
                startAngle: startAngle,
                endAngle: endAngle,
                radiusX: rx,
                radiusY: ry,
                xRotation: rotation
            };
        }
        function bboxStartAngle(angle, start) {
            var startAngle = angle;
            while (startAngle < start) {
                startAngle += 90;
            }
            return startAngle;
        }
        var push = [].push;
        var pop = [].pop;
        var splice = [].splice;
        var shift = [].shift;
        var slice = [].slice;
        var unshift = [].unshift;
        var ElementsArray = Class.extend({
            init: function (array) {
                if (array === void 0) {
                    array = [];
                }
                this.length = 0;
                this._splice(0, array.length, array);
            },
            elements: function (value) {
                if (value) {
                    this._splice(0, this.length, value);
                    this._change();
                    return this;
                }
                return this.slice(0);
            },
            push: function () {
                var elements = arguments;
                var result = push.apply(this, elements);
                this._add(elements);
                return result;
            },
            slice: function () {
                return slice.call(this);
            },
            pop: function () {
                var length = this.length;
                var result = pop.apply(this);
                if (length) {
                    this._remove([result]);
                }
                return result;
            },
            splice: function (index, howMany) {
                var elements = slice.call(arguments, 2);
                var result = this._splice(index, howMany, elements);
                this._change();
                return result;
            },
            shift: function () {
                var length = this.length;
                var result = shift.apply(this);
                if (length) {
                    this._remove([result]);
                }
                return result;
            },
            unshift: function () {
                var elements = arguments;
                var result = unshift.apply(this, elements);
                this._add(elements);
                return result;
            },
            indexOf: function (element) {
                var this$1 = this;
                var length = this.length;
                for (var idx = 0; idx < length; idx++) {
                    if (this$1[idx] === element) {
                        return idx;
                    }
                }
                return -1;
            },
            _splice: function (index, howMany, elements) {
                var result = splice.apply(this, [
                    index,
                    howMany
                ].concat(elements));
                this._clearObserver(result);
                this._setObserver(elements);
                return result;
            },
            _add: function (elements) {
                this._setObserver(elements);
                this._change();
            },
            _remove: function (elements) {
                this._clearObserver(elements);
                this._change();
            },
            _setObserver: function (elements) {
                var this$1 = this;
                for (var idx = 0; idx < elements.length; idx++) {
                    elements[idx].addObserver(this$1);
                }
            },
            _clearObserver: function (elements) {
                var this$1 = this;
                for (var idx = 0; idx < elements.length; idx++) {
                    elements[idx].removeObserver(this$1);
                }
            },
            _change: function () {
            }
        });
        ObserversMixin.extend(ElementsArray.prototype);
        var GeometryElementsArray = ElementsArray.extend({
            _change: function () {
                this.geometryChange();
            }
        });
        function pointAccessor(name) {
            var fieldName = '_' + name;
            return function (value) {
                if (defined(value)) {
                    this._observerField(fieldName, Point.create(value));
                    this.geometryChange();
                    return this;
                }
                return this[fieldName];
            };
        }
        function definePointAccessors(fn, names) {
            for (var i = 0; i < names.length; i++) {
                fn[names[i]] = pointAccessor(names[i]);
            }
        }
        function isOutOfEndPoint(endPoint, controlPoint, point) {
            var angle = deg(Math.atan2(controlPoint.y - endPoint.y, controlPoint.x - endPoint.x));
            var rotatedPoint = point.transformCopy(transform().rotate(-angle, endPoint));
            return rotatedPoint.x < endPoint.x;
        }
        function calculateCurveAt(t, field, points) {
            var t1 = 1 - t;
            return Math.pow(t1, 3) * points[0][field] + 3 * Math.pow(t1, 2) * t * points[1][field] + 3 * Math.pow(t, 2) * t1 * points[2][field] + Math.pow(t, 3) * points[3][field];
        }
        function toCubicPolynomial(points, field) {
            return [
                -points[0][field] + 3 * points[1][field] - 3 * points[2][field] + points[3][field],
                3 * (points[0][field] - 2 * points[1][field] + points[2][field]),
                3 * (-points[0][field] + points[1][field]),
                points[0][field]
            ];
        }
        var ComplexNumber = Class.extend({
            init: function (real, img) {
                if (real === void 0) {
                    real = 0;
                }
                if (img === void 0) {
                    img = 0;
                }
                this.real = real;
                this.img = img;
            },
            add: function (cNumber) {
                return new ComplexNumber(round(this.real + cNumber.real, PRECISION), round(this.img + cNumber.img, PRECISION));
            },
            addConstant: function (value) {
                return new ComplexNumber(this.real + value, this.img);
            },
            negate: function () {
                return new ComplexNumber(-this.real, -this.img);
            },
            multiply: function (cNumber) {
                return new ComplexNumber(this.real * cNumber.real - this.img * cNumber.img, this.real * cNumber.img + this.img * cNumber.real);
            },
            multiplyConstant: function (value) {
                return new ComplexNumber(this.real * value, this.img * value);
            },
            nthRoot: function (n) {
                var rad$$1 = Math.atan2(this.img, this.real);
                var r = Math.sqrt(Math.pow(this.img, 2) + Math.pow(this.real, 2));
                var nthR = Math.pow(r, 1 / n);
                return new ComplexNumber(nthR * Math.cos(rad$$1 / n), nthR * Math.sin(rad$$1 / n));
            },
            equals: function (cNumber) {
                return this.real === cNumber.real && this.img === cNumber.img;
            },
            isReal: function () {
                return this.img === 0;
            }
        });
        function numberSign(x) {
            return x < 0 ? -1 : 1;
        }
        function solveQuadraticEquation(a, b, c) {
            var squareRoot = Math.sqrt(Math.pow(b, 2) - 4 * a * c);
            return [
                (-b + squareRoot) / (2 * a),
                (-b - squareRoot) / (2 * a)
            ];
        }
        function solveCubicEquation(a, b, c, d) {
            if (a === 0) {
                return solveQuadraticEquation(b, c, d);
            }
            var p = (3 * a * c - Math.pow(b, 2)) / (3 * Math.pow(a, 2));
            var q = (2 * Math.pow(b, 3) - 9 * a * b * c + 27 * Math.pow(a, 2) * d) / (27 * Math.pow(a, 3));
            var Q = Math.pow(p / 3, 3) + Math.pow(q / 2, 2);
            var i = new ComplexNumber(0, 1);
            var b3a = -b / (3 * a);
            var x1, x2, y1, y2, y3, z1, z2;
            if (Q < 0) {
                x1 = new ComplexNumber(-q / 2, Math.sqrt(-Q)).nthRoot(3);
                x2 = new ComplexNumber(-q / 2, -Math.sqrt(-Q)).nthRoot(3);
            } else {
                x1 = -q / 2 + Math.sqrt(Q);
                x1 = new ComplexNumber(numberSign(x1) * Math.pow(Math.abs(x1), 1 / 3));
                x2 = -q / 2 - Math.sqrt(Q);
                x2 = new ComplexNumber(numberSign(x2) * Math.pow(Math.abs(x2), 1 / 3));
            }
            y1 = x1.add(x2);
            z1 = x1.add(x2).multiplyConstant(-1 / 2);
            z2 = x1.add(x2.negate()).multiplyConstant(Math.sqrt(3) / 2);
            y2 = z1.add(i.multiply(z2));
            y3 = z1.add(i.negate().multiply(z2));
            var result = [];
            if (y1.isReal()) {
                result.push(round(y1.real + b3a, PRECISION));
            }
            if (y2.isReal()) {
                result.push(round(y2.real + b3a, PRECISION));
            }
            if (y3.isReal()) {
                result.push(round(y3.real + b3a, PRECISION));
            }
            return result;
        }
        function hasRootsInRange(points, point, field, rootField, range) {
            var polynomial = toCubicPolynomial(points, rootField);
            var roots = solveCubicEquation(polynomial[0], polynomial[1], polynomial[2], polynomial[3] - point[rootField]);
            var intersection;
            for (var idx = 0; idx < roots.length; idx++) {
                if (0 <= roots[idx] && roots[idx] <= 1) {
                    intersection = calculateCurveAt(roots[idx], field, points);
                    if (Math.abs(intersection - point[field]) <= range) {
                        return true;
                    }
                }
            }
        }
        function curveIntersectionsCount(points, point, bbox) {
            var polynomial = toCubicPolynomial(points, 'x');
            var roots = solveCubicEquation(polynomial[0], polynomial[1], polynomial[2], polynomial[3] - point.x);
            var rayIntersection, intersectsRay;
            var count = 0;
            for (var i = 0; i < roots.length; i++) {
                rayIntersection = calculateCurveAt(roots[i], 'y', points);
                intersectsRay = close(rayIntersection, point.y) || rayIntersection > point.y;
                if (intersectsRay && ((roots[i] === 0 || roots[i] === 1) && bbox.bottomRight().x > point.x || 0 < roots[i] && roots[i] < 1)) {
                    count++;
                }
            }
            return count;
        }
        function lineIntersectionsCount(a, b, point) {
            var intersects;
            if (a.x !== b.x) {
                var minX = Math.min(a.x, b.x);
                var maxX = Math.max(a.x, b.x);
                var minY = Math.min(a.y, b.y);
                var maxY = Math.max(a.y, b.y);
                var inRange = minX <= point.x && point.x < maxX;
                if (minY === maxY) {
                    intersects = point.y <= minY && inRange;
                } else {
                    intersects = inRange && (maxY - minY) * ((a.x - b.x) * (a.y - b.y) > 0 ? point.x - minX : maxX - point.x) / (maxX - minX) + minY - point.y >= 0;
                }
            }
            return intersects ? 1 : 0;
        }
        var Segment = Class.extend({
            init: function (anchor, controlIn, controlOut) {
                this.anchor(anchor || new Point());
                this.controlIn(controlIn);
                this.controlOut(controlOut);
            },
            bboxTo: function (toSegment, matrix) {
                var segmentAnchor = this.anchor().transformCopy(matrix);
                var toSegmentAnchor = toSegment.anchor().transformCopy(matrix);
                var rect;
                if (this.controlOut() && toSegment.controlIn()) {
                    rect = this._curveBoundingBox(segmentAnchor, this.controlOut().transformCopy(matrix), toSegment.controlIn().transformCopy(matrix), toSegmentAnchor);
                } else {
                    rect = this._lineBoundingBox(segmentAnchor, toSegmentAnchor);
                }
                return rect;
            },
            _lineBoundingBox: function (p1, p2) {
                return Rect.fromPoints(p1, p2);
            },
            _curveBoundingBox: function (p1, cp1, cp2, p2) {
                var points = [
                    p1,
                    cp1,
                    cp2,
                    p2
                ];
                var extremesX = this._curveExtremesFor(points, 'x');
                var extremesY = this._curveExtremesFor(points, 'y');
                var xLimits = arrayLimits([
                    extremesX.min,
                    extremesX.max,
                    p1.x,
                    p2.x
                ]);
                var yLimits = arrayLimits([
                    extremesY.min,
                    extremesY.max,
                    p1.y,
                    p2.y
                ]);
                return Rect.fromPoints(new Point(xLimits.min, yLimits.min), new Point(xLimits.max, yLimits.max));
            },
            _curveExtremesFor: function (points, field) {
                var extremes = this._curveExtremes(points[0][field], points[1][field], points[2][field], points[3][field]);
                return {
                    min: calculateCurveAt(extremes.min, field, points),
                    max: calculateCurveAt(extremes.max, field, points)
                };
            },
            _curveExtremes: function (x1, x2, x3, x4) {
                var a = x1 - 3 * x2 + 3 * x3 - x4;
                var b = -2 * (x1 - 2 * x2 + x3);
                var c = x1 - x2;
                var sqrt = Math.sqrt(b * b - 4 * a * c);
                var t1 = 0;
                var t2 = 1;
                if (a === 0) {
                    if (b !== 0) {
                        t1 = t2 = -c / b;
                    }
                } else if (!isNaN(sqrt)) {
                    t1 = (-b + sqrt) / (2 * a);
                    t2 = (-b - sqrt) / (2 * a);
                }
                var min = Math.max(Math.min(t1, t2), 0);
                if (min < 0 || min > 1) {
                    min = 0;
                }
                var max = Math.min(Math.max(t1, t2), 1);
                if (max > 1 || max < 0) {
                    max = 1;
                }
                return {
                    min: min,
                    max: max
                };
            },
            _intersectionsTo: function (segment, point) {
                var intersectionsCount;
                if (this.controlOut() && segment.controlIn()) {
                    intersectionsCount = curveIntersectionsCount([
                        this.anchor(),
                        this.controlOut(),
                        segment.controlIn(),
                        segment.anchor()
                    ], point, this.bboxTo(segment));
                } else {
                    intersectionsCount = lineIntersectionsCount(this.anchor(), segment.anchor(), point);
                }
                return intersectionsCount;
            },
            _isOnCurveTo: function (segment, point, width, endSegment) {
                var bbox = this.bboxTo(segment).expand(width, width);
                if (bbox.containsPoint(point)) {
                    var p1 = this.anchor();
                    var p2 = this.controlOut();
                    var p3 = segment.controlIn();
                    var p4 = segment.anchor();
                    if (endSegment === 'start' && p1.distanceTo(point) <= width) {
                        return !isOutOfEndPoint(p1, p2, point);
                    } else if (endSegment === 'end' && p4.distanceTo(point) <= width) {
                        return !isOutOfEndPoint(p4, p3, point);
                    }
                    var points = [
                        p1,
                        p2,
                        p3,
                        p4
                    ];
                    if (hasRootsInRange(points, point, 'x', 'y', width) || hasRootsInRange(points, point, 'y', 'x', width)) {
                        return true;
                    }
                    var rotation = transform().rotate(45, point);
                    var rotatedPoints = [
                        p1.transformCopy(rotation),
                        p2.transformCopy(rotation),
                        p3.transformCopy(rotation),
                        p4.transformCopy(rotation)
                    ];
                    return hasRootsInRange(rotatedPoints, point, 'x', 'y', width) || hasRootsInRange(rotatedPoints, point, 'y', 'x', width);
                }
            },
            _isOnLineTo: function (segment, point, width) {
                var p1 = this.anchor();
                var p2 = segment.anchor();
                var angle = deg(Math.atan2(p2.y - p1.y, p2.x - p1.x));
                var rect = new Rect([
                    p1.x,
                    p1.y - width / 2
                ], [
                    p1.distanceTo(p2),
                    width
                ]);
                return rect.containsPoint(point.transformCopy(transform().rotate(-angle, p1)));
            },
            _isOnPathTo: function (segment, point, width, endSegment) {
                var isOnPath;
                if (this.controlOut() && segment.controlIn()) {
                    isOnPath = this._isOnCurveTo(segment, point, width / 2, endSegment);
                } else {
                    isOnPath = this._isOnLineTo(segment, point, width);
                }
                return isOnPath;
            }
        });
        definePointAccessors(Segment.prototype, [
            'anchor',
            'controlIn',
            'controlOut'
        ]);
        ObserversMixin.extend(Segment.prototype);
        function arrayLimits(arr) {
            var length = arr.length;
            var min = MAX_NUM;
            var max = MIN_NUM;
            for (var i = 0; i < length; i++) {
                max = Math.max(max, arr[i]);
                min = Math.min(min, arr[i]);
            }
            return {
                min: min,
                max: max
            };
        }
        function elementsBoundingBox(elements, applyTransform, transformation) {
            var boundingBox;
            for (var i = 0; i < elements.length; i++) {
                var element = elements[i];
                if (element.visible()) {
                    var elementBoundingBox = applyTransform ? element.bbox(transformation) : element.rawBBox();
                    if (elementBoundingBox) {
                        if (boundingBox) {
                            boundingBox = Rect.union(boundingBox, elementBoundingBox);
                        } else {
                            boundingBox = elementBoundingBox;
                        }
                    }
                }
            }
            return boundingBox;
        }
        function elementsClippedBoundingBox(elements, transformation) {
            var boundingBox;
            for (var i = 0; i < elements.length; i++) {
                var element = elements[i];
                if (element.visible()) {
                    var elementBoundingBox = element.clippedBBox(transformation);
                    if (elementBoundingBox) {
                        if (boundingBox) {
                            boundingBox = Rect.union(boundingBox, elementBoundingBox);
                        } else {
                            boundingBox = elementBoundingBox;
                        }
                    }
                }
            }
            return boundingBox;
        }
        var MultiPath = Element$1.extend({
            init: function (options) {
                Element$1.fn.init.call(this, options);
                this.paths = new GeometryElementsArray();
                this.paths.addObserver(this);
                if (!defined(this.options.stroke)) {
                    this.stroke('#000');
                }
            },
            moveTo: function (x, y) {
                var path = new Path();
                path.moveTo(x, y);
                this.paths.push(path);
                return this;
            },
            lineTo: function (x, y) {
                if (this.paths.length > 0) {
                    last(this.paths).lineTo(x, y);
                }
                return this;
            },
            curveTo: function (controlOut, controlIn, point) {
                if (this.paths.length > 0) {
                    last(this.paths).curveTo(controlOut, controlIn, point);
                }
                return this;
            },
            arc: function (startAngle, endAngle, radiusX, radiusY, anticlockwise) {
                if (this.paths.length > 0) {
                    last(this.paths).arc(startAngle, endAngle, radiusX, radiusY, anticlockwise);
                }
                return this;
            },
            arcTo: function (end, rx, ry, largeArc, swipe, rotation) {
                if (this.paths.length > 0) {
                    last(this.paths).arcTo(end, rx, ry, largeArc, swipe, rotation);
                }
                return this;
            },
            close: function () {
                if (this.paths.length > 0) {
                    last(this.paths).close();
                }
                return this;
            },
            _bbox: function (matrix) {
                return elementsBoundingBox(this.paths, true, matrix);
            },
            rawBBox: function () {
                return elementsBoundingBox(this.paths, false);
            },
            _containsPoint: function (point) {
                var paths = this.paths;
                for (var idx = 0; idx < paths.length; idx++) {
                    if (paths[idx]._containsPoint(point)) {
                        return true;
                    }
                }
                return false;
            },
            _isOnPath: function (point) {
                var paths = this.paths;
                var width = this.options.stroke.width;
                for (var idx = 0; idx < paths.length; idx++) {
                    if (paths[idx]._isOnPath(point, width)) {
                        return true;
                    }
                }
                return false;
            },
            _clippedBBox: function (transformation) {
                return elementsClippedBoundingBox(this.paths, this.currentTransform(transformation));
            }
        });
        MultiPath.prototype.nodeType = 'MultiPath';
        Paintable.extend(MultiPath.prototype);
        Measurable.extend(MultiPath.prototype);
        var ShapeMap = {
            l: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                for (var i = 0; i < parameters.length; i += 2) {
                    var point = new Point(parameters[i], parameters[i + 1]);
                    if (options.isRelative) {
                        point.translateWith(position);
                    }
                    path.lineTo(point.x, point.y);
                    position.x = point.x;
                    position.y = point.y;
                }
            },
            c: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                for (var i = 0; i < parameters.length; i += 6) {
                    var controlOut = new Point(parameters[i], parameters[i + 1]);
                    var controlIn = new Point(parameters[i + 2], parameters[i + 3]);
                    var point = new Point(parameters[i + 4], parameters[i + 5]);
                    if (options.isRelative) {
                        controlIn.translateWith(position);
                        controlOut.translateWith(position);
                        point.translateWith(position);
                    }
                    path.curveTo(controlOut, controlIn, point);
                    position.x = point.x;
                    position.y = point.y;
                }
            },
            v: function (path, options) {
                var value = options.isRelative ? 0 : options.position.x;
                toLineParamaters(options.parameters, true, value);
                this.l(path, options);
            },
            h: function (path, options) {
                var value = options.isRelative ? 0 : options.position.y;
                toLineParamaters(options.parameters, false, value);
                this.l(path, options);
            },
            a: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                for (var i = 0; i < parameters.length; i += 7) {
                    var radiusX = parameters[i];
                    var radiusY = parameters[i + 1];
                    var rotation = parameters[i + 2];
                    var largeArc = parameters[i + 3];
                    var swipe = parameters[i + 4];
                    var endPoint = new Point(parameters[i + 5], parameters[i + 6]);
                    if (options.isRelative) {
                        endPoint.translateWith(position);
                    }
                    if (position.x !== endPoint.x || position.y !== endPoint.y) {
                        path.arcTo(endPoint, radiusX, radiusY, largeArc, swipe, rotation);
                        position.x = endPoint.x;
                        position.y = endPoint.y;
                    }
                }
            },
            s: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                var previousCommand = options.previousCommand;
                var lastControlIn;
                if (previousCommand === 's' || previousCommand === 'c') {
                    lastControlIn = last(last(path.paths).segments).controlIn();
                }
                for (var i = 0; i < parameters.length; i += 4) {
                    var controlIn = new Point(parameters[i], parameters[i + 1]);
                    var endPoint = new Point(parameters[i + 2], parameters[i + 3]);
                    var controlOut = void 0;
                    if (options.isRelative) {
                        controlIn.translateWith(position);
                        endPoint.translateWith(position);
                    }
                    if (lastControlIn) {
                        controlOut = reflectionPoint(lastControlIn, position);
                    } else {
                        controlOut = position.clone();
                    }
                    lastControlIn = controlIn;
                    path.curveTo(controlOut, controlIn, endPoint);
                    position.x = endPoint.x;
                    position.y = endPoint.y;
                }
            },
            q: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                for (var i = 0; i < parameters.length; i += 4) {
                    var controlPoint = new Point(parameters[i], parameters[i + 1]);
                    var endPoint = new Point(parameters[i + 2], parameters[i + 3]);
                    if (options.isRelative) {
                        controlPoint.translateWith(position);
                        endPoint.translateWith(position);
                    }
                    var cubicControlPoints = quadraticToCubicControlPoints(position, controlPoint, endPoint);
                    path.curveTo(cubicControlPoints.controlOut, cubicControlPoints.controlIn, endPoint);
                    position.x = endPoint.x;
                    position.y = endPoint.y;
                }
            },
            t: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                var previousCommand = options.previousCommand;
                var controlPoint;
                if (previousCommand === 'q' || previousCommand === 't') {
                    var lastSegment = last(last(path.paths).segments);
                    controlPoint = lastSegment.controlIn().clone().translateWith(position.scaleCopy(-1 / 3)).scale(3 / 2);
                }
                for (var i = 0; i < parameters.length; i += 2) {
                    var endPoint = new Point(parameters[i], parameters[i + 1]);
                    if (options.isRelative) {
                        endPoint.translateWith(position);
                    }
                    if (controlPoint) {
                        controlPoint = reflectionPoint(controlPoint, position);
                    } else {
                        controlPoint = position.clone();
                    }
                    var cubicControlPoints = quadraticToCubicControlPoints(position, controlPoint, endPoint);
                    path.curveTo(cubicControlPoints.controlOut, cubicControlPoints.controlIn, endPoint);
                    position.x = endPoint.x;
                    position.y = endPoint.y;
                }
            }
        };
        function toLineParamaters(parameters, isVertical, value) {
            var insertPosition = isVertical ? 0 : 1;
            for (var i = 0; i < parameters.length; i += 2) {
                parameters.splice(i + insertPosition, 0, value);
            }
        }
        function reflectionPoint(point, center) {
            if (point && center) {
                return center.scaleCopy(2).translate(-point.x, -point.y);
            }
        }
        var third = 1 / 3;
        function quadraticToCubicControlPoints(position, controlPoint, endPoint) {
            var scaledPoint = controlPoint.clone().scale(2 / 3);
            return {
                controlOut: scaledPoint.clone().translateWith(position.scaleCopy(third)),
                controlIn: scaledPoint.translateWith(endPoint.scaleCopy(third))
            };
        }
        var SEGMENT_REGEX = /([a-df-z]{1})([^a-df-z]*)(z)?/gi;
        var SPLIT_REGEX = /[,\s]?([+\-]?(?:\d*\.\d+|\d+)(?:[eE][+\-]?\d+)?)/g;
        var MOVE = 'm';
        var CLOSE = 'z';
        function parseParameters(str) {
            var parameters = [];
            str.replace(SPLIT_REGEX, function (match, number) {
                parameters.push(parseFloat(number));
            });
            return parameters;
        }
        var PathParser = Class.extend({
            parse: function (str, options) {
                var multiPath = new MultiPath(options);
                var position = new Point();
                var previousCommand;
                str.replace(SEGMENT_REGEX, function (match, element, params, closePath) {
                    var command = element.toLowerCase();
                    var isRelative = command === element;
                    var parameters = parseParameters(params.trim());
                    if (command === MOVE) {
                        if (isRelative) {
                            position.x += parameters[0];
                            position.y += parameters[1];
                        } else {
                            position.x = parameters[0];
                            position.y = parameters[1];
                        }
                        multiPath.moveTo(position.x, position.y);
                        if (parameters.length > 2) {
                            command = 'l';
                            parameters.splice(0, 2);
                        }
                    }
                    if (ShapeMap[command]) {
                        ShapeMap[command](multiPath, {
                            parameters: parameters,
                            position: position,
                            isRelative: isRelative,
                            previousCommand: previousCommand
                        });
                        if (closePath && closePath.toLowerCase() === CLOSE) {
                            multiPath.close();
                        }
                    } else if (command !== MOVE) {
                        throw new Error('Error while parsing SVG path. Unsupported command: ' + command);
                    }
                    previousCommand = command;
                });
                return multiPath;
            }
        });
        PathParser.current = new PathParser();
        var Path = Element$1.extend({
            init: function (options) {
                Element$1.fn.init.call(this, options);
                this.segments = new GeometryElementsArray();
                this.segments.addObserver(this);
                if (!defined(this.options.stroke)) {
                    this.stroke('#000');
                    if (!defined(this.options.stroke.lineJoin)) {
                        this.options.set('stroke.lineJoin', 'miter');
                    }
                }
            },
            moveTo: function (x, y) {
                this.suspend();
                this.segments.elements([]);
                this.resume();
                this.lineTo(x, y);
                return this;
            },
            lineTo: function (x, y) {
                var point = defined(y) ? new Point(x, y) : x;
                var segment = new Segment(point);
                this.segments.push(segment);
                return this;
            },
            curveTo: function (controlOut, controlIn, point) {
                if (this.segments.length > 0) {
                    var lastSegment = last(this.segments);
                    var segment = new Segment(point, controlIn);
                    this.suspend();
                    lastSegment.controlOut(controlOut);
                    this.resume();
                    this.segments.push(segment);
                }
                return this;
            },
            arc: function (startAngle, endAngle, radiusX, radiusY, anticlockwise) {
                if (this.segments.length > 0) {
                    var lastSegment = last(this.segments);
                    var anchor = lastSegment.anchor();
                    var start = rad(startAngle);
                    var center = new Point(anchor.x - radiusX * Math.cos(start), anchor.y - radiusY * Math.sin(start));
                    var arc = new Arc$2(center, {
                        startAngle: startAngle,
                        endAngle: endAngle,
                        radiusX: radiusX,
                        radiusY: radiusY,
                        anticlockwise: anticlockwise
                    });
                    this._addArcSegments(arc);
                }
                return this;
            },
            arcTo: function (end, rx, ry, largeArc, swipe, rotation) {
                if (this.segments.length > 0) {
                    var lastSegment = last(this.segments);
                    var anchor = lastSegment.anchor();
                    var arc = Arc$2.fromPoints(anchor, end, rx, ry, largeArc, swipe, rotation);
                    this._addArcSegments(arc);
                }
                return this;
            },
            _addArcSegments: function (arc) {
                var this$1 = this;
                this.suspend();
                var curvePoints = arc.curvePoints();
                for (var i = 1; i < curvePoints.length; i += 3) {
                    this$1.curveTo(curvePoints[i], curvePoints[i + 1], curvePoints[i + 2]);
                }
                this.resume();
                this.geometryChange();
            },
            close: function () {
                this.options.closed = true;
                this.geometryChange();
                return this;
            },
            rawBBox: function () {
                return this._bbox();
            },
            _containsPoint: function (point) {
                var segments = this.segments;
                var length = segments.length;
                var intersectionsCount = 0;
                var previous, current;
                for (var idx = 1; idx < length; idx++) {
                    previous = segments[idx - 1];
                    current = segments[idx];
                    intersectionsCount += previous._intersectionsTo(current, point);
                }
                if (this.options.closed || !segments[0].anchor().equals(segments[length - 1].anchor())) {
                    intersectionsCount += lineIntersectionsCount(segments[0].anchor(), segments[length - 1].anchor(), point);
                }
                return intersectionsCount % 2 !== 0;
            },
            _isOnPath: function (point, width) {
                var segments = this.segments;
                var length = segments.length;
                var pathWidth = width || this.options.stroke.width;
                if (length > 1) {
                    if (segments[0]._isOnPathTo(segments[1], point, pathWidth, 'start')) {
                        return true;
                    }
                    for (var idx = 2; idx <= length - 2; idx++) {
                        if (segments[idx - 1]._isOnPathTo(segments[idx], point, pathWidth)) {
                            return true;
                        }
                    }
                    if (segments[length - 2]._isOnPathTo(segments[length - 1], point, pathWidth, 'end')) {
                        return true;
                    }
                }
                return false;
            },
            _bbox: function (matrix) {
                var segments = this.segments;
                var length = segments.length;
                var boundingBox;
                if (length === 1) {
                    var anchor = segments[0].anchor().transformCopy(matrix);
                    boundingBox = new Rect(anchor, Size.ZERO);
                } else if (length > 0) {
                    for (var i = 1; i < length; i++) {
                        var segmentBox = segments[i - 1].bboxTo(segments[i], matrix);
                        if (boundingBox) {
                            boundingBox = Rect.union(boundingBox, segmentBox);
                        } else {
                            boundingBox = segmentBox;
                        }
                    }
                }
                return boundingBox;
            }
        });
        Path.fromRect = function (rect, options) {
            return new Path(options).moveTo(rect.topLeft()).lineTo(rect.topRight()).lineTo(rect.bottomRight()).lineTo(rect.bottomLeft()).close();
        };
        Path.fromPoints = function (points, options) {
            if (points) {
                var path = new Path(options);
                for (var i = 0; i < points.length; i++) {
                    var point = Point.create(points[i]);
                    if (point) {
                        if (i === 0) {
                            path.moveTo(point);
                        } else {
                            path.lineTo(point);
                        }
                    }
                }
                return path;
            }
        };
        Path.fromArc = function (arc, options) {
            var path = new Path(options);
            var startAngle = arc.startAngle;
            var start = arc.pointAt(startAngle);
            path.moveTo(start.x, start.y);
            path.arc(startAngle, arc.endAngle, arc.radiusX, arc.radiusY, arc.anticlockwise);
            return path;
        };
        Path.prototype.nodeType = 'Path';
        Paintable.extend(Path.prototype);
        Measurable.extend(Path.prototype);
        Path.parse = function (str, options) {
            return PathParser.current.parse(str, options);
        };
        var DEFAULT_STROKE$1 = '#000';
        var Arc = Element$1.extend({
            init: function (geometry, options) {
                if (geometry === void 0) {
                    geometry = new Arc$2();
                }
                if (options === void 0) {
                    options = {};
                }
                Element$1.fn.init.call(this, options);
                this.geometry(geometry);
                if (!defined(this.options.stroke)) {
                    this.stroke(DEFAULT_STROKE$1);
                }
            },
            _bbox: function (matrix) {
                return this._geometry.bbox(matrix);
            },
            rawBBox: function () {
                return this.geometry().bbox();
            },
            toPath: function () {
                var path = new Path();
                var curvePoints = this.geometry().curvePoints();
                if (curvePoints.length > 0) {
                    path.moveTo(curvePoints[0].x, curvePoints[0].y);
                    for (var i = 1; i < curvePoints.length; i += 3) {
                        path.curveTo(curvePoints[i], curvePoints[i + 1], curvePoints[i + 2]);
                    }
                }
                return path;
            },
            _containsPoint: function (point) {
                return this.geometry().containsPoint(point);
            },
            _isOnPath: function (point) {
                return this.geometry()._isOnPath(point, this.options.stroke.width / 2);
            }
        });
        Arc.prototype.nodeType = 'Arc';
        Paintable.extend(Arc.prototype);
        Measurable.extend(Arc.prototype);
        defineGeometryAccessors(Arc.prototype, ['geometry']);
        var DEFAULT_FONT = '12px sans-serif';
        var DEFAULT_FILL = '#000';
        var Text = Element$1.extend({
            init: function (content, position, options) {
                if (position === void 0) {
                    position = new Point();
                }
                if (options === void 0) {
                    options = {};
                }
                Element$1.fn.init.call(this, options);
                this.content(content);
                this.position(position);
                if (!this.options.font) {
                    this.options.font = DEFAULT_FONT;
                }
                if (!defined(this.options.fill)) {
                    this.fill(DEFAULT_FILL);
                }
            },
            content: function (value) {
                if (defined(value)) {
                    this.options.set('content', value);
                    return this;
                }
                return this.options.get('content');
            },
            measure: function () {
                var metrics = kendoUtil.measureText(this.content(), { font: this.options.get('font') });
                return metrics;
            },
            rect: function () {
                var size = this.measure();
                var pos = this.position().clone();
                return new Rect(pos, [
                    size.width,
                    size.height
                ]);
            },
            bbox: function (transformation) {
                var combinedMatrix = toMatrix(this.currentTransform(transformation));
                return this.rect().bbox(combinedMatrix);
            },
            rawBBox: function () {
                return this.rect().bbox();
            },
            _containsPoint: function (point) {
                return this.rect().containsPoint(point);
            }
        });
        Text.prototype.nodeType = 'Text';
        Paintable.extend(Text.prototype);
        definePointAccessors(Text.prototype, ['position']);
        var Image$1 = Element$1.extend({
            init: function (src, rect, options) {
                if (rect === void 0) {
                    rect = new Rect();
                }
                if (options === void 0) {
                    options = {};
                }
                Element$1.fn.init.call(this, options);
                this.src(src);
                this.rect(rect);
            },
            src: function (value) {
                if (defined(value)) {
                    this.options.set('src', value);
                    return this;
                }
                return this.options.get('src');
            },
            bbox: function (transformation) {
                var combinedMatrix = toMatrix(this.currentTransform(transformation));
                return this._rect.bbox(combinedMatrix);
            },
            rawBBox: function () {
                return this._rect.bbox();
            },
            _containsPoint: function (point) {
                return this._rect.containsPoint(point);
            },
            _hasFill: function () {
                return this.src();
            }
        });
        Image$1.prototype.nodeType = 'Image';
        defineGeometryAccessors(Image$1.prototype, ['rect']);
        var Traversable = {
            extend: function (proto, childrenField) {
                proto.traverse = function (callback) {
                    var children = this[childrenField];
                    for (var i = 0; i < children.length; i++) {
                        var child = children[i];
                        if (child.traverse) {
                            child.traverse(callback);
                        } else {
                            callback(child);
                        }
                    }
                    return this;
                };
            }
        };
        var Group = Element$1.extend({
            init: function (options) {
                Element$1.fn.init.call(this, options);
                this.children = [];
            },
            childrenChange: function (action, items, index) {
                this.trigger('childrenChange', {
                    action: action,
                    items: items,
                    index: index
                });
            },
            append: function () {
                append(this.children, arguments);
                this._reparent(arguments, this);
                this.childrenChange('add', arguments);
                return this;
            },
            insert: function (index, element) {
                this.children.splice(index, 0, element);
                element.parent = this;
                this.childrenChange('add', [element], index);
                return this;
            },
            insertAt: function (element, index) {
                return this.insert(index, element);
            },
            remove: function (element) {
                var index = this.children.indexOf(element);
                if (index >= 0) {
                    this.children.splice(index, 1);
                    element.parent = null;
                    this.childrenChange('remove', [element], index);
                }
                return this;
            },
            removeAt: function (index) {
                if (0 <= index && index < this.children.length) {
                    var element = this.children[index];
                    this.children.splice(index, 1);
                    element.parent = null;
                    this.childrenChange('remove', [element], index);
                }
                return this;
            },
            clear: function () {
                var items = this.children;
                this.children = [];
                this._reparent(items, null);
                this.childrenChange('remove', items, 0);
                return this;
            },
            bbox: function (transformation) {
                return elementsBoundingBox(this.children, true, this.currentTransform(transformation));
            },
            rawBBox: function () {
                return elementsBoundingBox(this.children, false);
            },
            _clippedBBox: function (transformation) {
                return elementsClippedBoundingBox(this.children, this.currentTransform(transformation));
            },
            currentTransform: function (transformation) {
                return Element$1.prototype.currentTransform.call(this, transformation) || null;
            },
            containsPoint: function (point, parentTransform) {
                if (this.visible()) {
                    var children = this.children;
                    var transform = this.currentTransform(parentTransform);
                    for (var idx = 0; idx < children.length; idx++) {
                        if (children[idx].containsPoint(point, transform)) {
                            return true;
                        }
                    }
                }
                return false;
            },
            _reparent: function (elements, newParent) {
                var this$1 = this;
                for (var i = 0; i < elements.length; i++) {
                    var child = elements[i];
                    var parent = child.parent;
                    if (parent && parent !== this$1 && parent.remove) {
                        parent.remove(child);
                    }
                    child.parent = newParent;
                }
            }
        });
        Group.prototype.nodeType = 'Group';
        Traversable.extend(Group.prototype, 'children');
        function translateToPoint(point, bbox, element) {
            var transofrm = element.transform() || transform();
            var matrix = transofrm.matrix();
            matrix.e += point.x - bbox.origin.x;
            matrix.f += point.y - bbox.origin.y;
            transofrm.matrix(matrix);
            element.transform(transofrm);
        }
        function alignStart(size, rect, align, axis, sizeField) {
            var start;
            if (align === 'start') {
                start = rect.origin[axis];
            } else if (align === 'end') {
                start = rect.origin[axis] + rect.size[sizeField] - size;
            } else {
                start = rect.origin[axis] + (rect.size[sizeField] - size) / 2;
            }
            return start;
        }
        function alignStartReverse(size, rect, align, axis, sizeField) {
            var start;
            if (align === 'start') {
                start = rect.origin[axis] + rect.size[sizeField] - size;
            } else if (align === 'end') {
                start = rect.origin[axis];
            } else {
                start = rect.origin[axis] + (rect.size[sizeField] - size) / 2;
            }
            return start;
        }
        var DEFAULT_OPTIONS = {
            alignContent: 'start',
            justifyContent: 'start',
            alignItems: 'start',
            spacing: 0,
            orientation: 'horizontal',
            lineSpacing: 0,
            wrap: true,
            revers: false
        };
        var forEach = function (elements, callback) {
            elements.forEach(callback);
        };
        var forEachReverse = function (elements, callback) {
            var length = elements.length;
            for (var idx = length - 1; idx >= 0; idx--) {
                callback(elements[idx], idx);
            }
        };
        var Layout = Group.extend({
            init: function (rect, options) {
                Group.fn.init.call(this, $.extend({}, DEFAULT_OPTIONS, options));
                this._rect = rect;
                this._fieldMap = {};
            },
            rect: function (value) {
                if (value) {
                    this._rect = value;
                    return this;
                }
                return this._rect;
            },
            _initMap: function () {
                var options = this.options;
                var fieldMap = this._fieldMap;
                if (options.orientation === 'horizontal') {
                    fieldMap.sizeField = 'width';
                    fieldMap.groupsSizeField = 'height';
                    fieldMap.groupAxis = 'x';
                    fieldMap.groupsAxis = 'y';
                } else {
                    fieldMap.sizeField = 'height';
                    fieldMap.groupsSizeField = 'width';
                    fieldMap.groupAxis = 'y';
                    fieldMap.groupsAxis = 'x';
                }
                if (options.reverse) {
                    this.forEach = forEachReverse;
                    this.justifyAlign = alignStartReverse;
                } else {
                    this.forEach = forEach;
                    this.justifyAlign = alignStart;
                }
            },
            reflow: function () {
                var this$1 = this;
                if (!this._rect || this.children.length === 0) {
                    return;
                }
                this._initMap();
                if (this.options.transform) {
                    this.transform(null);
                }
                var options = this.options;
                var rect = this._rect;
                var ref = this._initGroups();
                var groups = ref.groups;
                var groupsSize = ref.groupsSize;
                var ref$1 = this._fieldMap;
                var sizeField = ref$1.sizeField;
                var groupsSizeField = ref$1.groupsSizeField;
                var groupAxis = ref$1.groupAxis;
                var groupsAxis = ref$1.groupsAxis;
                var groupOrigin = new Point();
                var elementOrigin = new Point();
                var size = new Size();
                var groupStart = alignStart(groupsSize, rect, options.alignContent, groupsAxis, groupsSizeField);
                var elementStart, group, groupBox;
                var arrangeElements = function (bbox, idx) {
                    var element = group.elements[idx];
                    elementOrigin[groupAxis] = elementStart;
                    elementOrigin[groupsAxis] = alignStart(bbox.size[groupsSizeField], groupBox, options.alignItems, groupsAxis, groupsSizeField);
                    translateToPoint(elementOrigin, bbox, element);
                    elementStart += bbox.size[sizeField] + options.spacing;
                };
                for (var groupIdx = 0; groupIdx < groups.length; groupIdx++) {
                    group = groups[groupIdx];
                    groupOrigin[groupAxis] = elementStart = this$1.justifyAlign(group.size, rect, options.justifyContent, groupAxis, sizeField);
                    groupOrigin[groupsAxis] = groupStart;
                    size[sizeField] = group.size;
                    size[groupsSizeField] = group.lineSize;
                    groupBox = new Rect(groupOrigin, size);
                    this$1.forEach(group.bboxes, arrangeElements);
                    groupStart += group.lineSize + options.lineSpacing;
                }
                if (!options.wrap && group.size > rect.size[sizeField]) {
                    var scale = rect.size[sizeField] / groupBox.size[sizeField];
                    var scaledStart = groupBox.topLeft().scale(scale, scale);
                    var scaledSize = groupBox.size[groupsSizeField] * scale;
                    var newStart = alignStart(scaledSize, rect, options.alignContent, groupsAxis, groupsSizeField);
                    var transform$$1 = transform();
                    if (groupAxis === 'x') {
                        transform$$1.translate(rect.origin.x - scaledStart.x, newStart - scaledStart.y);
                    } else {
                        transform$$1.translate(newStart - scaledStart.x, rect.origin.y - scaledStart.y);
                    }
                    transform$$1.scale(scale, scale);
                    this.transform(transform$$1);
                }
            },
            _initGroups: function () {
                var this$1 = this;
                var ref = this;
                var options = ref.options;
                var children = ref.children;
                var lineSpacing = options.lineSpacing;
                var wrap = options.wrap;
                var spacing = options.spacing;
                var sizeField = this._fieldMap.sizeField;
                var group = this._newGroup();
                var groups = [];
                var addGroup = function () {
                    groups.push(group);
                    groupsSize += group.lineSize + lineSpacing;
                };
                var groupsSize = -lineSpacing;
                for (var idx = 0; idx < children.length; idx++) {
                    var element = children[idx];
                    var bbox = children[idx].clippedBBox();
                    if (element.visible() && bbox) {
                        if (wrap && group.size + bbox.size[sizeField] + spacing > this$1._rect.size[sizeField]) {
                            if (group.bboxes.length === 0) {
                                this$1._addToGroup(group, bbox, element);
                                addGroup();
                                group = this$1._newGroup();
                            } else {
                                addGroup();
                                group = this$1._newGroup();
                                this$1._addToGroup(group, bbox, element);
                            }
                        } else {
                            this$1._addToGroup(group, bbox, element);
                        }
                    }
                }
                if (group.bboxes.length) {
                    addGroup();
                }
                return {
                    groups: groups,
                    groupsSize: groupsSize
                };
            },
            _addToGroup: function (group, bbox, element) {
                group.size += bbox.size[this._fieldMap.sizeField] + this.options.spacing;
                group.lineSize = Math.max(bbox.size[this._fieldMap.groupsSizeField], group.lineSize);
                group.bboxes.push(bbox);
                group.elements.push(element);
            },
            _newGroup: function () {
                return {
                    lineSize: 0,
                    size: -this.options.spacing,
                    bboxes: [],
                    elements: []
                };
            }
        });
        var Rect$2 = Element$1.extend({
            init: function (geometry, options) {
                if (geometry === void 0) {
                    geometry = new Rect();
                }
                if (options === void 0) {
                    options = {};
                }
                Element$1.fn.init.call(this, options);
                this.geometry(geometry);
                if (!defined(this.options.stroke)) {
                    this.stroke('#000');
                }
            },
            _bbox: function (matrix) {
                return this._geometry.bbox(matrix);
            },
            rawBBox: function () {
                return this._geometry.bbox();
            },
            _containsPoint: function (point) {
                return this._geometry.containsPoint(point);
            },
            _isOnPath: function (point) {
                return this.geometry()._isOnPath(point, this.options.stroke.width / 2);
            }
        });
        Rect$2.prototype.nodeType = 'Rect';
        Paintable.extend(Rect$2.prototype);
        Measurable.extend(Rect$2.prototype);
        defineGeometryAccessors(Rect$2.prototype, ['geometry']);
        function alignElements(elements, rect, alignment, axis, sizeField) {
            for (var idx = 0; idx < elements.length; idx++) {
                var bbox = elements[idx].clippedBBox();
                if (bbox) {
                    var point = bbox.origin.clone();
                    point[axis] = alignStart(bbox.size[sizeField], rect, alignment || 'start', axis, sizeField);
                    translateToPoint(point, bbox, elements[idx]);
                }
            }
        }
        function align(elements, rect, alignment) {
            alignElements(elements, rect, alignment, 'x', 'width');
        }
        function vAlign(elements, rect, alignment) {
            alignElements(elements, rect, alignment, 'y', 'height');
        }
        function stackElements(elements, stackAxis, otherAxis, sizeField) {
            if (elements.length > 1) {
                var origin = new Point();
                var previousBBox = elements[0].bbox;
                for (var idx = 1; idx < elements.length; idx++) {
                    var element = elements[idx].element;
                    var bbox = elements[idx].bbox;
                    origin[stackAxis] = previousBBox.origin[stackAxis] + previousBBox.size[sizeField];
                    origin[otherAxis] = bbox.origin[otherAxis];
                    translateToPoint(origin, bbox, element);
                    bbox.origin[stackAxis] = origin[stackAxis];
                    previousBBox = bbox;
                }
            }
        }
        function createStackElements(elements) {
            var stackElements = [];
            for (var idx = 0; idx < elements.length; idx++) {
                var element = elements[idx];
                var bbox = element.clippedBBox();
                if (bbox) {
                    stackElements.push({
                        element: element,
                        bbox: bbox
                    });
                }
            }
            return stackElements;
        }
        function stack(elements) {
            stackElements(createStackElements(elements), 'x', 'y', 'width');
        }
        function vStack(elements) {
            stackElements(createStackElements(elements), 'y', 'x', 'height');
        }
        function getStacks(elements, rect, sizeField) {
            var maxSize = rect.size[sizeField];
            var stacks = [];
            var stack = [];
            var stackSize = 0;
            var element, bbox;
            var addElementToStack = function () {
                stack.push({
                    element: element,
                    bbox: bbox
                });
            };
            for (var idx = 0; idx < elements.length; idx++) {
                element = elements[idx];
                bbox = element.clippedBBox();
                if (bbox) {
                    var size = bbox.size[sizeField];
                    if (stackSize + size > maxSize) {
                        if (stack.length) {
                            stacks.push(stack);
                            stack = [];
                            addElementToStack();
                            stackSize = size;
                        } else {
                            addElementToStack();
                            stacks.push(stack);
                            stack = [];
                            stackSize = 0;
                        }
                    } else {
                        addElementToStack();
                        stackSize += size;
                    }
                }
            }
            if (stack.length) {
                stacks.push(stack);
            }
            return stacks;
        }
        function wrapElements(elements, rect, axis, otherAxis, sizeField) {
            var stacks = getStacks(elements, rect, sizeField);
            var origin = rect.origin.clone();
            var result = [];
            for (var idx = 0; idx < stacks.length; idx++) {
                var stack = stacks[idx];
                var startElement = stack[0];
                origin[otherAxis] = startElement.bbox.origin[otherAxis];
                translateToPoint(origin, startElement.bbox, startElement.element);
                startElement.bbox.origin[axis] = origin[axis];
                stackElements(stack, axis, otherAxis, sizeField);
                result.push([]);
                for (var elementIdx = 0; elementIdx < stack.length; elementIdx++) {
                    result[idx].push(stack[elementIdx].element);
                }
            }
            return result;
        }
        function wrap(elements, rect) {
            return wrapElements(elements, rect, 'x', 'y', 'width');
        }
        function vWrap(elements, rect) {
            return wrapElements(elements, rect, 'y', 'x', 'height');
        }
        function fit(element, rect) {
            var bbox = element.clippedBBox();
            if (bbox) {
                var elementSize = bbox.size;
                var rectSize = rect.size;
                if (rectSize.width < elementSize.width || rectSize.height < elementSize.height) {
                    var scale = Math.min(rectSize.width / elementSize.width, rectSize.height / elementSize.height);
                    var transform$$1 = element.transform() || transform();
                    transform$$1.scale(scale, scale);
                    element.transform(transform$$1);
                }
            }
        }
        var StopsArray = ElementsArray.extend({
            _change: function () {
                this.optionsChange({ field: 'stops' });
            }
        });
        function optionsAccessor(name) {
            return function (value) {
                if (defined(value)) {
                    this.options.set(name, value);
                    return this;
                }
                return this.options.get(name);
            };
        }
        function defineOptionsAccessors(fn, names) {
            for (var i = 0; i < names.length; i++) {
                fn[names[i]] = optionsAccessor(names[i]);
            }
        }
        var GradientStop = Class.extend({
            init: function (offset, color, opacity) {
                this.options = new OptionsStore({
                    offset: offset,
                    color: color,
                    opacity: defined(opacity) ? opacity : 1
                });
                this.options.addObserver(this);
            }
        });
        GradientStop.create = function (arg) {
            if (defined(arg)) {
                var stop;
                if (arg instanceof GradientStop) {
                    stop = arg;
                } else if (arg.length > 1) {
                    stop = new GradientStop(arg[0], arg[1], arg[2]);
                } else {
                    stop = new GradientStop(arg.offset, arg.color, arg.opacity);
                }
                return stop;
            }
        };
        defineOptionsAccessors(GradientStop.prototype, [
            'offset',
            'color',
            'opacity'
        ]);
        ObserversMixin.extend(GradientStop.prototype);
        var Gradient = Class.extend({
            init: function (options) {
                if (options === void 0) {
                    options = {};
                }
                this.stops = new StopsArray(this._createStops(options.stops));
                this.stops.addObserver(this);
                this._userSpace = options.userSpace;
                this.id = definitionId();
            },
            userSpace: function (value) {
                if (defined(value)) {
                    this._userSpace = value;
                    this.optionsChange();
                    return this;
                }
                return this._userSpace;
            },
            _createStops: function (stops) {
                if (stops === void 0) {
                    stops = [];
                }
                var result = [];
                for (var idx = 0; idx < stops.length; idx++) {
                    result.push(GradientStop.create(stops[idx]));
                }
                return result;
            },
            addStop: function (offset, color, opacity) {
                this.stops.push(new GradientStop(offset, color, opacity));
            },
            removeStop: function (stop) {
                var index = this.stops.indexOf(stop);
                if (index >= 0) {
                    this.stops.splice(index, 1);
                }
            }
        });
        Gradient.prototype.nodeType = 'Gradient';
        ObserversMixin.extend(Gradient.prototype);
        $.extend(Gradient.prototype, {
            optionsChange: function (e) {
                this.trigger('optionsChange', {
                    field: 'gradient' + (e ? '.' + e.field : ''),
                    value: this
                });
            },
            geometryChange: function () {
                this.optionsChange();
            }
        });
        var LinearGradient = Gradient.extend({
            init: function (options) {
                if (options === void 0) {
                    options = {};
                }
                Gradient.fn.init.call(this, options);
                this.start(options.start || new Point());
                this.end(options.end || new Point(1, 0));
            }
        });
        definePointAccessors(LinearGradient.prototype, [
            'start',
            'end'
        ]);
        var RadialGradient = Gradient.extend({
            init: function (options) {
                if (options === void 0) {
                    options = {};
                }
                Gradient.fn.init.call(this, options);
                this.center(options.center || new Point());
                this._radius = defined(options.radius) ? options.radius : 1;
                this._fallbackFill = options.fallbackFill;
            },
            radius: function (value) {
                if (defined(value)) {
                    this._radius = value;
                    this.geometryChange();
                    return this;
                }
                return this._radius;
            },
            fallbackFill: function (value) {
                if (defined(value)) {
                    this._fallbackFill = value;
                    this.optionsChange();
                    return this;
                }
                return this._fallbackFill;
            }
        });
        definePointAccessors(RadialGradient.prototype, ['center']);
        function swing(position) {
            return 0.5 - Math.cos(position * Math.PI) / 2;
        }
        function linear(position) {
            return position;
        }
        function easeOutElastic(position, time, start, diff) {
            var s = 1.70158, p = 0, a = diff;
            if (position === 0) {
                return start;
            }
            if (position === 1) {
                return start + diff;
            }
            if (!p) {
                p = 0.5;
            }
            if (a < Math.abs(diff)) {
                a = diff;
                s = p / 4;
            } else {
                s = p / (2 * Math.PI) * Math.asin(diff / a);
            }
            return a * Math.pow(2, -10 * position) * Math.sin((Number(position) - s) * (1.1 * Math.PI) / p) + diff + start;
        }
        var easingFunctions = {
            swing: swing,
            linear: linear,
            easeOutElastic: easeOutElastic
        };
        var AnimationFactory = Class.extend({
            init: function () {
                this._items = [];
            },
            register: function (name, type) {
                this._items.push({
                    name: name,
                    type: type
                });
            },
            create: function (element, options) {
                var items = this._items;
                var match;
                if (options && options.type) {
                    var type = options.type.toLowerCase();
                    for (var i = 0; i < items.length; i++) {
                        if (items[i].name.toLowerCase() === type) {
                            match = items[i];
                            break;
                        }
                    }
                }
                if (match) {
                    return new match.type(element, options);
                }
            }
        });
        AnimationFactory.current = new AnimationFactory();
        var now = Date.now || function () {
            return new Date().getTime();
        };
        var Animation = Class.extend({
            init: function (element, options) {
                this.options = $.extend({}, this.options, options);
                this.element = element;
            },
            setup: function () {
            },
            step: function () {
            },
            play: function () {
                var this$1 = this;
                var options = this.options;
                var duration = options.duration;
                var delay = options.delay;
                if (delay === void 0) {
                    delay = 0;
                }
                var easing = easingFunctions[options.easing];
                var start = now() + delay;
                var finish = start + duration;
                if (duration === 0) {
                    this.step(1);
                    this.abort();
                } else {
                    setTimeout(function () {
                        var loop = function () {
                            if (this$1._stopped) {
                                return;
                            }
                            var wallTime = now();
                            var time = limitValue(wallTime - start, 0, duration);
                            var position = time / duration;
                            var easingPosition = easing(position, time, 0, 1, duration);
                            this$1.step(easingPosition);
                            if (wallTime < finish) {
                                kendo.animationFrame(loop);
                            } else {
                                this$1.abort();
                            }
                        };
                        loop();
                    }, delay);
                }
            },
            abort: function () {
                this._stopped = true;
            },
            destroy: function () {
                this.abort();
            }
        });
        Animation.prototype.options = {
            duration: 500,
            easing: 'swing'
        };
        Animation.create = function (type, element, options) {
            return AnimationFactory.current.create(type, element, options);
        };
        var SurfaceFactory = Class.extend({
            init: function () {
                this._items = [];
            },
            register: function (name, type, order) {
                var items = this._items;
                var first = items[0];
                var entry = {
                    name: name,
                    type: type,
                    order: order
                };
                if (!first || order < first.order) {
                    items.unshift(entry);
                } else {
                    items.push(entry);
                }
            },
            create: function (element, options) {
                var items = this._items;
                var match = items[0];
                if (options && options.type) {
                    var preferred = options.type.toLowerCase();
                    for (var i = 0; i < items.length; i++) {
                        if (items[i].name === preferred) {
                            match = items[i];
                            break;
                        }
                    }
                }
                if (match) {
                    return new match.type(element, options);
                }
                kendo.logToConsole('Warning: Unable to create Kendo UI Drawing Surface. Possible causes:\n' + '- The browser does not support SVG and Canvas. User agent: ' + navigator.userAgent);
            }
        });
        SurfaceFactory.current = new SurfaceFactory();
        var events = [
            'click',
            'mouseenter',
            'mouseleave',
            'mousemove',
            'resize'
        ];
        var Surface = kendo.Observable.extend({
            init: function (element, options) {
                kendo.Observable.fn.init.call(this);
                this.options = $.extend({}, options);
                this.element = element;
                this.element._kendoExportVisual = this.exportVisual.bind(this);
                this._click = this._handler('click');
                this._mouseenter = this._handler('mouseenter');
                this._mouseleave = this._handler('mouseleave');
                this._mousemove = this._handler('mousemove');
                this._visual = new Group();
                elementSize(element, this.options);
                this.bind(events, this.options);
                this._enableTracking();
            },
            draw: function (element) {
                this._visual.children.push(element);
            },
            clear: function () {
                this._visual.children = [];
            },
            destroy: function () {
                this._visual = null;
                this.element._kendoExportVisual = null;
                this.unbind();
            },
            eventTarget: function (e) {
                var this$1 = this;
                var domNode = eventElement(e);
                var node;
                while (!node && domNode) {
                    node = domNode._kendoNode;
                    if (domNode === this$1.element) {
                        break;
                    }
                    domNode = domNode.parentElement;
                }
                if (node) {
                    return node.srcElement;
                }
            },
            exportVisual: function () {
                return this._visual;
            },
            getSize: function () {
                return elementSize(this.element);
            },
            currentSize: function (size) {
                if (size) {
                    this._size = size;
                } else {
                    return this._size;
                }
            },
            setSize: function (size) {
                elementSize(this.element, size);
                this.currentSize(size);
                this._resize();
            },
            resize: function (force) {
                var size = this.getSize();
                var currentSize = this.currentSize();
                if (force || (size.width > 0 || size.height > 0) && (!currentSize || size.width !== currentSize.width || size.height !== currentSize.height)) {
                    this.currentSize(size);
                    this._resize(size, force);
                    this.trigger('resize', size);
                }
            },
            size: function (value) {
                if (!value) {
                    return this.getSize();
                }
                this.setSize(value);
            },
            suspendTracking: function () {
                this._suspendedTracking = true;
            },
            resumeTracking: function () {
                this._suspendedTracking = false;
            },
            _enableTracking: function () {
            },
            _resize: function () {
            },
            _handler: function (eventName) {
                var this$1 = this;
                return function (e) {
                    var node = this$1.eventTarget(e);
                    if (node && !this$1._suspendedTracking) {
                        this$1.trigger(eventName, {
                            element: node,
                            originalEvent: e,
                            type: eventName
                        });
                    }
                };
            },
            _elementOffset: function () {
                var element = this.element;
                var ref = elementStyles(element, [
                    'paddingLeft',
                    'paddingTop'
                ]);
                var paddingLeft = ref.paddingLeft;
                var paddingTop = ref.paddingTop;
                var ref$1 = elementOffset(element);
                var left = ref$1.left;
                var top = ref$1.top;
                return {
                    left: left + parseInt(paddingLeft, 10),
                    top: top + parseInt(paddingTop, 10)
                };
            },
            _surfacePoint: function (e) {
                var offset = this._elementOffset();
                var coord = eventCoordinates(e);
                var x = coord.x - offset.left;
                var y = coord.y - offset.top;
                return new Point(x, y);
            }
        });
        Surface.create = function (element, options) {
            return SurfaceFactory.current.create(element, options);
        };
        Surface.support = {};
        var BaseNode = Class.extend({
            init: function (srcElement) {
                this.childNodes = [];
                this.parent = null;
                if (srcElement) {
                    this.srcElement = srcElement;
                    this.observe();
                }
            },
            destroy: function () {
                var this$1 = this;
                if (this.srcElement) {
                    this.srcElement.removeObserver(this);
                }
                var children = this.childNodes;
                for (var i = 0; i < children.length; i++) {
                    this$1.childNodes[i].destroy();
                }
                this.parent = null;
            },
            load: function () {
            },
            observe: function () {
                if (this.srcElement) {
                    this.srcElement.addObserver(this);
                }
            },
            append: function (node) {
                this.childNodes.push(node);
                node.parent = this;
            },
            insertAt: function (node, pos) {
                this.childNodes.splice(pos, 0, node);
                node.parent = this;
            },
            remove: function (index, count) {
                var this$1 = this;
                var end = index + count;
                for (var i = index; i < end; i++) {
                    this$1.childNodes[i].removeSelf();
                }
                this.childNodes.splice(index, count);
            },
            removeSelf: function () {
                this.clear();
                this.destroy();
            },
            clear: function () {
                this.remove(0, this.childNodes.length);
            },
            invalidate: function () {
                if (this.parent) {
                    this.parent.invalidate();
                }
            },
            geometryChange: function () {
                this.invalidate();
            },
            optionsChange: function () {
                this.invalidate();
            },
            childrenChange: function (e) {
                if (e.action === 'add') {
                    this.load(e.items, e.index);
                } else if (e.action === 'remove') {
                    this.remove(e.index, e.items.length);
                }
                this.invalidate();
            }
        });
        function renderAttr(name, value) {
            return defined(value) && value !== null ? ' ' + name + '="' + value + '" ' : '';
        }
        function renderAllAttr(attrs) {
            var output = '';
            for (var i = 0; i < attrs.length; i++) {
                output += renderAttr(attrs[i][0], attrs[i][1]);
            }
            return output;
        }
        function renderStyle(attrs) {
            var output = '';
            for (var i = 0; i < attrs.length; i++) {
                var value = attrs[i][1];
                if (defined(value)) {
                    output += attrs[i][0] + ':' + value + ';';
                }
            }
            if (output !== '') {
                return output;
            }
        }
        var NODE_MAP = {};
        var SVG_NS = 'http://www.w3.org/2000/svg';
        var NONE = 'none';
        var renderSVG = function (container, svg) {
            container.innerHTML = svg;
        };
        if (typeof document !== 'undefined') {
            var testFragment = '<svg xmlns=\'' + SVG_NS + '\'></svg>';
            var testContainer = document.createElement('div');
            var hasParser = typeof DOMParser !== 'undefined';
            testContainer.innerHTML = testFragment;
            if (hasParser && testContainer.firstChild.namespaceURI !== SVG_NS) {
                renderSVG = function (container, svg) {
                    var parser = new DOMParser();
                    var chartDoc = parser.parseFromString(svg, 'text/xml');
                    var importedDoc = document.adoptNode(chartDoc.documentElement);
                    container.innerHTML = '';
                    container.appendChild(importedDoc);
                };
            }
        }
        var renderSVG$1 = renderSVG;
        var TRANSFORM = 'transform';
        var DefinitionMap = {
            clip: 'clip-path',
            fill: 'fill'
        };
        function isDefinition(type, value) {
            return type === 'clip' || type === 'fill' && (!value || value.nodeType === 'Gradient');
        }
        function baseUrl() {
            var base = document.getElementsByTagName('base')[0];
            var href = document.location.href;
            var url = '';
            if (base && !supportBrowser.msie) {
                var hashIndex = href.indexOf('#');
                if (hashIndex !== -1) {
                    href = href.substring(0, hashIndex);
                }
                url = href;
            }
            return url;
        }
        var Node = BaseNode.extend({
            init: function (srcElement, options) {
                BaseNode.fn.init.call(this, srcElement);
                this.definitions = {};
                this.options = options;
            },
            destroy: function () {
                if (this.element) {
                    this.element._kendoNode = null;
                    this.element = null;
                }
                this.clearDefinitions();
                BaseNode.fn.destroy.call(this);
            },
            load: function (elements, pos) {
                var this$1 = this;
                for (var i = 0; i < elements.length; i++) {
                    var srcElement = elements[i];
                    var children = srcElement.children;
                    var childNode = new NODE_MAP[srcElement.nodeType](srcElement, this$1.options);
                    if (defined(pos)) {
                        this$1.insertAt(childNode, pos);
                    } else {
                        this$1.append(childNode);
                    }
                    childNode.createDefinitions();
                    if (children && children.length > 0) {
                        childNode.load(children);
                    }
                    var element = this$1.element;
                    if (element) {
                        childNode.attachTo(element, pos);
                    }
                }
            },
            root: function () {
                var root = this;
                while (root.parent) {
                    root = root.parent;
                }
                return root;
            },
            attachTo: function (domElement, pos) {
                var container = document.createElement('div');
                renderSVG$1(container, '<svg xmlns=\'' + SVG_NS + '\' version=\'1.1\'>' + this.render() + '</svg>');
                var element = container.firstChild.firstChild;
                if (element) {
                    if (defined(pos)) {
                        domElement.insertBefore(element, domElement.childNodes[pos] || null);
                    } else {
                        domElement.appendChild(element);
                    }
                    this.setElement(element);
                }
            },
            setElement: function (element) {
                if (this.element) {
                    this.element._kendoNode = null;
                }
                this.element = element;
                this.element._kendoNode = this;
                var nodes = this.childNodes;
                for (var i = 0; i < nodes.length; i++) {
                    var childElement = element.childNodes[i];
                    nodes[i].setElement(childElement);
                }
            },
            clear: function () {
                this.clearDefinitions();
                if (this.element) {
                    this.element.innerHTML = '';
                }
                var children = this.childNodes;
                for (var i = 0; i < children.length; i++) {
                    children[i].destroy();
                }
                this.childNodes = [];
            },
            removeSelf: function () {
                if (this.element) {
                    var parentNode = this.element.parentNode;
                    if (parentNode) {
                        parentNode.removeChild(this.element);
                    }
                    this.element = null;
                }
                BaseNode.fn.removeSelf.call(this);
            },
            template: function () {
                return this.renderChildren();
            },
            render: function () {
                return this.template();
            },
            renderChildren: function () {
                var nodes = this.childNodes;
                var output = '';
                for (var i = 0; i < nodes.length; i++) {
                    output += nodes[i].render();
                }
                return output;
            },
            optionsChange: function (e) {
                var field = e.field;
                var value = e.value;
                if (field === 'visible') {
                    this.css('display', value ? '' : NONE);
                } else if (DefinitionMap[field] && isDefinition(field, value)) {
                    this.updateDefinition(field, value);
                } else if (field === 'opacity') {
                    this.attr('opacity', value);
                } else if (field === 'cursor') {
                    this.css('cursor', value);
                } else if (field === 'id') {
                    if (value) {
                        this.attr('id', value);
                    } else {
                        this.removeAttr('id');
                    }
                }
                BaseNode.fn.optionsChange.call(this, e);
            },
            attr: function (name, value) {
                if (this.element) {
                    this.element.setAttribute(name, value);
                }
            },
            allAttr: function (attrs) {
                var this$1 = this;
                for (var i = 0; i < attrs.length; i++) {
                    this$1.attr(attrs[i][0], attrs[i][1]);
                }
            },
            css: function (name, value) {
                if (this.element) {
                    this.element.style[name] = value;
                }
            },
            allCss: function (styles) {
                var this$1 = this;
                for (var i = 0; i < styles.length; i++) {
                    this$1.css(styles[i][0], styles[i][1]);
                }
            },
            removeAttr: function (name) {
                if (this.element) {
                    this.element.removeAttribute(name);
                }
            },
            mapTransform: function (transform) {
                var attrs = [];
                if (transform) {
                    attrs.push([
                        TRANSFORM,
                        'matrix(' + transform.matrix().toString(6) + ')'
                    ]);
                }
                return attrs;
            },
            renderTransform: function () {
                return renderAllAttr(this.mapTransform(this.srcElement.transform()));
            },
            transformChange: function (value) {
                if (value) {
                    this.allAttr(this.mapTransform(value));
                } else {
                    this.removeAttr(TRANSFORM);
                }
            },
            mapStyle: function () {
                var options = this.srcElement.options;
                var style = [[
                        'cursor',
                        options.cursor
                    ]];
                if (options.visible === false) {
                    style.push([
                        'display',
                        NONE
                    ]);
                }
                return style;
            },
            renderStyle: function () {
                return renderAttr('style', renderStyle(this.mapStyle(true)));
            },
            renderOpacity: function () {
                return renderAttr('opacity', this.srcElement.options.opacity);
            },
            renderId: function () {
                return renderAttr('id', this.srcElement.options.id);
            },
            createDefinitions: function () {
                var srcElement = this.srcElement;
                var definitions = this.definitions;
                if (srcElement) {
                    var options = srcElement.options;
                    var hasDefinitions;
                    for (var field in DefinitionMap) {
                        var definition = options.get(field);
                        if (definition && isDefinition(field, definition)) {
                            definitions[field] = definition;
                            hasDefinitions = true;
                        }
                    }
                    if (hasDefinitions) {
                        this.definitionChange({
                            action: 'add',
                            definitions: definitions
                        });
                    }
                }
            },
            definitionChange: function (e) {
                if (this.parent) {
                    this.parent.definitionChange(e);
                }
            },
            updateDefinition: function (type, value) {
                var definitions = this.definitions;
                var current = definitions[type];
                var attr = DefinitionMap[type];
                var definition = {};
                if (current) {
                    definition[type] = current;
                    this.definitionChange({
                        action: 'remove',
                        definitions: definition
                    });
                    delete definitions[type];
                }
                if (!value) {
                    if (current) {
                        this.removeAttr(attr);
                    }
                } else {
                    definition[type] = value;
                    this.definitionChange({
                        action: 'add',
                        definitions: definition
                    });
                    definitions[type] = value;
                    this.attr(attr, this.refUrl(value.id));
                }
            },
            clearDefinitions: function () {
                var definitions = this.definitions;
                this.definitionChange({
                    action: 'remove',
                    definitions: definitions
                });
                this.definitions = {};
            },
            renderDefinitions: function () {
                return renderAllAttr(this.mapDefinitions());
            },
            mapDefinitions: function () {
                var this$1 = this;
                var definitions = this.definitions;
                var attrs = [];
                for (var field in definitions) {
                    attrs.push([
                        DefinitionMap[field],
                        this$1.refUrl(definitions[field].id)
                    ]);
                }
                return attrs;
            },
            refUrl: function (id) {
                var skipBaseHref = (this.options || {}).skipBaseHref;
                var baseHref = this.baseUrl().replace(/'/g, '\\\'');
                var base = skipBaseHref ? '' : baseHref;
                return 'url(' + base + '#' + id + ')';
            },
            baseUrl: function () {
                return baseUrl();
            }
        });
        var GradientStopNode = Node.extend({
            template: function () {
                return '<stop ' + this.renderOffset() + ' ' + this.renderStyle() + ' />';
            },
            renderOffset: function () {
                return renderAttr('offset', this.srcElement.offset());
            },
            mapStyle: function () {
                var srcElement = this.srcElement;
                return [
                    [
                        'stop-color',
                        srcElement.color()
                    ],
                    [
                        'stop-opacity',
                        srcElement.opacity()
                    ]
                ];
            },
            optionsChange: function (e) {
                if (e.field === 'offset') {
                    this.attr(e.field, e.value);
                } else if (e.field === 'color' || e.field === 'opacity') {
                    this.css('stop-' + e.field, e.value);
                }
            }
        });
        var GradientNode = Node.extend({
            init: function (srcElement) {
                Node.fn.init.call(this, srcElement);
                this.id = srcElement.id;
                this.loadStops();
            },
            loadStops: function () {
                var this$1 = this;
                var stops = this.srcElement.stops;
                var element = this.element;
                for (var idx = 0; idx < stops.length; idx++) {
                    var stopNode = new GradientStopNode(stops[idx]);
                    this$1.append(stopNode);
                    if (element) {
                        stopNode.attachTo(element);
                    }
                }
            },
            optionsChange: function (e) {
                if (e.field === 'gradient.stops') {
                    BaseNode.prototype.clear.call(this);
                    this.loadStops();
                } else if (e.field === 'gradient') {
                    this.allAttr(this.mapCoordinates());
                }
            },
            renderCoordinates: function () {
                return renderAllAttr(this.mapCoordinates());
            },
            mapSpace: function () {
                return [
                    'gradientUnits',
                    this.srcElement.userSpace() ? 'userSpaceOnUse' : 'objectBoundingBox'
                ];
            }
        });
        var LinearGradientNode = GradientNode.extend({
            template: function () {
                return '<linearGradient id=\'' + this.id + '\' ' + this.renderCoordinates() + '>' + this.renderChildren() + '</linearGradient>';
            },
            mapCoordinates: function () {
                var srcElement = this.srcElement;
                var start = srcElement.start();
                var end = srcElement.end();
                var attrs = [
                    [
                        'x1',
                        start.x
                    ],
                    [
                        'y1',
                        start.y
                    ],
                    [
                        'x2',
                        end.x
                    ],
                    [
                        'y2',
                        end.y
                    ],
                    this.mapSpace()
                ];
                return attrs;
            }
        });
        var RadialGradientNode = GradientNode.extend({
            template: function () {
                return '<radialGradient id=\'' + this.id + '\' ' + this.renderCoordinates() + '>' + this.renderChildren() + '</radialGradient>';
            },
            mapCoordinates: function () {
                var srcElement = this.srcElement;
                var center = srcElement.center();
                var radius = srcElement.radius();
                var attrs = [
                    [
                        'cx',
                        center.x
                    ],
                    [
                        'cy',
                        center.y
                    ],
                    [
                        'r',
                        radius
                    ],
                    this.mapSpace()
                ];
                return attrs;
            }
        });
        var ClipNode = Node.extend({
            init: function (srcElement) {
                Node.fn.init.call(this);
                this.srcElement = srcElement;
                this.id = srcElement.id;
                this.load([srcElement]);
            },
            template: function () {
                return '<clipPath id=\'' + this.id + '\'>' + this.renderChildren() + '</clipPath>';
            }
        });
        var DefinitionNode = Node.extend({
            init: function () {
                Node.fn.init.call(this);
                this.definitionMap = {};
            },
            attachTo: function (domElement) {
                this.element = domElement;
            },
            template: function () {
                return '<defs>' + this.renderChildren() + '</defs>';
            },
            definitionChange: function (e) {
                var definitions = e.definitions;
                var action = e.action;
                if (action === 'add') {
                    this.addDefinitions(definitions);
                } else if (action === 'remove') {
                    this.removeDefinitions(definitions);
                }
            },
            createDefinition: function (type, item) {
                var nodeType;
                if (type === 'clip') {
                    nodeType = ClipNode;
                } else if (type === 'fill') {
                    if (item instanceof LinearGradient) {
                        nodeType = LinearGradientNode;
                    } else if (item instanceof RadialGradient) {
                        nodeType = RadialGradientNode;
                    }
                }
                return new nodeType(item);
            },
            addDefinitions: function (definitions) {
                var this$1 = this;
                for (var field in definitions) {
                    this$1.addDefinition(field, definitions[field]);
                }
            },
            addDefinition: function (type, srcElement) {
                var ref = this;
                var element = ref.element;
                var definitionMap = ref.definitionMap;
                var id = srcElement.id;
                var mapItem = definitionMap[id];
                if (!mapItem) {
                    var node = this.createDefinition(type, srcElement);
                    definitionMap[id] = {
                        element: node,
                        count: 1
                    };
                    this.append(node);
                    if (element) {
                        node.attachTo(this.element);
                    }
                } else {
                    mapItem.count++;
                }
            },
            removeDefinitions: function (definitions) {
                var this$1 = this;
                for (var field in definitions) {
                    this$1.removeDefinition(definitions[field]);
                }
            },
            removeDefinition: function (srcElement) {
                var definitionMap = this.definitionMap;
                var id = srcElement.id;
                var mapItem = definitionMap[id];
                if (mapItem) {
                    mapItem.count--;
                    if (mapItem.count === 0) {
                        this.remove(this.childNodes.indexOf(mapItem.element), 1);
                        delete definitionMap[id];
                    }
                }
            }
        });
        var RootNode = Node.extend({
            init: function (options) {
                Node.fn.init.call(this);
                this.options = options;
                this.defs = new DefinitionNode();
            },
            attachTo: function (domElement) {
                this.element = domElement;
                this.defs.attachTo(domElement.firstElementChild);
            },
            clear: function () {
                BaseNode.prototype.clear.call(this);
            },
            template: function () {
                return this.defs.render() + this.renderChildren();
            },
            definitionChange: function (e) {
                this.defs.definitionChange(e);
            }
        });
        var RTL = 'rtl';
        function alignToScreen(element) {
            var ctm;
            try {
                ctm = element.getScreenCTM ? element.getScreenCTM() : null;
            } catch (e) {
            }
            if (ctm) {
                var left = -ctm.e % 1;
                var top = -ctm.f % 1;
                var style = element.style;
                if (left !== 0 || top !== 0) {
                    style.left = left + 'px';
                    style.top = top + 'px';
                }
            }
        }
        var Surface$1 = Surface.extend({
            init: function (element, options) {
                Surface.fn.init.call(this, element, options);
                this._root = new RootNode($.extend({ rtl: elementStyles(element, 'direction').direction === RTL }, this.options));
                renderSVG$1(this.element, this._template());
                this._rootElement = this.element.firstElementChild;
                alignToScreen(this._rootElement);
                this._root.attachTo(this._rootElement);
                bindEvents(this.element, {
                    click: this._click,
                    mouseover: this._mouseenter,
                    mouseout: this._mouseleave,
                    mousemove: this._mousemove
                });
                this.resize();
            },
            destroy: function () {
                if (this._root) {
                    this._root.destroy();
                    this._root = null;
                    this._rootElement = null;
                    unbindEvents(this.element, {
                        click: this._click,
                        mouseover: this._mouseenter,
                        mouseout: this._mouseleave,
                        mousemove: this._mousemove
                    });
                }
                Surface.fn.destroy.call(this);
            },
            translate: function (offset) {
                var viewBox = Math.round(offset.x) + ' ' + Math.round(offset.y) + ' ' + this._size.width + ' ' + this._size.height;
                this._offset = offset;
                this._rootElement.setAttribute('viewBox', viewBox);
            },
            draw: function (element) {
                Surface.fn.draw.call(this, element);
                this._root.load([element]);
            },
            clear: function () {
                Surface.fn.clear.call(this);
                this._root.clear();
            },
            svg: function () {
                return '<?xml version=\'1.0\' ?>' + this._template();
            },
            exportVisual: function () {
                var ref = this;
                var visual = ref._visual;
                var offset = ref._offset;
                if (offset) {
                    var wrap = new Group();
                    wrap.children.push(visual);
                    wrap.transform(transform().translate(-offset.x, -offset.y));
                    visual = wrap;
                }
                return visual;
            },
            _resize: function () {
                if (this._offset) {
                    this.translate(this._offset);
                }
            },
            _template: function () {
                return '<svg style=\'width: 100%; height: 100%; overflow: hidden;\' xmlns=\'' + SVG_NS + '\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' version=\'1.1\'>' + this._root.render() + '</svg>';
            }
        });
        Surface$1.prototype.type = 'svg';
        if (typeof document !== 'undefined' && document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1')) {
            Surface.support.svg = true;
            SurfaceFactory.current.register('svg', Surface$1, 10);
        }
        var GroupNode = Node.extend({
            template: function () {
                return '<g' + (this.renderId() + this.renderTransform() + this.renderStyle() + this.renderOpacity() + this.renderDefinitions()) + '>' + this.renderChildren() + '</g>';
            },
            optionsChange: function (e) {
                if (e.field === 'transform') {
                    this.transformChange(e.value);
                }
                Node.fn.optionsChange.call(this, e);
            }
        });
        NODE_MAP.Group = GroupNode;
        var DASH_ARRAYS = {
            dot: [
                1.5,
                3.5
            ],
            dash: [
                4,
                3.5
            ],
            longdash: [
                8,
                3.5
            ],
            dashdot: [
                3.5,
                3.5,
                1.5,
                3.5
            ],
            longdashdot: [
                8,
                3.5,
                1.5,
                3.5
            ],
            longdashdotdot: [
                8,
                3.5,
                1.5,
                3.5,
                1.5,
                3.5
            ]
        };
        var SOLID = 'solid';
        var BUTT = 'butt';
        var ATTRIBUTE_MAP = {
            'fill.opacity': 'fill-opacity',
            'stroke.color': 'stroke',
            'stroke.width': 'stroke-width',
            'stroke.opacity': 'stroke-opacity'
        };
        var SPACE = ' ';
        var PathNode = Node.extend({
            geometryChange: function () {
                this.attr('d', this.renderData());
                this.invalidate();
            },
            optionsChange: function (e) {
                switch (e.field) {
                case 'fill':
                    if (e.value) {
                        this.allAttr(this.mapFill(e.value));
                    } else {
                        this.removeAttr('fill');
                    }
                    break;
                case 'fill.color':
                    this.allAttr(this.mapFill({ color: e.value }));
                    break;
                case 'stroke':
                    if (e.value) {
                        this.allAttr(this.mapStroke(e.value));
                    } else {
                        this.removeAttr('stroke');
                    }
                    break;
                case 'transform':
                    this.transformChange(e.value);
                    break;
                default:
                    var name = ATTRIBUTE_MAP[e.field];
                    if (name) {
                        this.attr(name, e.value);
                    }
                    break;
                }
                Node.fn.optionsChange.call(this, e);
            },
            content: function () {
                if (this.element) {
                    this.element.textContent = this.srcElement.content();
                }
            },
            renderData: function () {
                return this.printPath(this.srcElement);
            },
            printPath: function (path) {
                var this$1 = this;
                var segments = path.segments;
                var length = segments.length;
                if (length > 0) {
                    var parts = [];
                    var output, currentType;
                    for (var i = 1; i < length; i++) {
                        var segmentType = this$1.segmentType(segments[i - 1], segments[i]);
                        if (segmentType !== currentType) {
                            currentType = segmentType;
                            parts.push(segmentType);
                        }
                        if (segmentType === 'L') {
                            parts.push(this$1.printPoints(segments[i].anchor()));
                        } else {
                            parts.push(this$1.printPoints(segments[i - 1].controlOut(), segments[i].controlIn(), segments[i].anchor()));
                        }
                    }
                    output = 'M' + this.printPoints(segments[0].anchor()) + SPACE + parts.join(SPACE);
                    if (path.options.closed) {
                        output += 'Z';
                    }
                    return output;
                }
            },
            printPoints: function () {
                var points = arguments;
                var length = points.length;
                var result = [];
                for (var i = 0; i < length; i++) {
                    result.push(points[i].toString(3));
                }
                return result.join(' ');
            },
            segmentType: function (segmentStart, segmentEnd) {
                return segmentStart.controlOut() && segmentEnd.controlIn() ? 'C' : 'L';
            },
            mapStroke: function (stroke) {
                var attrs = [];
                if (stroke && !isTransparent(stroke.color)) {
                    attrs.push([
                        'stroke',
                        stroke.color
                    ]);
                    attrs.push([
                        'stroke-width',
                        stroke.width
                    ]);
                    attrs.push([
                        'stroke-linecap',
                        this.renderLinecap(stroke)
                    ]);
                    attrs.push([
                        'stroke-linejoin',
                        stroke.lineJoin
                    ]);
                    if (defined(stroke.opacity)) {
                        attrs.push([
                            'stroke-opacity',
                            stroke.opacity
                        ]);
                    }
                    if (defined(stroke.dashType)) {
                        attrs.push([
                            'stroke-dasharray',
                            this.renderDashType(stroke)
                        ]);
                    }
                } else {
                    attrs.push([
                        'stroke',
                        NONE
                    ]);
                }
                return attrs;
            },
            renderStroke: function () {
                return renderAllAttr(this.mapStroke(this.srcElement.options.stroke));
            },
            renderDashType: function (stroke) {
                var dashType = stroke.dashType;
                var width = stroke.width;
                if (width === void 0) {
                    width = 1;
                }
                if (dashType && dashType !== SOLID) {
                    var dashArray = DASH_ARRAYS[dashType.toLowerCase()];
                    var result = [];
                    for (var i = 0; i < dashArray.length; i++) {
                        result.push(dashArray[i] * width);
                    }
                    return result.join(' ');
                }
            },
            renderLinecap: function (stroke) {
                var dashType = stroke.dashType;
                var lineCap = stroke.lineCap;
                return dashType && dashType !== 'solid' ? BUTT : lineCap;
            },
            mapFill: function (fill) {
                var attrs = [];
                if (!(fill && fill.nodeType === 'Gradient')) {
                    if (fill && !isTransparent(fill.color)) {
                        attrs.push([
                            'fill',
                            fill.color
                        ]);
                        if (defined(fill.opacity)) {
                            attrs.push([
                                'fill-opacity',
                                fill.opacity
                            ]);
                        }
                    } else {
                        attrs.push([
                            'fill',
                            NONE
                        ]);
                    }
                }
                return attrs;
            },
            renderFill: function () {
                return renderAllAttr(this.mapFill(this.srcElement.options.fill));
            },
            template: function () {
                return '<path ' + this.renderId() + ' ' + this.renderStyle() + ' ' + this.renderOpacity() + ' ' + renderAttr('d', this.renderData()) + '' + this.renderStroke() + this.renderFill() + this.renderDefinitions() + this.renderTransform() + '></path>';
            }
        });
        NODE_MAP.Path = PathNode;
        var ArcNode = PathNode.extend({
            renderData: function () {
                return this.printPath(this.srcElement.toPath());
            }
        });
        NODE_MAP.Arc = ArcNode;
        var CircleNode = PathNode.extend({
            geometryChange: function () {
                var center = this.center();
                this.attr('cx', center.x);
                this.attr('cy', center.y);
                this.attr('r', this.radius());
                this.invalidate();
            },
            center: function () {
                return this.srcElement.geometry().center;
            },
            radius: function () {
                return this.srcElement.geometry().radius;
            },
            template: function () {
                return '<circle ' + this.renderId() + ' ' + this.renderStyle() + ' ' + this.renderOpacity() + 'cx=\'' + this.center().x + '\' cy=\'' + this.center().y + '\' r=\'' + this.radius() + '\'' + this.renderStroke() + ' ' + this.renderFill() + ' ' + this.renderDefinitions() + this.renderTransform() + ' ></circle>';
            }
        });
        NODE_MAP.Circle = CircleNode;
        var RectNode = PathNode.extend({
            geometryChange: function () {
                var geometry = this.srcElement.geometry();
                this.attr('x', geometry.origin.x);
                this.attr('y', geometry.origin.y);
                this.attr('width', geometry.size.width);
                this.attr('height', geometry.size.height);
                this.invalidate();
            },
            size: function () {
                return this.srcElement.geometry().size;
            },
            origin: function () {
                return this.srcElement.geometry().origin;
            },
            template: function () {
                return '<rect ' + this.renderId() + ' ' + this.renderStyle() + ' ' + this.renderOpacity() + ' x=\'' + this.origin().x + '\' y=\'' + this.origin().y + '\' ' + 'width=\'' + this.size().width + '\' height=\'' + this.size().height + '\' ' + this.renderStroke() + ' ' + this.renderFill() + ' ' + this.renderDefinitions() + ' ' + this.renderTransform() + ' />';
            }
        });
        NODE_MAP.Rect = RectNode;
        var ImageNode = PathNode.extend({
            geometryChange: function () {
                this.allAttr(this.mapPosition());
                this.invalidate();
            },
            optionsChange: function (e) {
                if (e.field === 'src') {
                    this.allAttr(this.mapSource());
                }
                PathNode.fn.optionsChange.call(this, e);
            },
            mapPosition: function () {
                var rect = this.srcElement.rect();
                var tl = rect.topLeft();
                return [
                    [
                        'x',
                        tl.x
                    ],
                    [
                        'y',
                        tl.y
                    ],
                    [
                        'width',
                        rect.width() + 'px'
                    ],
                    [
                        'height',
                        rect.height() + 'px'
                    ]
                ];
            },
            renderPosition: function () {
                return renderAllAttr(this.mapPosition());
            },
            mapSource: function (encode) {
                var src = this.srcElement.src();
                if (encode) {
                    src = kendo.htmlEncode(src);
                }
                return [[
                        'xlink:href',
                        src
                    ]];
            },
            renderSource: function () {
                return renderAllAttr(this.mapSource(true));
            },
            template: function () {
                return '<image preserveAspectRatio=\'none\' ' + this.renderId() + ' ' + this.renderStyle() + ' ' + this.renderTransform() + ' ' + this.renderOpacity() + this.renderPosition() + ' ' + this.renderSource() + ' ' + this.renderDefinitions() + '>' + '</image>';
            }
        });
        NODE_MAP.Image = ImageNode;
        var ENTITY_REGEX = /&(?:[a-zA-Z]+|#\d+);/g;
        function decodeEntities(text) {
            if (!text || typeof text !== 'string' || !ENTITY_REGEX.test(text)) {
                return text;
            }
            var element = decodeEntities._element;
            ENTITY_REGEX.lastIndex = 0;
            return text.replace(ENTITY_REGEX, function (match) {
                element.innerHTML = match;
                return element.textContent || element.innerText;
            });
        }
        if (typeof document !== 'undefined') {
            decodeEntities._element = document.createElement('span');
        }
        var TextNode = PathNode.extend({
            geometryChange: function () {
                var pos = this.pos();
                this.attr('x', pos.x);
                this.attr('y', pos.y);
                this.invalidate();
            },
            optionsChange: function (e) {
                if (e.field === 'font') {
                    this.attr('style', renderStyle(this.mapStyle()));
                    this.geometryChange();
                } else if (e.field === 'content') {
                    PathNode.fn.content.call(this, this.srcElement.content());
                }
                PathNode.fn.optionsChange.call(this, e);
            },
            mapStyle: function (encode) {
                var style = PathNode.fn.mapStyle.call(this, encode);
                var font = this.srcElement.options.font;
                if (encode) {
                    font = kendo.htmlEncode(font);
                }
                style.push([
                    'font',
                    font
                ], [
                    'white-space',
                    'pre'
                ]);
                return style;
            },
            pos: function () {
                var pos = this.srcElement.position();
                var size = this.srcElement.measure();
                return pos.clone().setY(pos.y + size.baseline);
            },
            renderContent: function () {
                var content = this.srcElement.content();
                content = decodeEntities(content);
                content = kendo.htmlEncode(content);
                return kendoUtil.normalizeText(content);
            },
            renderTextAnchor: function () {
                var anchor;
                if ((this.options || {}).rtl && !(supportBrowser.msie || supportBrowser.edge)) {
                    anchor = 'end';
                }
                return renderAttr('text-anchor', anchor);
            },
            template: function () {
                return '<text ' + this.renderId() + ' ' + this.renderTextAnchor() + ' ' + this.renderStyle() + ' ' + this.renderOpacity() + 'x=\'' + this.pos().x + '\' y=\'' + this.pos().y + '\' ' + this.renderStroke() + ' ' + this.renderTransform() + ' ' + this.renderDefinitions() + this.renderFill() + '>' + this.renderContent() + '</text>';
            }
        });
        NODE_MAP.Text = TextNode;
        var MultiPathNode = PathNode.extend({
            renderData: function () {
                var this$1 = this;
                var paths = this.srcElement.paths;
                if (paths.length > 0) {
                    var result = [];
                    for (var i = 0; i < paths.length; i++) {
                        result.push(this$1.printPath(paths[i]));
                    }
                    return result.join(' ');
                }
            }
        });
        NODE_MAP.MultiPath = MultiPathNode;
        var geometry = {
            Circle: Circle$2,
            Arc: Arc$2,
            Rect: Rect,
            Point: Point,
            Segment: Segment,
            Matrix: Matrix,
            Size: Size,
            toMatrix: toMatrix,
            Transformation: Transformation,
            transform: transform
        };
        function exportGroup(group) {
            var root = new RootNode({ skipBaseHref: true });
            var bbox = group.clippedBBox();
            var rootGroup = group;
            if (bbox) {
                var origin = bbox.getOrigin();
                var exportRoot = new Group();
                exportRoot.transform(transform().translate(-origin.x, -origin.y));
                exportRoot.children.push(group);
                rootGroup = exportRoot;
            }
            root.load([rootGroup]);
            var svg = '<?xml version=\'1.0\' ?><svg xmlns=\'' + SVG_NS + '\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' version=\'1.1\'>' + root.render() + '</svg>';
            root.destroy();
            return svg;
        }
        var svg = {
            Surface: Surface$1,
            RootNode: RootNode,
            Node: Node,
            GroupNode: GroupNode,
            ArcNode: ArcNode,
            CircleNode: CircleNode,
            RectNode: RectNode,
            ImageNode: ImageNode,
            TextNode: TextNode,
            PathNode: PathNode,
            MultiPathNode: MultiPathNode,
            DefinitionNode: DefinitionNode,
            ClipNode: ClipNode,
            GradientStopNode: GradientStopNode,
            LinearGradientNode: LinearGradientNode,
            RadialGradientNode: RadialGradientNode,
            exportGroup: exportGroup
        };
        var NODE_MAP$2 = {};
        function renderPath(ctx, path) {
            var segments = path.segments;
            if (segments.length === 0) {
                return;
            }
            var segment = segments[0];
            var anchor = segment.anchor();
            ctx.moveTo(anchor.x, anchor.y);
            for (var i = 1; i < segments.length; i++) {
                segment = segments[i];
                anchor = segment.anchor();
                var prevSeg = segments[i - 1];
                var prevOut = prevSeg.controlOut();
                var controlIn = segment.controlIn();
                if (prevOut && controlIn) {
                    ctx.bezierCurveTo(prevOut.x, prevOut.y, controlIn.x, controlIn.y, anchor.x, anchor.y);
                } else {
                    ctx.lineTo(anchor.x, anchor.y);
                }
            }
            if (path.options.closed) {
                ctx.closePath();
            }
        }
        var Node$2 = BaseNode.extend({
            init: function (srcElement) {
                BaseNode.fn.init.call(this, srcElement);
                if (srcElement) {
                    this.initClip();
                }
            },
            initClip: function () {
                var clip = this.srcElement.clip();
                if (clip) {
                    this.clip = clip;
                    clip.addObserver(this);
                }
            },
            clear: function () {
                if (this.srcElement) {
                    this.srcElement.removeObserver(this);
                }
                this.clearClip();
                BaseNode.fn.clear.call(this);
            },
            clearClip: function () {
                if (this.clip) {
                    this.clip.removeObserver(this);
                    delete this.clip;
                }
            },
            setClip: function (ctx) {
                if (this.clip) {
                    ctx.beginPath();
                    renderPath(ctx, this.clip);
                    ctx.clip();
                }
            },
            optionsChange: function (e) {
                if (e.field === 'clip') {
                    this.clearClip();
                    this.initClip();
                }
                BaseNode.fn.optionsChange.call(this, e);
            },
            setTransform: function (ctx) {
                if (this.srcElement) {
                    var transform = this.srcElement.transform();
                    if (transform) {
                        ctx.transform.apply(ctx, transform.matrix().toArray(6));
                    }
                }
            },
            loadElements: function (elements, pos, cors) {
                var this$1 = this;
                for (var i = 0; i < elements.length; i++) {
                    var srcElement = elements[i];
                    var children = srcElement.children;
                    var childNode = new NODE_MAP$2[srcElement.nodeType](srcElement, cors);
                    if (children && children.length > 0) {
                        childNode.load(children, pos, cors);
                    }
                    if (defined(pos)) {
                        this$1.insertAt(childNode, pos);
                    } else {
                        this$1.append(childNode);
                    }
                }
            },
            load: function (elements, pos, cors) {
                this.loadElements(elements, pos, cors);
                this.invalidate();
            },
            setOpacity: function (ctx) {
                if (this.srcElement) {
                    var opacity = this.srcElement.opacity();
                    if (defined(opacity)) {
                        this.globalAlpha(ctx, opacity);
                    }
                }
            },
            globalAlpha: function (ctx, value) {
                var opactity = value;
                if (opactity && ctx.globalAlpha) {
                    opactity *= ctx.globalAlpha;
                }
                ctx.globalAlpha = opactity;
            },
            visible: function () {
                var src = this.srcElement;
                return !src || src && src.options.visible !== false;
            }
        });
        var GroupNode$2 = Node$2.extend({
            renderTo: function (ctx) {
                if (!this.visible()) {
                    return;
                }
                ctx.save();
                this.setTransform(ctx);
                this.setClip(ctx);
                this.setOpacity(ctx);
                var childNodes = this.childNodes;
                for (var i = 0; i < childNodes.length; i++) {
                    var child = childNodes[i];
                    if (child.visible()) {
                        child.renderTo(ctx);
                    }
                }
                ctx.restore();
            }
        });
        Traversable.extend(GroupNode$2.prototype, 'childNodes');
        NODE_MAP$2.Group = GroupNode$2;
        var FRAME_DELAY = 1000 / 60;
        var RootNode$2 = GroupNode$2.extend({
            init: function (canvas) {
                GroupNode$2.fn.init.call(this);
                this.canvas = canvas;
                this.ctx = canvas.getContext('2d');
                var invalidateHandler = this._invalidate.bind(this);
                this.invalidate = kendo.throttle(function () {
                    kendo.animationFrame(invalidateHandler);
                }, FRAME_DELAY);
            },
            destroy: function () {
                GroupNode$2.fn.destroy.call(this);
                this.canvas = null;
                this.ctx = null;
            },
            load: function (elements, pos, cors) {
                this.loadElements(elements, pos, cors);
                this._invalidate();
            },
            _invalidate: function () {
                if (!this.ctx) {
                    return;
                }
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                this.renderTo(this.ctx);
            }
        });
        Traversable.extend(RootNode$2.prototype, 'childNodes');
        var QuadRoot = Class.extend({
            init: function () {
                this.shapes = [];
            },
            _add: function (shape, bbox) {
                this.shapes.push({
                    bbox: bbox,
                    shape: shape
                });
                shape._quadNode = this;
            },
            pointShapes: function (point) {
                var shapes = this.shapes;
                var length = shapes.length;
                var result = [];
                for (var idx = 0; idx < length; idx++) {
                    if (shapes[idx].bbox.containsPoint(point)) {
                        result.push(shapes[idx].shape);
                    }
                }
                return result;
            },
            insert: function (shape, bbox) {
                this._add(shape, bbox);
            },
            remove: function (shape) {
                var shapes = this.shapes;
                var length = shapes.length;
                for (var idx = 0; idx < length; idx++) {
                    if (shapes[idx].shape === shape) {
                        shapes.splice(idx, 1);
                        break;
                    }
                }
            }
        });
        var QuadNode = QuadRoot.extend({
            init: function (rect) {
                QuadRoot.fn.init.call(this);
                this.children = [];
                this.rect = rect;
            },
            inBounds: function (rect) {
                var nodeRect = this.rect;
                var nodeBottomRight = nodeRect.bottomRight();
                var bottomRight = rect.bottomRight();
                var inBounds = nodeRect.origin.x <= rect.origin.x && nodeRect.origin.y <= rect.origin.y && bottomRight.x <= nodeBottomRight.x && bottomRight.y <= nodeBottomRight.y;
                return inBounds;
            },
            pointShapes: function (point) {
                var children = this.children;
                var length = children.length;
                var result = QuadRoot.fn.pointShapes.call(this, point);
                for (var idx = 0; idx < length; idx++) {
                    append(result, children[idx].pointShapes(point));
                }
                return result;
            },
            insert: function (shape, bbox) {
                var children = this.children;
                var inserted = false;
                if (this.inBounds(bbox)) {
                    if (this.shapes.length < 4) {
                        this._add(shape, bbox);
                    } else {
                        if (!children.length) {
                            this._initChildren();
                        }
                        for (var idx = 0; idx < children.length; idx++) {
                            if (children[idx].insert(shape, bbox)) {
                                inserted = true;
                                break;
                            }
                        }
                        if (!inserted) {
                            this._add(shape, bbox);
                        }
                    }
                    inserted = true;
                }
                return inserted;
            },
            _initChildren: function () {
                var ref = this;
                var rect = ref.rect;
                var children = ref.children;
                var center = rect.center();
                var halfWidth = rect.width() / 2;
                var halfHeight = rect.height() / 2;
                children.push(new QuadNode(new Rect([
                    rect.origin.x,
                    rect.origin.y
                ], [
                    halfWidth,
                    halfHeight
                ])), new QuadNode(new Rect([
                    center.x,
                    rect.origin.y
                ], [
                    halfWidth,
                    halfHeight
                ])), new QuadNode(new Rect([
                    rect.origin.x,
                    center.y
                ], [
                    halfWidth,
                    halfHeight
                ])), new QuadNode(new Rect([
                    center.x,
                    center.y
                ], [
                    halfWidth,
                    halfHeight
                ])));
            }
        });
        var ROOT_SIZE = 3000;
        var LEVEL_STEP = 10000;
        var MAX_LEVEL = 75;
        var ShapesQuadTree = Class.extend({
            init: function () {
                this.initRoots();
            },
            initRoots: function () {
                this.rootMap = {};
                this.root = new QuadRoot();
                this.rootElements = [];
            },
            clear: function () {
                var this$1 = this;
                var rootElements = this.rootElements;
                for (var idx = 0; idx < rootElements.length; idx++) {
                    this$1.remove(rootElements[idx]);
                }
                this.initRoots();
            },
            pointShape: function (point) {
                var sectorRoot = (this.rootMap[Math.floor(point.x / ROOT_SIZE)] || {})[Math.floor(point.y / ROOT_SIZE)];
                var result = this.root.pointShapes(point);
                if (sectorRoot) {
                    result = result.concat(sectorRoot.pointShapes(point));
                }
                this.assignZindex(result);
                result.sort(zIndexComparer);
                for (var idx = 0; idx < result.length; idx++) {
                    if (result[idx].containsPoint(point)) {
                        return result[idx];
                    }
                }
            },
            assignZindex: function (elements) {
                var this$1 = this;
                for (var idx = 0; idx < elements.length; idx++) {
                    var element = elements[idx];
                    var zIndex = 0;
                    var levelWeight = Math.pow(LEVEL_STEP, MAX_LEVEL);
                    var parents = [];
                    while (element) {
                        parents.push(element);
                        element = element.parent;
                    }
                    while (parents.length) {
                        element = parents.pop();
                        zIndex += ((element.parent ? element.parent.children : this$1.rootElements).indexOf(element) + 1) * levelWeight;
                        levelWeight /= LEVEL_STEP;
                    }
                    elements[idx]._zIndex = zIndex;
                }
            },
            optionsChange: function (e) {
                if (e.field === 'transform' || e.field === 'stroke.width') {
                    this.bboxChange(e.element);
                }
            },
            geometryChange: function (e) {
                this.bboxChange(e.element);
            },
            bboxChange: function (element) {
                var this$1 = this;
                if (element.nodeType === 'Group') {
                    for (var idx = 0; idx < element.children.length; idx++) {
                        this$1.bboxChange(element.children[idx]);
                    }
                } else {
                    if (element._quadNode) {
                        element._quadNode.remove(element);
                    }
                    this._insertShape(element);
                }
            },
            add: function (elements) {
                var elementsArray = Array.isArray(elements) ? elements.slice(0) : [elements];
                append(this.rootElements, elementsArray);
                this._insert(elementsArray);
            },
            childrenChange: function (e) {
                var this$1 = this;
                if (e.action === 'remove') {
                    for (var idx = 0; idx < e.items.length; idx++) {
                        this$1.remove(e.items[idx]);
                    }
                } else {
                    this._insert(Array.prototype.slice.call(e.items, 0));
                }
            },
            _insert: function (elements) {
                var this$1 = this;
                var element;
                while (elements.length > 0) {
                    element = elements.pop();
                    element.addObserver(this$1);
                    if (element.nodeType === 'Group') {
                        append(elements, element.children);
                    } else {
                        this$1._insertShape(element);
                    }
                }
            },
            _insertShape: function (shape) {
                var bbox = shape.bbox();
                if (bbox) {
                    var sectors = this.getSectors(bbox);
                    var x = sectors[0][0];
                    var y = sectors[1][0];
                    if (this.inRoot(sectors)) {
                        this.root.insert(shape, bbox);
                    } else {
                        var rootMap = this.rootMap;
                        if (!rootMap[x]) {
                            rootMap[x] = {};
                        }
                        if (!rootMap[x][y]) {
                            rootMap[x][y] = new QuadNode(new Rect([
                                x * ROOT_SIZE,
                                y * ROOT_SIZE
                            ], [
                                ROOT_SIZE,
                                ROOT_SIZE
                            ]));
                        }
                        rootMap[x][y].insert(shape, bbox);
                    }
                }
            },
            remove: function (element) {
                var this$1 = this;
                element.removeObserver(this);
                if (element.nodeType === 'Group') {
                    var children = element.children;
                    for (var idx = 0; idx < children.length; idx++) {
                        this$1.remove(children[idx]);
                    }
                } else if (element._quadNode) {
                    element._quadNode.remove(element);
                    delete element._quadNode;
                }
            },
            inRoot: function (sectors) {
                return sectors[0].length > 1 || sectors[1].length > 1;
            },
            getSectors: function (rect) {
                var bottomRight = rect.bottomRight();
                var bottomX = Math.floor(bottomRight.x / ROOT_SIZE);
                var bottomY = Math.floor(bottomRight.y / ROOT_SIZE);
                var sectors = [
                    [],
                    []
                ];
                for (var x = Math.floor(rect.origin.x / ROOT_SIZE); x <= bottomX; x++) {
                    sectors[0].push(x);
                }
                for (var y = Math.floor(rect.origin.y / ROOT_SIZE); y <= bottomY; y++) {
                    sectors[1].push(y);
                }
                return sectors;
            }
        });
        function zIndexComparer(x1, x2) {
            if (x1._zIndex < x2._zIndex) {
                return 1;
            }
            if (x1._zIndex > x2._zIndex) {
                return -1;
            }
            return 0;
        }
        var SurfaceCursor = Class.extend({
            init: function (surface) {
                surface.bind('mouseenter', this._mouseenter.bind(this));
                surface.bind('mouseleave', this._mouseleave.bind(this));
                this.element = surface.element;
            },
            clear: function () {
                this._resetCursor();
            },
            destroy: function () {
                this._resetCursor();
                delete this.element;
            },
            _mouseenter: function (e) {
                var cursor = this._shapeCursor(e);
                if (!cursor) {
                    this._resetCursor();
                } else {
                    if (!this._current) {
                        this._defaultCursor = this._getCursor();
                    }
                    this._setCursor(cursor);
                }
            },
            _mouseleave: function () {
                this._resetCursor();
            },
            _shapeCursor: function (e) {
                var shape = e.element;
                while (shape && !defined(shape.options.cursor)) {
                    shape = shape.parent;
                }
                if (shape) {
                    return shape.options.cursor;
                }
            },
            _getCursor: function () {
                if (this.element) {
                    return this.element.style.cursor;
                }
            },
            _setCursor: function (cursor) {
                if (this.element) {
                    this.element.style.cursor = cursor;
                    this._current = cursor;
                }
            },
            _resetCursor: function () {
                if (this._current) {
                    this._setCursor(this._defaultCursor || '');
                    delete this._current;
                }
            }
        });
        var Surface$3 = Surface.extend({
            init: function (element, options) {
                Surface.fn.init.call(this, element, options);
                this.element.innerHTML = this._template(this);
                var canvas = this.element.firstElementChild;
                var size = elementSize(element);
                canvas.width = size.width;
                canvas.height = size.height;
                this._rootElement = canvas;
                this._root = new RootNode$2(canvas);
                this._mouseTrackHandler = this._trackMouse.bind(this);
                bindEvents(this.element, {
                    click: this._mouseTrackHandler,
                    mousemove: this._mouseTrackHandler
                });
            },
            destroy: function () {
                Surface.fn.destroy.call(this);
                if (this._root) {
                    this._root.destroy();
                    this._root = null;
                }
                if (this._searchTree) {
                    this._searchTree.clear();
                    delete this._searchTree;
                }
                if (this._cursor) {
                    this._cursor.destroy();
                    delete this._cursor;
                }
                unbindEvents(this.element, {
                    click: this._mouseTrackHandler,
                    mousemove: this._mouseTrackHandler
                });
            },
            draw: function (element) {
                Surface.fn.draw.call(this, element);
                this._root.load([element], undefined, this.options.cors);
                if (this._searchTree) {
                    this._searchTree.add([element]);
                }
            },
            clear: function () {
                Surface.fn.clear.call(this);
                this._root.clear();
                if (this._searchTree) {
                    this._searchTree.clear();
                }
                if (this._cursor) {
                    this._cursor.clear();
                }
            },
            eventTarget: function (e) {
                if (this._searchTree) {
                    var point = this._surfacePoint(e);
                    var shape = this._searchTree.pointShape(point);
                    return shape;
                }
            },
            image: function () {
                var ref = this;
                var root = ref._root;
                var rootElement = ref._rootElement;
                var loadingStates = [];
                root.traverse(function (childNode) {
                    if (childNode.loading) {
                        loadingStates.push(childNode.loading);
                    }
                });
                var promise = createPromise();
                var resolveDataURL = function () {
                    root._invalidate();
                    try {
                        var data = rootElement.toDataURL();
                        promise.resolve(data);
                    } catch (e) {
                        promise.reject(e);
                    }
                };
                promiseAll(loadingStates).then(resolveDataURL, resolveDataURL);
                return promise;
            },
            suspendTracking: function () {
                Surface.fn.suspendTracking.call(this);
                if (this._searchTree) {
                    this._searchTree.clear();
                    delete this._searchTree;
                }
            },
            resumeTracking: function () {
                Surface.fn.resumeTracking.call(this);
                if (!this._searchTree) {
                    this._searchTree = new ShapesQuadTree();
                    var childNodes = this._root.childNodes;
                    var rootElements = [];
                    for (var idx = 0; idx < childNodes.length; idx++) {
                        rootElements.push(childNodes[idx].srcElement);
                    }
                    this._searchTree.add(rootElements);
                }
            },
            _resize: function () {
                this._rootElement.width = this._size.width;
                this._rootElement.height = this._size.height;
                this._root.invalidate();
            },
            _template: function () {
                return '<canvas style=\'width: 100%; height: 100%;\'></canvas>';
            },
            _enableTracking: function () {
                this._searchTree = new ShapesQuadTree();
                this._cursor = new SurfaceCursor(this);
                Surface.fn._enableTracking.call(this);
            },
            _trackMouse: function (e) {
                if (this._suspendedTracking) {
                    return;
                }
                var shape = this.eventTarget(e);
                if (e.type !== 'click') {
                    var currentShape = this._currentShape;
                    if (currentShape && currentShape !== shape) {
                        this.trigger('mouseleave', {
                            element: currentShape,
                            originalEvent: e,
                            type: 'mouseleave'
                        });
                    }
                    if (shape && currentShape !== shape) {
                        this.trigger('mouseenter', {
                            element: shape,
                            originalEvent: e,
                            type: 'mouseenter'
                        });
                    }
                    this.trigger('mousemove', {
                        element: shape,
                        originalEvent: e,
                        type: 'mousemove'
                    });
                    this._currentShape = shape;
                } else if (shape) {
                    this.trigger('click', {
                        element: shape,
                        originalEvent: e,
                        type: 'click'
                    });
                }
            }
        });
        Surface$3.prototype.type = 'canvas';
        if (typeof document !== 'undefined' && document.createElement('canvas').getContext) {
            Surface.support.canvas = true;
            SurfaceFactory.current.register('canvas', Surface$3, 20);
        }
        function addGradientStops(gradient, stops) {
            for (var idx = 0; idx < stops.length; idx++) {
                var stop = stops[idx];
                var color = kendo.parseColor(stop.color());
                color.a *= stop.opacity();
                gradient.addColorStop(stop.offset(), color.toCssRgba());
            }
        }
        var PathNode$2 = Node$2.extend({
            renderTo: function (ctx) {
                ctx.save();
                this.setTransform(ctx);
                this.setClip(ctx);
                this.setOpacity(ctx);
                ctx.beginPath();
                this.renderPoints(ctx, this.srcElement);
                this.setLineDash(ctx);
                this.setLineCap(ctx);
                this.setLineJoin(ctx);
                this.setFill(ctx);
                this.setStroke(ctx);
                ctx.restore();
            },
            setFill: function (ctx) {
                var fill = this.srcElement.options.fill;
                var hasFill = false;
                if (fill) {
                    if (fill.nodeType === 'Gradient') {
                        this.setGradientFill(ctx, fill);
                        hasFill = true;
                    } else if (!isTransparent(fill.color)) {
                        ctx.fillStyle = fill.color;
                        ctx.save();
                        this.globalAlpha(ctx, fill.opacity);
                        ctx.fill();
                        ctx.restore();
                        hasFill = true;
                    }
                }
                return hasFill;
            },
            setGradientFill: function (ctx, fill) {
                var bbox = this.srcElement.rawBBox();
                var gradient;
                if (fill instanceof LinearGradient) {
                    var start = fill.start();
                    var end = fill.end();
                    gradient = ctx.createLinearGradient(start.x, start.y, end.x, end.y);
                } else if (fill instanceof RadialGradient) {
                    var center = fill.center();
                    gradient = ctx.createRadialGradient(center.x, center.y, 0, center.x, center.y, fill.radius());
                }
                addGradientStops(gradient, fill.stops);
                ctx.save();
                if (!fill.userSpace()) {
                    ctx.transform(bbox.width(), 0, 0, bbox.height(), bbox.origin.x, bbox.origin.y);
                }
                ctx.fillStyle = gradient;
                ctx.fill();
                ctx.restore();
            },
            setStroke: function (ctx) {
                var stroke = this.srcElement.options.stroke;
                if (stroke && !isTransparent(stroke.color) && stroke.width > 0) {
                    ctx.strokeStyle = stroke.color;
                    ctx.lineWidth = valueOrDefault(stroke.width, 1);
                    ctx.save();
                    this.globalAlpha(ctx, stroke.opacity);
                    ctx.stroke();
                    ctx.restore();
                    return true;
                }
            },
            dashType: function () {
                var stroke = this.srcElement.options.stroke;
                if (stroke && stroke.dashType) {
                    return stroke.dashType.toLowerCase();
                }
            },
            setLineDash: function (ctx) {
                var dashType = this.dashType();
                if (dashType && dashType !== SOLID) {
                    var dashArray = DASH_ARRAYS[dashType];
                    if (ctx.setLineDash) {
                        ctx.setLineDash(dashArray);
                    } else {
                        ctx.mozDash = dashArray;
                        ctx.webkitLineDash = dashArray;
                    }
                }
            },
            setLineCap: function (ctx) {
                var dashType = this.dashType();
                var stroke = this.srcElement.options.stroke;
                if (dashType && dashType !== SOLID) {
                    ctx.lineCap = BUTT;
                } else if (stroke && stroke.lineCap) {
                    ctx.lineCap = stroke.lineCap;
                }
            },
            setLineJoin: function (ctx) {
                var stroke = this.srcElement.options.stroke;
                if (stroke && stroke.lineJoin) {
                    ctx.lineJoin = stroke.lineJoin;
                }
            },
            renderPoints: function (ctx, path) {
                renderPath(ctx, path);
            }
        });
        NODE_MAP$2.Path = PathNode$2;
        var ArcNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var path = this.srcElement.toPath();
                renderPath(ctx, path);
            }
        });
        NODE_MAP$2.Arc = ArcNode$2;
        var CircleNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var ref = this.srcElement.geometry();
                var center = ref.center;
                var radius = ref.radius;
                ctx.arc(center.x, center.y, radius, 0, Math.PI * 2);
            }
        });
        NODE_MAP$2.Circle = CircleNode$2;
        var RectNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var ref = this.srcElement.geometry();
                var origin = ref.origin;
                var size = ref.size;
                ctx.rect(origin.x, origin.y, size.width, size.height);
            }
        });
        NODE_MAP$2.Rect = RectNode$2;
        var ImageNode$2 = PathNode$2.extend({
            init: function (srcElement, cors) {
                PathNode$2.fn.init.call(this, srcElement);
                this.onLoad = this.onLoad.bind(this);
                this.onError = this.onError.bind(this);
                this.loading = createPromise();
                var img = this.img = new Image();
                if (cors && !/^data:/i.test(srcElement.src())) {
                    img.crossOrigin = cors;
                }
                img.src = srcElement.src();
                if (img.complete) {
                    this.onLoad();
                } else {
                    img.onload = this.onLoad;
                    img.onerror = this.onError;
                }
            },
            renderTo: function (ctx) {
                if (this.loading.state() === 'resolved') {
                    ctx.save();
                    this.setTransform(ctx);
                    this.setClip(ctx);
                    this.drawImage(ctx);
                    ctx.restore();
                }
            },
            optionsChange: function (e) {
                if (e.field === 'src') {
                    this.loading = createPromise();
                    this.img.src = this.srcElement.src();
                } else {
                    PathNode$2.fn.optionsChange.call(this, e);
                }
            },
            onLoad: function () {
                this.loading.resolve();
                this.invalidate();
            },
            onError: function () {
                this.loading.reject(new Error('Unable to load image \'' + this.img.src + '\'. Check for connectivity and verify CORS headers.'));
            },
            drawImage: function (ctx) {
                var rect = this.srcElement.rect();
                var topLeft = rect.topLeft();
                ctx.drawImage(this.img, topLeft.x, topLeft.y, rect.width(), rect.height());
            }
        });
        NODE_MAP$2.Image = ImageNode$2;
        var TextNode$2 = PathNode$2.extend({
            renderTo: function (ctx) {
                var text = this.srcElement;
                var pos = text.position();
                var size = text.measure();
                ctx.save();
                this.setTransform(ctx);
                this.setClip(ctx);
                this.setOpacity(ctx);
                ctx.beginPath();
                ctx.font = text.options.font;
                ctx.textAlign = 'left';
                if (this.setFill(ctx)) {
                    ctx.fillText(text.content(), pos.x, pos.y + size.baseline);
                }
                if (this.setStroke(ctx)) {
                    this.setLineDash(ctx);
                    ctx.strokeText(text.content(), pos.x, pos.y + size.baseline);
                }
                ctx.restore();
            }
        });
        NODE_MAP$2.Text = TextNode$2;
        var MultiPathNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var paths = this.srcElement.paths;
                for (var i = 0; i < paths.length; i++) {
                    renderPath(ctx, paths[i]);
                }
            }
        });
        NODE_MAP$2.MultiPath = MultiPathNode$2;
        var canvas = {
            Surface: Surface$3,
            RootNode: RootNode$2,
            Node: Node$2,
            GroupNode: GroupNode$2,
            ArcNode: ArcNode$2,
            CircleNode: CircleNode$2,
            RectNode: RectNode$2,
            ImageNode: ImageNode$2,
            TextNode: TextNode$2,
            PathNode: PathNode$2,
            MultiPathNode: MultiPathNode$2
        };
        function exportImage(group, options) {
            var defaults = {
                width: '800px',
                height: '600px',
                cors: 'Anonymous'
            };
            var exportRoot = group;
            var bbox = group.clippedBBox();
            if (bbox) {
                var origin = bbox.getOrigin();
                exportRoot = new Group();
                exportRoot.transform(transform().translate(-origin.x, -origin.y));
                exportRoot.children.push(group);
                var size = bbox.getSize();
                defaults.width = size.width + 'px';
                defaults.height = size.height + 'px';
            }
            var surfaceOptions = $.extend(defaults, options);
            var container = document.createElement('div');
            var style = container.style;
            style.display = 'none';
            style.width = surfaceOptions.width;
            style.height = surfaceOptions.height;
            document.body.appendChild(container);
            var surface = new Surface$3(container, surfaceOptions);
            surface.suspendTracking();
            surface.draw(exportRoot);
            var promise = surface.image();
            var destroy = function () {
                surface.destroy();
                document.body.removeChild(container);
            };
            promise.then(destroy, destroy);
            return promise;
        }
        function exportSVG(group, options) {
            var svg = exportGroup(group);
            if (!options || !options.raw) {
                svg = 'data:image/svg+xml;base64,' + encodeBase64(svg);
            }
            return createPromise().resolve(svg);
        }
        var browser = supportBrowser;
        function slice$1(thing) {
            return Array.prototype.slice.call(thing);
        }
        var KENDO_PSEUDO_ELEMENT = 'KENDO-PSEUDO-ELEMENT';
        var IMAGE_CACHE = {};
        var nodeInfo = {};
        nodeInfo._root = nodeInfo;
        var inBrowser = typeof window !== 'undefined';
        var microsoft = inBrowser ? browser.msie || browser.edge : false;
        var TextRect = Text.extend({
            init: function (str, rect, options) {
                Text.fn.init.call(this, str, rect.getOrigin(), options);
                this._pdfRect = rect;
            },
            rect: function () {
                return this._pdfRect;
            },
            rawBBox: function () {
                return this._pdfRect;
            }
        });
        function addClass(el, cls) {
            if (el.classList) {
                el.classList.add(cls);
            } else {
                el.className += ' ' + cls;
            }
        }
        function removeClass(el, cls) {
            if (el.classList) {
                el.classList.remove(cls);
            } else {
                el.className = el.className.split(/\s+/).reduce(function (a, word) {
                    if (word != cls) {
                        a.push(word);
                    }
                    return a;
                }, []).join(' ');
            }
        }
        function setCSS(el, styles) {
            Object.keys(styles).forEach(function (key) {
                el.style[key] = styles[key];
            });
        }
        var matches = typeof Element !== 'undefined' && Element.prototype && function (p) {
            if (p.matches) {
                return function (el, selector) {
                    return el.matches(selector);
                };
            }
            if (p.webkitMatchesSelector) {
                return function (el, selector) {
                    return el.webkitMatchesSelector(selector);
                };
            }
            if (p.mozMatchesSelector) {
                return function (el, selector) {
                    return el.mozMatchesSelector(selector);
                };
            }
            if (p.msMatchesSelector) {
                return function (el, selector) {
                    return el.msMatchesSelector(selector);
                };
            }
            return function (s) {
                return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
            };
        }(Element.prototype);
        function closest(el, selector) {
            if (el.closest) {
                return el.closest(selector);
            }
            while (el && !/^\[object (?:HTML)?Document\]$/.test(String(el))) {
                if (el.nodeType == 1 && matches(el, selector)) {
                    return el;
                }
                el = el.parentNode;
            }
        }
        var cloneNodes = function ($) {
            if ($) {
                return function cloneNodes(el) {
                    var clone = el.cloneNode(false);
                    if (el.nodeType == 1) {
                        var $el = $(el), $clone = $(clone), i;
                        var data = $el.data();
                        for (i in data) {
                            $clone.data(i, data[i]);
                        }
                        if (/^canvas$/i.test(el.tagName)) {
                            clone.getContext('2d').drawImage(el, 0, 0);
                        } else if (/^(?:input|select|textarea|option)$/i.test(el.tagName)) {
                            clone.removeAttribute('id');
                            clone.removeAttribute('name');
                            clone.value = el.value;
                            clone.checked = el.checked;
                            clone.selected = el.selected;
                        }
                        for (i = el.firstChild; i; i = i.nextSibling) {
                            clone.appendChild(cloneNodes(i));
                        }
                    }
                    return clone;
                };
            } else {
                return function cloneNodes(el) {
                    var clone = function dive(node) {
                        var clone = node.cloneNode(false);
                        if (node._kendoExportVisual) {
                            clone._kendoExportVisual = node._kendoExportVisual;
                        }
                        for (var i = node.firstChild; i; i = i.nextSibling) {
                            clone.appendChild(dive(i));
                        }
                        return clone;
                    }(el);
                    var canvases = el.querySelectorAll('canvas');
                    if (canvases.length) {
                        slice$1(clone.querySelectorAll('canvas')).forEach(function (canvas$$1, i) {
                            canvas$$1.getContext('2d').drawImage(canvases[i], 0, 0);
                        });
                    }
                    var orig = el.querySelectorAll('input, select, textarea, option');
                    slice$1(clone.querySelectorAll('input, select, textarea, option')).forEach(function (el, i) {
                        el.removeAttribute('id');
                        el.removeAttribute('name');
                        el.value = orig[i].value;
                        el.checked = orig[i].checked;
                        el.selected = orig[i].selected;
                    });
                    return clone;
                };
            }
        }(typeof window !== 'undefined' && window.kendo && window.kendo.jQuery);
        function getXY(thing) {
            if (typeof thing == 'number') {
                return {
                    x: thing,
                    y: thing
                };
            }
            if (Array.isArray(thing)) {
                return {
                    x: thing[0],
                    y: thing[1]
                };
            }
            return {
                x: thing.x,
                y: thing.y
            };
        }
        function drawDOM(element, options) {
            if (!options) {
                options = {};
            }
            var promise = createPromise();
            if (!element) {
                return promise.reject('No element to export');
            }
            if (typeof window.getComputedStyle != 'function') {
                throw new Error('window.getComputedStyle is missing.  You are using an unsupported browser, or running in IE8 compatibility mode.  Drawing HTML is supported in Chrome, Firefox, Safari and IE9+.');
            }
            kendo.pdf.defineFont(getFontFaces(element.ownerDocument));
            var scale = getXY(options.scale || 1);
            function doOne(element) {
                var group = new Group();
                var pos = element.getBoundingClientRect();
                setTransform(group, [
                    scale.x,
                    0,
                    0,
                    scale.y,
                    -pos.left * scale.x,
                    -pos.top * scale.y
                ]);
                nodeInfo._clipbox = false;
                nodeInfo._matrix = Matrix.unit();
                nodeInfo._stackingContext = {
                    element: element,
                    group: group
                };
                if (options.avoidLinks === true) {
                    nodeInfo._avoidLinks = 'a';
                } else {
                    nodeInfo._avoidLinks = options.avoidLinks;
                }
                addClass(element, 'k-pdf-export');
                renderElement(element, group);
                removeClass(element, 'k-pdf-export');
                return group;
            }
            cacheImages(element, function () {
                var forceBreak = options && options.forcePageBreak;
                var hasPaperSize = options && options.paperSize && options.paperSize != 'auto';
                var paperOptions = kendo.pdf.getPaperOptions(function (key, def) {
                    if (key == 'paperSize') {
                        return hasPaperSize ? options[key] : 'A4';
                    }
                    return key in options ? options[key] : def;
                });
                var pageWidth = hasPaperSize && paperOptions.paperSize[0];
                var pageHeight = hasPaperSize && paperOptions.paperSize[1];
                var margin = options.margin && paperOptions.margin;
                var hasMargin = Boolean(margin);
                if (forceBreak || pageHeight) {
                    if (!margin) {
                        margin = {
                            left: 0,
                            top: 0,
                            right: 0,
                            bottom: 0
                        };
                    }
                    if (pageWidth) {
                        pageWidth /= scale.x;
                    }
                    if (pageHeight) {
                        pageHeight /= scale.y;
                    }
                    margin.left /= scale.x;
                    margin.right /= scale.x;
                    margin.top /= scale.y;
                    margin.bottom /= scale.y;
                    var group = new Group({
                        pdf: {
                            multiPage: true,
                            paperSize: hasPaperSize ? paperOptions.paperSize : 'auto',
                            _ignoreMargin: hasMargin
                        }
                    });
                    handlePageBreaks(function (x) {
                        if (options.progress) {
                            var canceled = false, pageNum = 0;
                            (function next() {
                                if (pageNum < x.pages.length) {
                                    var page = doOne(x.pages[pageNum]);
                                    group.append(page);
                                    options.progress({
                                        page: page,
                                        pageNum: ++pageNum,
                                        totalPages: x.pages.length,
                                        cancel: function () {
                                            canceled = true;
                                        }
                                    });
                                    if (!canceled) {
                                        setTimeout(next);
                                    } else {
                                        x.container.parentNode.removeChild(x.container);
                                    }
                                } else {
                                    x.container.parentNode.removeChild(x.container);
                                    promise.resolve(group);
                                }
                            }());
                        } else {
                            x.pages.forEach(function (page) {
                                group.append(doOne(page));
                            });
                            x.container.parentNode.removeChild(x.container);
                            promise.resolve(group);
                        }
                    }, element, forceBreak, pageWidth ? pageWidth - margin.left - margin.right : null, pageHeight ? pageHeight - margin.top - margin.bottom : null, margin, options);
                } else {
                    promise.resolve(doOne(element));
                }
            });
            function makeTemplate(template$$1) {
                if (template$$1 != null) {
                    if (typeof template$$1 == 'string') {
                        template$$1 = kendo.template(template$$1.replace(/^\s+|\s+$/g, ''));
                    }
                    if (typeof template$$1 == 'function') {
                        return function (data) {
                            var el = template$$1(data);
                            if (el && typeof el == 'string') {
                                var div = document.createElement('div');
                                div.innerHTML = el;
                                el = div.firstElementChild;
                            }
                            return el;
                        };
                    }
                    return function () {
                        return template$$1.cloneNode(true);
                    };
                }
            }
            function handlePageBreaks(callback, element, forceBreak, pageWidth, pageHeight, margin, options) {
                var template$$1 = makeTemplate(options.template);
                var doc = element.ownerDocument;
                var pages = [];
                var copy = options._destructive ? element : cloneNodes(element);
                var container = doc.createElement('KENDO-PDF-DOCUMENT');
                var adjust = 0;
                slice$1(copy.querySelectorAll('tfoot')).forEach(function (tfoot) {
                    tfoot.parentNode.appendChild(tfoot);
                });
                slice$1(copy.querySelectorAll('ol')).forEach(function (ol) {
                    slice$1(ol.children).forEach(function (li, index) {
                        li.setAttribute('kendo-split-index', index);
                    });
                });
                setCSS(container, {
                    display: 'block',
                    position: 'absolute',
                    boxSizing: 'content-box',
                    left: '-10000px',
                    top: '-10000px'
                });
                if (pageWidth) {
                    setCSS(container, {
                        width: pageWidth + 'px',
                        paddingLeft: margin.left + 'px',
                        paddingRight: margin.right + 'px'
                    });
                    setCSS(copy, { overflow: 'hidden' });
                }
                element.parentNode.insertBefore(container, element);
                container.appendChild(copy);
                if (options.beforePageBreak) {
                    setTimeout(function () {
                        options.beforePageBreak(container, doPageBreak);
                    }, 15);
                } else {
                    setTimeout(doPageBreak, 15);
                }
                function doPageBreak() {
                    if (forceBreak != '-' || pageHeight) {
                        splitElement(copy);
                    }
                    {
                        var page = makePage();
                        copy.parentNode.insertBefore(page, copy);
                        page.appendChild(copy);
                    }
                    if (template$$1) {
                        pages.forEach(function (page, i) {
                            var el = template$$1({
                                element: page,
                                pageNum: i + 1,
                                totalPages: pages.length
                            });
                            if (el) {
                                page.appendChild(el);
                            }
                        });
                    }
                    cacheImages(pages, function () {
                        whenImagesAreActuallyLoaded(pages, function () {
                            callback({
                                pages: pages,
                                container: container
                            });
                        });
                    });
                }
                function keepTogether(el) {
                    if (options.keepTogether && matches(el, options.keepTogether) && el.offsetHeight <= pageHeight - adjust) {
                        return true;
                    }
                    var tag = el.tagName;
                    if (/^h[1-6]$/i.test(tag) && el.offsetHeight >= pageHeight - adjust) {
                        return false;
                    }
                    return el.getAttribute('data-kendo-chart') || /^(?:img|tr|thead|th|tfoot|iframe|svg|object|canvas|input|textarea|select|video|h[1-6])/i.test(el.tagName);
                }
                function splitElement(element) {
                    if (element.tagName == 'TABLE') {
                        setCSS(element, { tableLayout: 'fixed' });
                    }
                    if (keepTogether(element)) {
                        return;
                    }
                    var style = getComputedStyle(element);
                    var bottomPadding = parseFloat(getPropertyValue(style, 'padding-bottom'));
                    var bottomBorder = parseFloat(getPropertyValue(style, 'border-bottom-width'));
                    var saveAdjust = adjust;
                    adjust += bottomPadding + bottomBorder;
                    var isFirst = true;
                    for (var el = element.firstChild; el; el = el.nextSibling) {
                        if (el.nodeType == 1) {
                            isFirst = false;
                            if (matches(el, forceBreak)) {
                                breakAtElement(el);
                                continue;
                            }
                            if (!pageHeight) {
                                splitElement(el);
                                continue;
                            }
                            if (!/^(?:static|relative)$/.test(getPropertyValue(getComputedStyle(el), 'position'))) {
                                continue;
                            }
                            var fall = fallsOnMargin(el);
                            if (fall == 1) {
                                breakAtElement(el);
                            } else if (fall) {
                                if (keepTogether(el)) {
                                    breakAtElement(el);
                                } else {
                                    splitElement(el);
                                }
                            } else {
                                splitElement(el);
                            }
                        } else if (el.nodeType == 3 && pageHeight) {
                            splitText(el, isFirst);
                            isFirst = false;
                        }
                    }
                    adjust = saveAdjust;
                }
                function firstInParent(el) {
                    var p = el.parentNode, first = p.firstChild;
                    if (el === first) {
                        return true;
                    }
                    if (el === p.children[0]) {
                        if (first.nodeType == 7 || first.nodeType == 8) {
                            return true;
                        }
                        if (first.nodeType == 3) {
                            return !/\S/.test(first.data);
                        }
                    }
                    return false;
                }
                function breakAtElement(el) {
                    if (el.nodeType == 1 && el !== copy && firstInParent(el)) {
                        return breakAtElement(el.parentNode);
                    }
                    var table, colgroup, thead, grid, gridHead;
                    table = closest(el, 'table');
                    colgroup = table && table.querySelector('colgroup');
                    if (options.repeatHeaders) {
                        thead = table && table.querySelector('thead');
                        grid = closest(el, '.k-grid.k-widget');
                        if (grid && grid.querySelector('.k-auto-scrollable')) {
                            gridHead = grid.querySelector('.k-grid-header');
                        }
                    }
                    var page = makePage();
                    var range = doc.createRange();
                    range.setStartBefore(copy);
                    range.setEndBefore(el);
                    page.appendChild(range.extractContents());
                    copy.parentNode.insertBefore(page, copy);
                    preventBulletOnListItem(el.parentNode);
                    if (table) {
                        table = closest(el, 'table');
                        if (options.repeatHeaders && thead) {
                            table.insertBefore(thead.cloneNode(true), table.firstChild);
                        }
                        if (colgroup) {
                            table.insertBefore(colgroup.cloneNode(true), table.firstChild);
                        }
                    }
                    if (options.repeatHeaders && gridHead) {
                        grid = closest(el, '.k-grid.k-widget');
                        grid.insertBefore(gridHead.cloneNode(true), grid.firstChild);
                    }
                }
                function makePage() {
                    var page = doc.createElement('KENDO-PDF-PAGE');
                    setCSS(page, {
                        display: 'block',
                        boxSizing: 'content-box',
                        width: pageWidth ? pageWidth + 'px' : 'auto',
                        padding: margin.top + 'px ' + margin.right + 'px ' + margin.bottom + 'px ' + margin.left + 'px',
                        position: 'relative',
                        height: pageHeight ? pageHeight + 'px' : 'auto',
                        overflow: pageHeight || pageWidth ? 'hidden' : 'visible',
                        clear: 'both'
                    });
                    if (options && options.pageClassName) {
                        page.className = options.pageClassName;
                    }
                    pages.push(page);
                    return page;
                }
                function fallsOnMargin(thing) {
                    var box = thing.getBoundingClientRect();
                    if (box.width === 0 || box.height === 0) {
                        return 0;
                    }
                    var top = copy.getBoundingClientRect().top;
                    var available = pageHeight - adjust;
                    return box.height > available ? 3 : box.top - top > available ? 1 : box.bottom - top > available ? 2 : 0;
                }
                function splitText(node, isFirst) {
                    if (!/\S/.test(node.data)) {
                        return;
                    }
                    var len = node.data.length;
                    var range = doc.createRange();
                    range.selectNodeContents(node);
                    var fall = fallsOnMargin(range);
                    if (!fall) {
                        return;
                    }
                    var nextnode = node;
                    if (fall == 1) {
                        if (isFirst) {
                            breakAtElement(node.parentNode);
                        } else {
                            breakAtElement(node);
                        }
                    } else {
                        (function findEOP(min, pos, max) {
                            range.setEnd(node, pos);
                            if (min == pos || pos == max) {
                                return pos;
                            }
                            if (fallsOnMargin(range)) {
                                return findEOP(min, min + pos >> 1, pos);
                            } else {
                                return findEOP(pos, pos + max >> 1, max);
                            }
                        }(0, len >> 1, len));
                        if (!/\S/.test(range.toString()) && isFirst) {
                            breakAtElement(node.parentNode);
                        } else {
                            nextnode = node.splitText(range.endOffset);
                            var page = makePage();
                            range.setStartBefore(copy);
                            page.appendChild(range.extractContents());
                            copy.parentNode.insertBefore(page, copy);
                            preventBulletOnListItem(nextnode.parentNode);
                        }
                    }
                    splitText(nextnode);
                }
                function preventBulletOnListItem(el) {
                    var li = closest(el, 'li');
                    if (li) {
                        li.setAttribute('kendo-no-bullet', '1');
                        preventBulletOnListItem(li.parentNode);
                    }
                }
            }
            return promise;
        }
        drawDOM.getFontFaces = getFontFaces;
        drawDOM.drawText = function (element) {
            var group = new Group();
            nodeInfo._clipbox = false;
            nodeInfo._matrix = Matrix.unit();
            nodeInfo._stackingContext = {
                element: element,
                group: group
            };
            pushNodeInfo(element, getComputedStyle(element), group);
            if (element.firstChild.nodeType == 3) {
                renderText(element, element.firstChild, group);
            } else {
                _renderElement(element, group);
            }
            popNodeInfo();
            return group;
        };
        var parseBackgroundImage = function () {
            var tok_linear_gradient = /^((-webkit-|-moz-|-o-|-ms-)?linear-gradient\s*)\(/;
            var tok_percent = /^([-0-9.]+%)/;
            var tok_length = /^([-0-9.]+px)/;
            var tok_keyword = /^(left|right|top|bottom|to|center)\W/;
            var tok_angle = /^([-0-9.]+(deg|grad|rad|turn))/;
            var tok_whitespace = /^(\s+)/;
            var tok_popen = /^(\()/;
            var tok_pclose = /^(\))/;
            var tok_comma = /^(,)/;
            var tok_url = /^(url)\(/;
            var tok_content = /^(.*?)\)/;
            var cache1 = {}, cache2 = {};
            function parse(input) {
                var orig = input;
                if (hasOwnProperty(cache1, orig)) {
                    return cache1[orig];
                }
                function skip_ws() {
                    var m = tok_whitespace.exec(input);
                    if (m) {
                        input = input.substr(m[1].length);
                    }
                }
                function read(token) {
                    skip_ws();
                    var m = token.exec(input);
                    if (m) {
                        input = input.substr(m[1].length);
                        return m[1];
                    }
                }
                function read_stop() {
                    var color = kendo.parseColor(input, true);
                    var length, percent;
                    if (color) {
                        var match = /^#[0-9a-f]+/i.exec(input) || /^rgba?\(.*?\)/i.exec(input) || /^..*?\b/.exec(input);
                        input = input.substr(match[0].length);
                        color = color.toRGB();
                        if (!(length = read(tok_length))) {
                            percent = read(tok_percent);
                        }
                        return {
                            color: color,
                            length: length,
                            percent: percent
                        };
                    }
                }
                function read_linear_gradient(propName) {
                    var angle;
                    var to1, to2;
                    var stops = [];
                    var reverse = false;
                    if (read(tok_popen)) {
                        angle = read(tok_angle);
                        if (angle) {
                            angle = parseAngle(angle);
                            read(tok_comma);
                        } else {
                            to1 = read(tok_keyword);
                            if (to1 == 'to') {
                                to1 = read(tok_keyword);
                            } else if (to1 && /^-/.test(propName)) {
                                reverse = true;
                            }
                            to2 = read(tok_keyword);
                            read(tok_comma);
                        }
                        if (/-moz-/.test(propName) && angle == null && to1 == null) {
                            var x = read(tok_percent), y = read(tok_percent);
                            reverse = true;
                            if (x == '0%') {
                                to1 = 'left';
                            } else if (x == '100%') {
                                to1 = 'right';
                            }
                            if (y == '0%') {
                                to2 = 'top';
                            } else if (y == '100%') {
                                to2 = 'bottom';
                            }
                            read(tok_comma);
                        }
                        while (input && !read(tok_pclose)) {
                            var stop = read_stop();
                            if (!stop) {
                                break;
                            }
                            stops.push(stop);
                            read(tok_comma);
                        }
                        return {
                            type: 'linear',
                            angle: angle,
                            to: to1 && to2 ? to1 + ' ' + to2 : to1 ? to1 : to2 ? to2 : null,
                            stops: stops,
                            reverse: reverse
                        };
                    }
                }
                function read_url() {
                    if (read(tok_popen)) {
                        var url = read(tok_content);
                        url = url.replace(/^['"]+|["']+$/g, '');
                        read(tok_pclose);
                        return {
                            type: 'url',
                            url: url
                        };
                    }
                }
                var tok;
                if (tok = read(tok_linear_gradient)) {
                    tok = read_linear_gradient(tok);
                } else if (tok = read(tok_url)) {
                    tok = read_url();
                }
                return cache1[orig] = tok || { type: 'none' };
            }
            return function (input) {
                if (hasOwnProperty(cache2, input)) {
                    return cache2[input];
                }
                return cache2[input] = splitProperty(input).map(parse);
            };
        }();
        var splitProperty = function () {
            var cache = {};
            return function (input, separator) {
                if (!separator) {
                    separator = /^\s*,\s*/;
                }
                var cacheKey = input + separator;
                if (hasOwnProperty(cache, cacheKey)) {
                    return cache[cacheKey];
                }
                var ret = [];
                var last$$1 = 0, pos = 0;
                var in_paren = 0;
                var in_string = false;
                var m;
                function looking_at(rx) {
                    return m = rx.exec(input.substr(pos));
                }
                function trim(str) {
                    return str.replace(/^\s+|\s+$/g, '');
                }
                while (pos < input.length) {
                    if (!in_string && looking_at(/^[\(\[\{]/)) {
                        in_paren++;
                        pos++;
                    } else if (!in_string && looking_at(/^[\)\]\}]/)) {
                        in_paren--;
                        pos++;
                    } else if (!in_string && looking_at(/^[\"\']/)) {
                        in_string = m[0];
                        pos++;
                    } else if (in_string == '\'' && looking_at(/^\\\'/)) {
                        pos += 2;
                    } else if (in_string == '"' && looking_at(/^\\\"/)) {
                        pos += 2;
                    } else if (in_string == '\'' && looking_at(/^\'/)) {
                        in_string = false;
                        pos++;
                    } else if (in_string == '"' && looking_at(/^\"/)) {
                        in_string = false;
                        pos++;
                    } else if (looking_at(separator)) {
                        if (!in_string && !in_paren && pos > last$$1) {
                            ret.push(trim(input.substring(last$$1, pos)));
                            last$$1 = pos + m[0].length;
                        }
                        pos += m[0].length;
                    } else {
                        pos++;
                    }
                }
                if (last$$1 < pos) {
                    ret.push(trim(input.substring(last$$1, pos)));
                }
                return cache[cacheKey] = ret;
            };
        }();
        var getFontURL = function (cache) {
            return function (el) {
                var url = cache[el];
                if (!url) {
                    var m;
                    if (m = /url\((['"]?)([^'")]*?)\1\)\s+format\((['"]?)truetype\3\)/.exec(el)) {
                        url = cache[el] = m[2];
                    } else if (m = /url\((['"]?)([^'")]*?\.ttf)\1\)/.exec(el)) {
                        url = cache[el] = m[2];
                    }
                }
                return url;
            };
        }(Object.create ? Object.create(null) : {});
        var getFontHeight = function (cache) {
            return function (font) {
                var height = cache[font];
                if (height == null) {
                    height = cache[font] = kendoUtil.measureText('Mapq', { font: font }).height;
                }
                return height;
            };
        }(Object.create ? Object.create(null) : {});
        function getFontFaces(doc) {
            if (doc == null) {
                doc = document;
            }
            var result = {};
            for (var i = 0; i < doc.styleSheets.length; ++i) {
                doStylesheet(doc.styleSheets[i]);
            }
            return result;
            function doStylesheet(ss) {
                if (ss) {
                    var rules = null;
                    try {
                        rules = ss.cssRules;
                    } catch (ex) {
                    }
                    if (rules) {
                        addRules(ss, rules);
                    }
                }
            }
            function findFonts(rule) {
                var src = getPropertyValue(rule.style, 'src');
                if (src) {
                    return splitProperty(src).reduce(function (a, el) {
                        var font = getFontURL(el);
                        if (font) {
                            a.push(font);
                        }
                        return a;
                    }, []);
                } else {
                    var font = getFontURL(rule.cssText);
                    return font ? [font] : [];
                }
            }
            function addRules(styleSheet, rules) {
                for (var i = 0; i < rules.length; ++i) {
                    var r = rules[i];
                    switch (r.type) {
                    case 3:
                        doStylesheet(r.styleSheet);
                        break;
                    case 5:
                        var style = r.style;
                        var family = splitProperty(getPropertyValue(style, 'font-family'));
                        var bold = /^([56789]00|bold)$/i.test(getPropertyValue(style, 'font-weight'));
                        var italic = 'italic' == getPropertyValue(style, 'font-style');
                        var src = findFonts(r);
                        if (src.length > 0) {
                            addRule(styleSheet, family, bold, italic, src[0]);
                        }
                    }
                }
            }
            function addRule(styleSheet, names, bold, italic, url) {
                if (!/^data:/i.test(url)) {
                    if (!(/^[^\/:]+:\/\//.test(url) || /^\//.test(url))) {
                        url = String(styleSheet.href).replace(/[^\/]*$/, '') + url;
                    }
                }
                names.forEach(function (name) {
                    name = name.replace(/^(['"]?)(.*?)\1$/, '$2');
                    if (bold) {
                        name += '|bold';
                    }
                    if (italic) {
                        name += '|italic';
                    }
                    result[name] = url;
                });
            }
        }
        function hasOwnProperty(obj, key) {
            return Object.prototype.hasOwnProperty.call(obj, key);
        }
        function getCounter(name) {
            name = '_counter_' + name;
            return nodeInfo[name];
        }
        function getAllCounters(name) {
            var values = [], p = nodeInfo;
            name = '_counter_' + name;
            while (p) {
                if (hasOwnProperty(p, name)) {
                    values.push(p[name]);
                }
                p = Object.getPrototypeOf(p);
            }
            return values.reverse();
        }
        function incCounter(name, inc) {
            var p = nodeInfo;
            name = '_counter_' + name;
            while (p && !hasOwnProperty(p, name)) {
                p = Object.getPrototypeOf(p);
            }
            if (!p) {
                p = nodeInfo._root;
            }
            p[name] = (p[name] || 0) + (inc == null ? 1 : inc);
        }
        function resetCounter(name, val) {
            name = '_counter_' + name;
            nodeInfo[name] = val == null ? 0 : val;
        }
        function doCounters(a, f, def) {
            for (var i = 0; i < a.length;) {
                var name = a[i++];
                var val = parseFloat(a[i]);
                if (isNaN(val)) {
                    f(name, def);
                } else {
                    f(name, val);
                    ++i;
                }
            }
        }
        function updateCounters(style) {
            var counterReset = getPropertyValue(style, 'counter-reset');
            if (counterReset) {
                doCounters(splitProperty(counterReset, /^\s+/), resetCounter, 0);
            }
            var counterIncrement = getPropertyValue(style, 'counter-increment');
            if (counterIncrement) {
                doCounters(splitProperty(counterIncrement, /^\s+/), incCounter, 1);
            }
        }
        function parseColor$1(str, css) {
            var color = kendo.parseColor(str, true);
            if (color) {
                color = color.toRGB();
                if (css) {
                    color = color.toCssRgba();
                } else if (color.a === 0) {
                    color = null;
                }
            }
            return color;
        }
        function whenImagesAreActuallyLoaded(elements, callback) {
            var pending = 0;
            elements.forEach(function (el) {
                var images = el.querySelectorAll('img');
                for (var i = 0; i < images.length; ++i) {
                    var img = images[i];
                    if (!img.complete) {
                        pending++;
                        img.onload = img.onerror = next;
                    }
                }
            });
            if (!pending) {
                next();
            }
            function next() {
                if (--pending <= 0) {
                    callback();
                }
            }
        }
        function cacheImages(element, callback) {
            var urls = [];
            function add(url) {
                if (!IMAGE_CACHE[url]) {
                    IMAGE_CACHE[url] = true;
                    urls.push(url);
                }
            }
            function dive(element) {
                if (/^img$/i.test(element.tagName)) {
                    add(element.src);
                }
                parseBackgroundImage(getPropertyValue(getComputedStyle(element), 'background-image')).forEach(function (bg) {
                    if (bg.type == 'url') {
                        add(bg.url);
                    }
                });
                if (element.children) {
                    slice$1(element.children).forEach(dive);
                }
            }
            if (Array.isArray(element)) {
                element.forEach(dive);
            } else {
                dive(element);
            }
            var count = urls.length;
            function next() {
                if (--count <= 0) {
                    callback();
                }
            }
            if (count === 0) {
                next();
            }
            urls.forEach(function (url) {
                var img = IMAGE_CACHE[url] = new window.Image();
                if (!/^data:/i.test(url)) {
                    img.crossOrigin = 'Anonymous';
                }
                img.src = url;
                if (img.complete) {
                    next();
                } else {
                    img.onload = next;
                    img.onerror = function () {
                        IMAGE_CACHE[url] = null;
                        next();
                    };
                }
            });
        }
        function alphaNumeral(n) {
            var result = '';
            do {
                var r = n % 26;
                result = String.fromCharCode(97 + r) + result;
                n = Math.floor(n / 26);
            } while (n > 0);
            return result;
        }
        function pushNodeInfo(element, style, group) {
            nodeInfo = Object.create(nodeInfo);
            nodeInfo[element.tagName.toLowerCase()] = {
                element: element,
                style: style
            };
            var decoration = getPropertyValue(style, 'text-decoration');
            if (decoration && decoration != 'none') {
                var color = getPropertyValue(style, 'color');
                decoration.split(/\s+/g).forEach(function (name) {
                    if (!nodeInfo[name]) {
                        nodeInfo[name] = color;
                    }
                });
            }
            if (createsStackingContext(style)) {
                nodeInfo._stackingContext = {
                    element: element,
                    group: group
                };
            }
        }
        function popNodeInfo() {
            nodeInfo = Object.getPrototypeOf(nodeInfo);
        }
        function updateClipbox(path) {
            if (nodeInfo._clipbox != null) {
                var box = path.bbox(nodeInfo._matrix);
                if (nodeInfo._clipbox) {
                    nodeInfo._clipbox = Rect.intersect(nodeInfo._clipbox, box);
                } else {
                    nodeInfo._clipbox = box;
                }
            }
        }
        function emptyClipbox() {
            var cb = nodeInfo._clipbox;
            if (cb == null) {
                return true;
            }
            if (cb) {
                return cb.width() === 0 || cb.height() === 0;
            }
        }
        function createsStackingContext(style) {
            function prop(name) {
                return getPropertyValue(style, name);
            }
            if (prop('transform') != 'none' || prop('position') != 'static' || prop('z-index') != 'auto' || prop('opacity') < 1) {
                return true;
            }
        }
        function getComputedStyle(element, pseudoElt) {
            return window.getComputedStyle(element, pseudoElt || null);
        }
        function getPropertyValue(style, prop, defa) {
            var val = style.getPropertyValue(prop);
            if (val == null || val === '') {
                if (browser.webkit) {
                    val = style.getPropertyValue('-webkit-' + prop);
                } else if (browser.mozilla) {
                    val = style.getPropertyValue('-moz-' + prop);
                } else if (browser.opera) {
                    val = style.getPropertyValue('-o-' + prop);
                } else if (microsoft) {
                    val = style.getPropertyValue('-ms-' + prop);
                }
            }
            if (arguments.length > 2 && (val == null || val === '')) {
                return defa;
            } else {
                return val;
            }
        }
        function pleaseSetPropertyValue(style, prop, value, important) {
            style.setProperty(prop, value, important);
            if (browser.webkit) {
                style.setProperty('-webkit-' + prop, value, important);
            } else if (browser.mozilla) {
                style.setProperty('-moz-' + prop, value, important);
            } else if (browser.opera) {
                style.setProperty('-o-' + prop, value, important);
            } else if (microsoft) {
                style.setProperty('-ms-' + prop, value, important);
                prop = 'ms' + prop.replace(/(^|-)([a-z])/g, function (s, p1, p2) {
                    return p1 + p2.toUpperCase();
                });
                style[prop] = value;
            }
        }
        function getBorder(style, side) {
            side = 'border-' + side;
            return {
                width: parseFloat(getPropertyValue(style, side + '-width')),
                style: getPropertyValue(style, side + '-style'),
                color: parseColor$1(getPropertyValue(style, side + '-color'), true)
            };
        }
        function saveStyle(element, func) {
            var prev = element.style.cssText;
            var result = func();
            element.style.cssText = prev;
            return result;
        }
        function getBorderRadius(style, side) {
            var r = getPropertyValue(style, 'border-' + side + '-radius').split(/\s+/g).map(parseFloat);
            if (r.length == 1) {
                r.push(r[0]);
            }
            return sanitizeRadius({
                x: r[0],
                y: r[1]
            });
        }
        function getContentBox(element) {
            var box = element.getBoundingClientRect();
            box = innerBox(box, 'border-*-width', element);
            box = innerBox(box, 'padding-*', element);
            return box;
        }
        function innerBox(box, prop, element) {
            var style, wt, wr, wb, wl;
            if (typeof prop == 'string') {
                style = getComputedStyle(element);
                wt = parseFloat(getPropertyValue(style, prop.replace('*', 'top')));
                wr = parseFloat(getPropertyValue(style, prop.replace('*', 'right')));
                wb = parseFloat(getPropertyValue(style, prop.replace('*', 'bottom')));
                wl = parseFloat(getPropertyValue(style, prop.replace('*', 'left')));
            } else if (typeof prop == 'number') {
                wt = wr = wb = wl = prop;
            }
            return {
                top: box.top + wt,
                right: box.right - wr,
                bottom: box.bottom - wb,
                left: box.left + wl,
                width: box.right - box.left - wr - wl,
                height: box.bottom - box.top - wb - wt
            };
        }
        function getTransform(style) {
            var transform$$1 = getPropertyValue(style, 'transform');
            if (transform$$1 == 'none') {
                return null;
            }
            var matrix = /^\s*matrix\(\s*(.*?)\s*\)\s*$/.exec(transform$$1);
            if (matrix) {
                var origin = getPropertyValue(style, 'transform-origin');
                matrix = matrix[1].split(/\s*,\s*/g).map(parseFloat);
                origin = origin.split(/\s+/g).map(parseFloat);
                return {
                    matrix: matrix,
                    origin: origin
                };
            }
        }
        function radiansToDegrees(radians) {
            return 180 * radians / Math.PI % 360;
        }
        function parseAngle(angle) {
            var num = parseFloat(angle);
            if (/grad$/.test(angle)) {
                return Math.PI * num / 200;
            } else if (/rad$/.test(angle)) {
                return num;
            } else if (/turn$/.test(angle)) {
                return Math.PI * num * 2;
            } else if (/deg$/.test(angle)) {
                return Math.PI * num / 180;
            }
        }
        function setTransform(shape, m) {
            m = new Matrix(m[0], m[1], m[2], m[3], m[4], m[5]);
            shape.transform(m);
            return m;
        }
        function setClipping(shape, clipPath) {
            shape.clip(clipPath);
        }
        function addArcToPath(path, x, y, options) {
            var points = new Arc$2([
                    x,
                    y
                ], options).curvePoints(), i = 1;
            while (i < points.length) {
                path.curveTo(points[i++], points[i++], points[i++]);
            }
        }
        function sanitizeRadius(r) {
            if (r.x <= 0 || r.y <= 0) {
                r.x = r.y = 0;
            }
            return r;
        }
        function adjustBorderRadiusForBox(box, rTL, rTR, rBR, rBL) {
            var tl_x = Math.max(0, rTL.x), tl_y = Math.max(0, rTL.y);
            var tr_x = Math.max(0, rTR.x), tr_y = Math.max(0, rTR.y);
            var br_x = Math.max(0, rBR.x), br_y = Math.max(0, rBR.y);
            var bl_x = Math.max(0, rBL.x), bl_y = Math.max(0, rBL.y);
            var f = Math.min(box.width / (tl_x + tr_x), box.height / (tr_y + br_y), box.width / (br_x + bl_x), box.height / (bl_y + tl_y));
            if (f < 1) {
                tl_x *= f;
                tl_y *= f;
                tr_x *= f;
                tr_y *= f;
                br_x *= f;
                br_y *= f;
                bl_x *= f;
                bl_y *= f;
            }
            return {
                tl: {
                    x: tl_x,
                    y: tl_y
                },
                tr: {
                    x: tr_x,
                    y: tr_y
                },
                br: {
                    x: br_x,
                    y: br_y
                },
                bl: {
                    x: bl_x,
                    y: bl_y
                }
            };
        }
        function elementRoundBox(element, box, type) {
            var style = getComputedStyle(element);
            var rTL = getBorderRadius(style, 'top-left');
            var rTR = getBorderRadius(style, 'top-right');
            var rBL = getBorderRadius(style, 'bottom-left');
            var rBR = getBorderRadius(style, 'bottom-right');
            if (type == 'padding' || type == 'content') {
                var bt = getBorder(style, 'top');
                var br = getBorder(style, 'right');
                var bb = getBorder(style, 'bottom');
                var bl = getBorder(style, 'left');
                rTL.x -= bl.width;
                rTL.y -= bt.width;
                rTR.x -= br.width;
                rTR.y -= bt.width;
                rBR.x -= br.width;
                rBR.y -= bb.width;
                rBL.x -= bl.width;
                rBL.y -= bb.width;
                if (type == 'content') {
                    var pt = parseFloat(getPropertyValue(style, 'padding-top'));
                    var pr = parseFloat(getPropertyValue(style, 'padding-right'));
                    var pb = parseFloat(getPropertyValue(style, 'padding-bottom'));
                    var pl = parseFloat(getPropertyValue(style, 'padding-left'));
                    rTL.x -= pl;
                    rTL.y -= pt;
                    rTR.x -= pr;
                    rTR.y -= pt;
                    rBR.x -= pr;
                    rBR.y -= pb;
                    rBL.x -= pl;
                    rBL.y -= pb;
                }
            }
            if (typeof type == 'number') {
                rTL.x -= type;
                rTL.y -= type;
                rTR.x -= type;
                rTR.y -= type;
                rBR.x -= type;
                rBR.y -= type;
                rBL.x -= type;
                rBL.y -= type;
            }
            return roundBox(box, rTL, rTR, rBR, rBL);
        }
        function roundBox(box, rTL0, rTR0, rBR0, rBL0) {
            var tmp = adjustBorderRadiusForBox(box, rTL0, rTR0, rBR0, rBL0);
            var rTL = tmp.tl;
            var rTR = tmp.tr;
            var rBR = tmp.br;
            var rBL = tmp.bl;
            var path = new Path({
                fill: null,
                stroke: null
            });
            path.moveTo(box.left, box.top + rTL.y);
            if (rTL.x) {
                addArcToPath(path, box.left + rTL.x, box.top + rTL.y, {
                    startAngle: -180,
                    endAngle: -90,
                    radiusX: rTL.x,
                    radiusY: rTL.y
                });
            }
            path.lineTo(box.right - rTR.x, box.top);
            if (rTR.x) {
                addArcToPath(path, box.right - rTR.x, box.top + rTR.y, {
                    startAngle: -90,
                    endAngle: 0,
                    radiusX: rTR.x,
                    radiusY: rTR.y
                });
            }
            path.lineTo(box.right, box.bottom - rBR.y);
            if (rBR.x) {
                addArcToPath(path, box.right - rBR.x, box.bottom - rBR.y, {
                    startAngle: 0,
                    endAngle: 90,
                    radiusX: rBR.x,
                    radiusY: rBR.y
                });
            }
            path.lineTo(box.left + rBL.x, box.bottom);
            if (rBL.x) {
                addArcToPath(path, box.left + rBL.x, box.bottom - rBL.y, {
                    startAngle: 90,
                    endAngle: 180,
                    radiusX: rBL.x,
                    radiusY: rBL.y
                });
            }
            return path.close();
        }
        function formatCounter(val, style) {
            var str = String(parseFloat(val));
            switch (style) {
            case 'decimal-leading-zero':
                if (str.length < 2) {
                    str = '0' + str;
                }
                return str;
            case 'lower-roman':
                return arabicToRoman(val).toLowerCase();
            case 'upper-roman':
                return arabicToRoman(val).toUpperCase();
            case 'lower-latin':
            case 'lower-alpha':
                return alphaNumeral(val - 1);
            case 'upper-latin':
            case 'upper-alpha':
                return alphaNumeral(val - 1).toUpperCase();
            default:
                return str;
            }
        }
        function evalPseudoElementContent(element, content) {
            function displayCounter(name, style, separator) {
                if (!separator) {
                    return formatCounter(getCounter(name) || 0, style);
                }
                separator = separator.replace(/^\s*(["'])(.*)\1\s*$/, '$2');
                return getAllCounters(name).map(function (val) {
                    return formatCounter(val, style);
                }).join(separator);
            }
            var a = splitProperty(content, /^\s+/);
            var result = [], m;
            a.forEach(function (el) {
                var tmp;
                if (m = /^\s*(["'])(.*)\1\s*$/.exec(el)) {
                    result.push(m[2].replace(/\\([0-9a-f]{4})/gi, function (s, p) {
                        return String.fromCharCode(parseInt(p, 16));
                    }));
                } else if (m = /^\s*counter\((.*?)\)\s*$/.exec(el)) {
                    tmp = splitProperty(m[1]);
                    result.push(displayCounter(tmp[0], tmp[1]));
                } else if (m = /^\s*counters\((.*?)\)\s*$/.exec(el)) {
                    tmp = splitProperty(m[1]);
                    result.push(displayCounter(tmp[0], tmp[2], tmp[1]));
                } else if (m = /^\s*attr\((.*?)\)\s*$/.exec(el)) {
                    result.push(element.getAttribute(m[1]) || '');
                } else {
                    result.push(el);
                }
            });
            return result.join('');
        }
        function getCssText(style) {
            if (style.cssText) {
                return style.cssText;
            }
            var result = [];
            for (var i = 0; i < style.length; ++i) {
                result.push(style[i] + ': ' + getPropertyValue(style, style[i]));
            }
            return result.join(';\n');
        }
        function _renderWithPseudoElements(element, group) {
            if (element.tagName == KENDO_PSEUDO_ELEMENT) {
                _renderElement(element, group);
                return;
            }
            var fake = [];
            function pseudo(kind, place) {
                var style = getComputedStyle(element, kind), content = style.content;
                updateCounters(style);
                if (content && content != 'normal' && content != 'none' && style.width != '0px') {
                    var psel = element.ownerDocument.createElement(KENDO_PSEUDO_ELEMENT);
                    psel.style.cssText = getCssText(style);
                    psel.textContent = evalPseudoElementContent(element, content);
                    element.insertBefore(psel, place);
                    fake.push(psel);
                }
            }
            pseudo(':before', element.firstChild);
            pseudo(':after', null);
            if (fake.length > 0) {
                var saveClass = element.className;
                element.className += ' kendo-pdf-hide-pseudo-elements';
                _renderElement(element, group);
                element.className = saveClass;
                fake.forEach(function (el) {
                    element.removeChild(el);
                });
            } else {
                _renderElement(element, group);
            }
        }
        function _renderElement(element, group) {
            var style = getComputedStyle(element);
            var top = getBorder(style, 'top');
            var right = getBorder(style, 'right');
            var bottom = getBorder(style, 'bottom');
            var left = getBorder(style, 'left');
            var rTL0 = getBorderRadius(style, 'top-left');
            var rTR0 = getBorderRadius(style, 'top-right');
            var rBL0 = getBorderRadius(style, 'bottom-left');
            var rBR0 = getBorderRadius(style, 'bottom-right');
            var dir = getPropertyValue(style, 'direction');
            var backgroundColor = getPropertyValue(style, 'background-color');
            backgroundColor = parseColor$1(backgroundColor);
            var backgroundImage = parseBackgroundImage(getPropertyValue(style, 'background-image'));
            var backgroundRepeat = splitProperty(getPropertyValue(style, 'background-repeat'));
            var backgroundPosition = splitProperty(getPropertyValue(style, 'background-position'));
            var backgroundOrigin = splitProperty(getPropertyValue(style, 'background-origin'));
            var backgroundSize = splitProperty(getPropertyValue(style, 'background-size'));
            var textOverflow, saveTextOverflow;
            if (microsoft) {
                textOverflow = style.textOverflow;
                if (textOverflow == 'ellipsis') {
                    saveTextOverflow = element.style.textOverflow;
                    element.style.textOverflow = 'clip';
                }
            }
            if (browser.msie && browser.version < 10) {
                backgroundPosition = splitProperty(element.currentStyle.backgroundPosition);
            }
            var innerbox = innerBox(element.getBoundingClientRect(), 'border-*-width', element);
            (function () {
                var clip = getPropertyValue(style, 'clip');
                var m = /^\s*rect\((.*)\)\s*$/.exec(clip);
                if (m) {
                    var a = m[1].split(/[ ,]+/g);
                    var top = a[0] == 'auto' ? innerbox.top : parseFloat(a[0]) + innerbox.top;
                    var right = a[1] == 'auto' ? innerbox.right : parseFloat(a[1]) + innerbox.left;
                    var bottom = a[2] == 'auto' ? innerbox.bottom : parseFloat(a[2]) + innerbox.top;
                    var left = a[3] == 'auto' ? innerbox.left : parseFloat(a[3]) + innerbox.left;
                    var tmp = new Group();
                    var clipPath = new Path().moveTo(left, top).lineTo(right, top).lineTo(right, bottom).lineTo(left, bottom).close();
                    setClipping(tmp, clipPath);
                    group.append(tmp);
                    group = tmp;
                    updateClipbox(clipPath);
                }
            }());
            var boxes, i, cells;
            var display = getPropertyValue(style, 'display');
            if (display == 'table-row') {
                boxes = [];
                for (i = 0, cells = element.children; i < cells.length; ++i) {
                    boxes.push(cells[i].getBoundingClientRect());
                }
            } else {
                boxes = element.getClientRects();
                if (boxes.length == 1) {
                    boxes = [element.getBoundingClientRect()];
                }
            }
            boxes = adjustBoxes(boxes);
            for (i = 0; i < boxes.length; ++i) {
                drawOneBox(boxes[i], i === 0, i == boxes.length - 1);
            }
            if (element.tagName == 'A' && element.href && !/^#?$/.test(element.getAttribute('href'))) {
                if (!nodeInfo._avoidLinks || !matches(element, nodeInfo._avoidLinks)) {
                    var r = document.createRange();
                    r.selectNodeContents(element);
                    slice$1(r.getClientRects()).forEach(function (box) {
                        var g = new Group();
                        g._pdfLink = {
                            url: element.href,
                            top: box.top,
                            right: box.right,
                            bottom: box.bottom,
                            left: box.left
                        };
                        group.append(g);
                    });
                }
            }
            if (boxes.length > 0 && display == 'list-item' && !element.getAttribute('kendo-no-bullet')) {
                drawBullet(boxes[0]);
            }
            (function () {
                function clipit() {
                    var clipPath = elementRoundBox(element, innerbox, 'padding');
                    var tmp = new Group();
                    setClipping(tmp, clipPath);
                    group.append(tmp);
                    group = tmp;
                    updateClipbox(clipPath);
                }
                if (isFormField(element)) {
                    clipit();
                } else if (/^(hidden|auto|scroll)/.test(getPropertyValue(style, 'overflow'))) {
                    clipit();
                } else if (/^(hidden|auto|scroll)/.test(getPropertyValue(style, 'overflow-x'))) {
                    clipit();
                } else if (/^(hidden|auto|scroll)/.test(getPropertyValue(style, 'overflow-y'))) {
                    clipit();
                }
            }());
            if (!maybeRenderWidget(element, group)) {
                renderContents(element, group);
            }
            if (microsoft && textOverflow == 'ellipsis') {
                element.style.textOverflow = saveTextOverflow;
            }
            return group;
            function adjustBoxes(boxes) {
                if (/^td$/i.test(element.tagName)) {
                    var table = nodeInfo.table;
                    if (table && getPropertyValue(table.style, 'border-collapse') == 'collapse') {
                        var tableBorderLeft = getBorder(table.style, 'left').width;
                        var tableBorderTop = getBorder(table.style, 'top').width;
                        if (tableBorderLeft === 0 && tableBorderTop === 0) {
                            return boxes;
                        }
                        var tableBox = table.element.getBoundingClientRect();
                        var firstCell = table.element.rows[0].cells[0];
                        var firstCellBox = firstCell.getBoundingClientRect();
                        if (firstCellBox.top == tableBox.top || firstCellBox.left == tableBox.left) {
                            return slice$1(boxes).map(function (box) {
                                return {
                                    left: box.left + tableBorderLeft,
                                    top: box.top + tableBorderTop,
                                    right: box.right + tableBorderLeft,
                                    bottom: box.bottom + tableBorderTop,
                                    height: box.height,
                                    width: box.width
                                };
                            });
                        }
                    }
                }
                return boxes;
            }
            function drawEdge(color, len, Wtop, Wleft, Wright, rl, rr, transform$$1) {
                if (Wtop <= 0) {
                    return;
                }
                var path, edge = new Group();
                setTransform(edge, transform$$1);
                group.append(edge);
                sanitizeRadius(rl);
                sanitizeRadius(rr);
                path = new Path({
                    fill: { color: color },
                    stroke: null
                });
                edge.append(path);
                path.moveTo(rl.x ? Math.max(rl.x, Wleft) : 0, 0).lineTo(len - (rr.x ? Math.max(rr.x, Wright) : 0), 0).lineTo(len - Math.max(rr.x, Wright), Wtop).lineTo(Math.max(rl.x, Wleft), Wtop).close();
                if (rl.x) {
                    drawRoundCorner(Wleft, rl, [
                        -1,
                        0,
                        0,
                        1,
                        rl.x,
                        0
                    ]);
                }
                if (rr.x) {
                    drawRoundCorner(Wright, rr, [
                        1,
                        0,
                        0,
                        1,
                        len - rr.x,
                        0
                    ]);
                }
                function drawRoundCorner(Wright, r, transform$$1) {
                    var angle = Math.PI / 2 * Wright / (Wright + Wtop);
                    var ri = {
                        x: r.x - Wright,
                        y: r.y - Wtop
                    };
                    var path = new Path({
                        fill: { color: color },
                        stroke: null
                    }).moveTo(0, 0);
                    setTransform(path, transform$$1);
                    addArcToPath(path, 0, r.y, {
                        startAngle: -90,
                        endAngle: -radiansToDegrees(angle),
                        radiusX: r.x,
                        radiusY: r.y
                    });
                    if (ri.x > 0 && ri.y > 0) {
                        path.lineTo(ri.x * Math.cos(angle), r.y - ri.y * Math.sin(angle));
                        addArcToPath(path, 0, r.y, {
                            startAngle: -radiansToDegrees(angle),
                            endAngle: -90,
                            radiusX: ri.x,
                            radiusY: ri.y,
                            anticlockwise: true
                        });
                    } else if (ri.x > 0) {
                        path.lineTo(ri.x, Wtop).lineTo(0, Wtop);
                    } else {
                        path.lineTo(ri.x, Wtop).lineTo(ri.x, 0);
                    }
                    edge.append(path.close());
                }
            }
            function drawBackground(box) {
                var background = new Group();
                setClipping(background, roundBox(box, rTL0, rTR0, rBR0, rBL0));
                group.append(background);
                if (backgroundColor) {
                    var path = new Path({
                        fill: { color: backgroundColor.toCssRgba() },
                        stroke: null
                    });
                    path.moveTo(box.left, box.top).lineTo(box.right, box.top).lineTo(box.right, box.bottom).lineTo(box.left, box.bottom).close();
                    background.append(path);
                }
                for (var i = backgroundImage.length; --i >= 0;) {
                    drawOneBackground(background, box, backgroundImage[i], backgroundRepeat[i % backgroundRepeat.length], backgroundPosition[i % backgroundPosition.length], backgroundOrigin[i % backgroundOrigin.length], backgroundSize[i % backgroundSize.length]);
                }
            }
            function drawOneBackground(group, box, background, backgroundRepeat, backgroundPosition, backgroundOrigin, backgroundSize) {
                if (!background || background == 'none') {
                    return;
                }
                if (background.type == 'url') {
                    if (/^url\(\"data:image\/svg/i.test(background.url)) {
                        return;
                    }
                    var img = IMAGE_CACHE[background.url];
                    if (img && img.width > 0 && img.height > 0) {
                        drawBackgroundImage(group, box, img.width, img.height, function (group, rect) {
                            group.append(new Image$1(background.url, rect));
                        });
                    }
                } else if (background.type == 'linear') {
                    drawBackgroundImage(group, box, box.width, box.height, gradientRenderer(background));
                } else {
                    return;
                }
                function drawBackgroundImage(group, box, img_width, img_height, renderBG) {
                    var aspect_ratio = img_width / img_height, f;
                    var orgBox = box;
                    if (backgroundOrigin == 'content-box') {
                        orgBox = innerBox(orgBox, 'border-*-width', element);
                        orgBox = innerBox(orgBox, 'padding-*', element);
                    } else if (backgroundOrigin == 'padding-box') {
                        orgBox = innerBox(orgBox, 'border-*-width', element);
                    }
                    if (!/^\s*auto(\s+auto)?\s*$/.test(backgroundSize)) {
                        if (backgroundSize == 'contain') {
                            f = Math.min(orgBox.width / img_width, orgBox.height / img_height);
                            img_width *= f;
                            img_height *= f;
                        } else if (backgroundSize == 'cover') {
                            f = Math.max(orgBox.width / img_width, orgBox.height / img_height);
                            img_width *= f;
                            img_height *= f;
                        } else {
                            var size = backgroundSize.split(/\s+/g);
                            if (/%$/.test(size[0])) {
                                img_width = orgBox.width * parseFloat(size[0]) / 100;
                            } else {
                                img_width = parseFloat(size[0]);
                            }
                            if (size.length == 1 || size[1] == 'auto') {
                                img_height = img_width / aspect_ratio;
                            } else if (/%$/.test(size[1])) {
                                img_height = orgBox.height * parseFloat(size[1]) / 100;
                            } else {
                                img_height = parseFloat(size[1]);
                            }
                        }
                    }
                    var pos = String(backgroundPosition);
                    switch (pos) {
                    case 'bottom':
                        pos = '50% 100%';
                        break;
                    case 'top':
                        pos = '50% 0';
                        break;
                    case 'left':
                        pos = '0 50%';
                        break;
                    case 'right':
                        pos = '100% 50%';
                        break;
                    case 'center':
                        pos = '50% 50%';
                        break;
                    }
                    pos = pos.split(/\s+/);
                    if (pos.length == 1) {
                        pos[1] = '50%';
                    }
                    if (/%$/.test(pos[0])) {
                        pos[0] = parseFloat(pos[0]) / 100 * (orgBox.width - img_width);
                    } else {
                        pos[0] = parseFloat(pos[0]);
                    }
                    if (/%$/.test(pos[1])) {
                        pos[1] = parseFloat(pos[1]) / 100 * (orgBox.height - img_height);
                    } else {
                        pos[1] = parseFloat(pos[1]);
                    }
                    var rect = new Rect([
                        orgBox.left + pos[0],
                        orgBox.top + pos[1]
                    ], [
                        img_width,
                        img_height
                    ]);
                    function rewX() {
                        while (rect.origin.x > box.left) {
                            rect.origin.x -= img_width;
                        }
                    }
                    function rewY() {
                        while (rect.origin.y > box.top) {
                            rect.origin.y -= img_height;
                        }
                    }
                    function repeatX() {
                        while (rect.origin.x < box.right) {
                            renderBG(group, rect.clone());
                            rect.origin.x += img_width;
                        }
                    }
                    if (backgroundRepeat == 'no-repeat') {
                        renderBG(group, rect);
                    } else if (backgroundRepeat == 'repeat-x') {
                        rewX();
                        repeatX();
                    } else if (backgroundRepeat == 'repeat-y') {
                        rewY();
                        while (rect.origin.y < box.bottom) {
                            renderBG(group, rect.clone());
                            rect.origin.y += img_height;
                        }
                    } else if (backgroundRepeat == 'repeat') {
                        rewX();
                        rewY();
                        var origin = rect.origin.clone();
                        while (rect.origin.y < box.bottom) {
                            rect.origin.x = origin.x;
                            repeatX();
                            rect.origin.y += img_height;
                        }
                    }
                }
            }
            function drawBullet() {
                var listStyleType = getPropertyValue(style, 'list-style-type');
                if (listStyleType == 'none') {
                    return;
                }
                var listStylePosition = getPropertyValue(style, 'list-style-position');
                function _drawBullet(f) {
                    saveStyle(element, function () {
                        element.style.position = 'relative';
                        var bullet = element.ownerDocument.createElement(KENDO_PSEUDO_ELEMENT);
                        bullet.style.position = 'absolute';
                        bullet.style.boxSizing = 'border-box';
                        if (listStylePosition == 'outside') {
                            bullet.style.width = '6em';
                            bullet.style.left = '-6.8em';
                            bullet.style.textAlign = 'right';
                        } else {
                            bullet.style.left = '0px';
                        }
                        f(bullet);
                        element.insertBefore(bullet, element.firstChild);
                        renderElement(bullet, group);
                        element.removeChild(bullet);
                    });
                }
                function elementIndex(f) {
                    var a = element.parentNode.children;
                    var k = element.getAttribute('kendo-split-index');
                    if (k != null) {
                        return f(k | 0, a.length);
                    }
                    for (var i = 0; i < a.length; ++i) {
                        if (a[i] === element) {
                            return f(i, a.length);
                        }
                    }
                }
                switch (listStyleType) {
                case 'circle':
                case 'disc':
                case 'square':
                    _drawBullet(function (bullet) {
                        bullet.style.fontSize = '60%';
                        bullet.style.lineHeight = '200%';
                        bullet.style.paddingRight = '0.5em';
                        bullet.style.fontFamily = 'DejaVu Serif';
                        bullet.innerHTML = {
                            'disc': '\u25CF',
                            'circle': '\u25EF',
                            'square': '\u25A0'
                        }[listStyleType];
                    });
                    break;
                case 'decimal':
                case 'decimal-leading-zero':
                    _drawBullet(function (bullet) {
                        elementIndex(function (idx) {
                            ++idx;
                            if (listStyleType == 'decimal-leading-zero' && idx < 10) {
                                idx = '0' + idx;
                            }
                            bullet.innerHTML = idx + '.';
                        });
                    });
                    break;
                case 'lower-roman':
                case 'upper-roman':
                    _drawBullet(function (bullet) {
                        elementIndex(function (idx) {
                            idx = arabicToRoman(idx + 1);
                            if (listStyleType == 'upper-roman') {
                                idx = idx.toUpperCase();
                            }
                            bullet.innerHTML = idx + '.';
                        });
                    });
                    break;
                case 'lower-latin':
                case 'lower-alpha':
                case 'upper-latin':
                case 'upper-alpha':
                    _drawBullet(function (bullet) {
                        elementIndex(function (idx) {
                            idx = alphaNumeral(idx);
                            if (/^upper/i.test(listStyleType)) {
                                idx = idx.toUpperCase();
                            }
                            bullet.innerHTML = idx + '.';
                        });
                    });
                    break;
                }
            }
            function drawOneBox(box, isFirst, isLast) {
                if (box.width === 0 || box.height === 0) {
                    return;
                }
                drawBackground(box);
                var shouldDrawLeft = left.width > 0 && (isFirst && dir == 'ltr' || isLast && dir == 'rtl');
                var shouldDrawRight = right.width > 0 && (isLast && dir == 'ltr' || isFirst && dir == 'rtl');
                if (top.width === 0 && left.width === 0 && right.width === 0 && bottom.width === 0) {
                    return;
                }
                if (top.color == right.color && top.color == bottom.color && top.color == left.color) {
                    if (top.width == right.width && top.width == bottom.width && top.width == left.width) {
                        if (shouldDrawLeft && shouldDrawRight) {
                            box = innerBox(box, top.width / 2);
                            var path = elementRoundBox(element, box, top.width / 2);
                            path.options.stroke = {
                                color: top.color,
                                width: top.width
                            };
                            group.append(path);
                            return;
                        }
                    }
                }
                if (rTL0.x === 0 && rTR0.x === 0 && rBR0.x === 0 && rBL0.x === 0) {
                    if (top.width < 2 && left.width < 2 && right.width < 2 && bottom.width < 2) {
                        if (top.width > 0) {
                            group.append(new Path({
                                stroke: {
                                    width: top.width,
                                    color: top.color
                                }
                            }).moveTo(box.left, box.top + top.width / 2).lineTo(box.right, box.top + top.width / 2));
                        }
                        if (bottom.width > 0) {
                            group.append(new Path({
                                stroke: {
                                    width: bottom.width,
                                    color: bottom.color
                                }
                            }).moveTo(box.left, box.bottom - bottom.width / 2).lineTo(box.right, box.bottom - bottom.width / 2));
                        }
                        if (shouldDrawLeft) {
                            group.append(new Path({
                                stroke: {
                                    width: left.width,
                                    color: left.color
                                }
                            }).moveTo(box.left + left.width / 2, box.top).lineTo(box.left + left.width / 2, box.bottom));
                        }
                        if (shouldDrawRight) {
                            group.append(new Path({
                                stroke: {
                                    width: right.width,
                                    color: right.color
                                }
                            }).moveTo(box.right - right.width / 2, box.top).lineTo(box.right - right.width / 2, box.bottom));
                        }
                        return;
                    }
                }
                var tmp = adjustBorderRadiusForBox(box, rTL0, rTR0, rBR0, rBL0);
                var rTL = tmp.tl;
                var rTR = tmp.tr;
                var rBR = tmp.br;
                var rBL = tmp.bl;
                drawEdge(top.color, box.width, top.width, left.width, right.width, rTL, rTR, [
                    1,
                    0,
                    0,
                    1,
                    box.left,
                    box.top
                ]);
                drawEdge(bottom.color, box.width, bottom.width, right.width, left.width, rBR, rBL, [
                    -1,
                    0,
                    0,
                    -1,
                    box.right,
                    box.bottom
                ]);
                function inv(p) {
                    return {
                        x: p.y,
                        y: p.x
                    };
                }
                drawEdge(left.color, box.height, left.width, bottom.width, top.width, inv(rBL), inv(rTL), [
                    0,
                    -1,
                    1,
                    0,
                    box.left,
                    box.bottom
                ]);
                drawEdge(right.color, box.height, right.width, top.width, bottom.width, inv(rTR), inv(rBR), [
                    0,
                    1,
                    -1,
                    0,
                    box.right,
                    box.top
                ]);
            }
        }
        function gradientRenderer(gradient) {
            return function (group, rect) {
                var width = rect.width(), height = rect.height();
                switch (gradient.type) {
                case 'linear':
                    var angle = gradient.angle != null ? gradient.angle : Math.PI;
                    switch (gradient.to) {
                    case 'top':
                        angle = 0;
                        break;
                    case 'left':
                        angle = -Math.PI / 2;
                        break;
                    case 'bottom':
                        angle = Math.PI;
                        break;
                    case 'right':
                        angle = Math.PI / 2;
                        break;
                    case 'top left':
                    case 'left top':
                        angle = -Math.atan2(height, width);
                        break;
                    case 'top right':
                    case 'right top':
                        angle = Math.atan2(height, width);
                        break;
                    case 'bottom left':
                    case 'left bottom':
                        angle = Math.PI + Math.atan2(height, width);
                        break;
                    case 'bottom right':
                    case 'right bottom':
                        angle = Math.PI - Math.atan2(height, width);
                        break;
                    }
                    if (gradient.reverse) {
                        angle -= Math.PI;
                    }
                    angle %= 2 * Math.PI;
                    if (angle < 0) {
                        angle += 2 * Math.PI;
                    }
                    var pxlen = Math.abs(width * Math.sin(angle)) + Math.abs(height * Math.cos(angle));
                    var scaledAngle = Math.atan(width * Math.tan(angle) / height);
                    var sin = Math.sin(scaledAngle), cos = Math.cos(scaledAngle);
                    var len = Math.abs(sin) + Math.abs(cos);
                    var x = len / 2 * sin;
                    var y = len / 2 * cos;
                    if (angle > Math.PI / 2 && angle <= 3 * Math.PI / 2) {
                        x = -x;
                        y = -y;
                    }
                    var implicit = [], right = 0;
                    var stops = gradient.stops.map(function (s, i) {
                        var offset = s.percent;
                        if (offset) {
                            offset = parseFloat(offset) / 100;
                        } else if (s.length) {
                            offset = parseFloat(s.length) / pxlen;
                        } else if (i === 0) {
                            offset = 0;
                        } else if (i == gradient.stops.length - 1) {
                            offset = 1;
                        }
                        var stop = {
                            color: s.color.toCssRgba(),
                            offset: offset
                        };
                        if (offset != null) {
                            right = offset;
                            implicit.forEach(function (s, i) {
                                var stop = s.stop;
                                stop.offset = s.left + (right - s.left) * (i + 1) / (implicit.length + 1);
                            });
                            implicit = [];
                        } else {
                            implicit.push({
                                left: right,
                                stop: stop
                            });
                        }
                        return stop;
                    });
                    var start = [
                        0.5 - x,
                        0.5 + y
                    ];
                    var end = [
                        0.5 + x,
                        0.5 - y
                    ];
                    group.append(Path.fromRect(rect).stroke(null).fill(new LinearGradient({
                        start: start,
                        end: end,
                        stops: stops,
                        userSpace: false
                    })));
                    break;
                case 'radial':
                    if (window.console && window.console.log) {
                        window.console.log('Radial gradients are not yet supported in HTML renderer');
                    }
                    break;
                }
            };
        }
        function maybeRenderWidget(element, group) {
            var visual;
            if (element._kendoExportVisual) {
                visual = element._kendoExportVisual();
            } else if (window.kendo && window.kendo.jQuery && element.getAttribute(window.kendo.attr('role'))) {
                var widget = window.kendo.widgetInstance(window.kendo.jQuery(element));
                if (widget && (widget.exportDOMVisual || widget.exportVisual)) {
                    if (widget.exportDOMVisual) {
                        visual = widget.exportDOMVisual();
                    } else {
                        visual = widget.exportVisual();
                    }
                }
            }
            if (!visual) {
                return false;
            }
            var wrap$$1 = new Group();
            wrap$$1.children.push(visual);
            var bbox = element.getBoundingClientRect();
            wrap$$1.transform(transform().translate(bbox.left, bbox.top));
            group.append(wrap$$1);
            return true;
        }
        function renderImage(element, url, group) {
            var box = getContentBox(element);
            var rect = new Rect([
                box.left,
                box.top
            ], [
                box.width,
                box.height
            ]);
            var image = new Image$1(url, rect);
            setClipping(image, elementRoundBox(element, box, 'content'));
            group.append(image);
        }
        function zIndexSort(a, b) {
            var sa = getComputedStyle(a);
            var sb = getComputedStyle(b);
            var za = parseFloat(getPropertyValue(sa, 'z-index'));
            var zb = parseFloat(getPropertyValue(sb, 'z-index'));
            var pa = getPropertyValue(sa, 'position');
            var pb = getPropertyValue(sb, 'position');
            if (isNaN(za) && isNaN(zb)) {
                if (/static|absolute/.test(pa) && /static|absolute/.test(pb)) {
                    return 0;
                }
                if (pa == 'static') {
                    return -1;
                }
                if (pb == 'static') {
                    return 1;
                }
                return 0;
            }
            if (isNaN(za)) {
                return zb === 0 ? 0 : zb > 0 ? -1 : 1;
            }
            if (isNaN(zb)) {
                return za === 0 ? 0 : za > 0 ? 1 : -1;
            }
            return parseFloat(za) - parseFloat(zb);
        }
        function isFormField(element) {
            return /^(?:textarea|select|input)$/i.test(element.tagName);
        }
        function getSelectedOption(element) {
            if (element.selectedOptions && element.selectedOptions.length > 0) {
                return element.selectedOptions[0];
            }
            return element.options[element.selectedIndex];
        }
        function renderCheckbox(element, group) {
            var style = getComputedStyle(element);
            var color = getPropertyValue(style, 'color');
            var box = element.getBoundingClientRect();
            if (element.type == 'checkbox') {
                group.append(Path.fromRect(new Rect([
                    box.left + 1,
                    box.top + 1
                ], [
                    box.width - 2,
                    box.height - 2
                ])).stroke(color, 1));
                if (element.checked) {
                    group.append(new Path().stroke(color, 1.2).moveTo(box.left + 0.22 * box.width, box.top + 0.55 * box.height).lineTo(box.left + 0.45 * box.width, box.top + 0.75 * box.height).lineTo(box.left + 0.78 * box.width, box.top + 0.22 * box.width));
                }
            } else {
                group.append(new Circle(new Circle$2([
                    (box.left + box.right) / 2,
                    (box.top + box.bottom) / 2
                ], Math.min(box.width - 2, box.height - 2) / 2)).stroke(color, 1));
                if (element.checked) {
                    group.append(new Circle(new Circle$2([
                        (box.left + box.right) / 2,
                        (box.top + box.bottom) / 2
                    ], Math.min(box.width - 8, box.height - 8) / 2)).fill(color).stroke(null));
                }
            }
        }
        function renderFormField(element, group) {
            var tag = element.tagName.toLowerCase();
            if (tag == 'input' && (element.type == 'checkbox' || element.type == 'radio')) {
                return renderCheckbox(element, group);
            }
            var p = element.parentNode;
            var doc = element.ownerDocument;
            var el = doc.createElement(KENDO_PSEUDO_ELEMENT);
            var option;
            el.style.cssText = getCssText(getComputedStyle(element));
            if (tag == 'input') {
                el.style.whiteSpace = 'pre';
            }
            if (tag == 'select' || tag == 'textarea') {
                el.style.overflow = 'auto';
            }
            if (tag == 'select') {
                if (element.multiple) {
                    for (var i = 0; i < element.options.length; ++i) {
                        option = doc.createElement(KENDO_PSEUDO_ELEMENT);
                        option.style.cssText = getCssText(getComputedStyle(element.options[i]));
                        option.style.display = 'block';
                        option.textContent = element.options[i].textContent;
                        el.appendChild(option);
                    }
                } else {
                    option = getSelectedOption(element);
                    if (option) {
                        el.textContent = option.textContent;
                    }
                }
            } else {
                el.textContent = element.value;
            }
            p.insertBefore(el, element);
            el.scrollLeft = element.scrollLeft;
            el.scrollTop = element.scrollTop;
            element.style.display = 'none';
            renderContents(el, group);
            element.style.display = '';
            p.removeChild(el);
        }
        function renderContents(element, group) {
            if (nodeInfo._stackingContext.element === element) {
                nodeInfo._stackingContext.group = group;
            }
            switch (element.tagName.toLowerCase()) {
            case 'img':
                renderImage(element, element.src, group);
                break;
            case 'canvas':
                try {
                    renderImage(element, element.toDataURL('image/png'), group);
                } catch (ex) {
                }
                break;
            case 'textarea':
            case 'input':
            case 'select':
                renderFormField(element, group);
                break;
            default:
                var children = [], floats = [], positioned = [];
                for (var i = element.firstChild; i; i = i.nextSibling) {
                    switch (i.nodeType) {
                    case 3:
                        if (/\S/.test(i.data)) {
                            renderText(element, i, group);
                        }
                        break;
                    case 1:
                        var style = getComputedStyle(i);
                        var floating = getPropertyValue(style, 'float');
                        var position = getPropertyValue(style, 'position');
                        if (position != 'static') {
                            positioned.push(i);
                        } else if (floating != 'none') {
                            floats.push(i);
                        } else {
                            children.push(i);
                        }
                        break;
                    }
                }
                mergeSort(children, zIndexSort).forEach(function (el) {
                    renderElement(el, group);
                });
                mergeSort(floats, zIndexSort).forEach(function (el) {
                    renderElement(el, group);
                });
                mergeSort(positioned, zIndexSort).forEach(function (el) {
                    renderElement(el, group);
                });
            }
        }
        function renderText(element, node, group) {
            if (emptyClipbox()) {
                return;
            }
            var style = getComputedStyle(element);
            if (parseFloat(getPropertyValue(style, 'text-indent')) < -500) {
                return;
            }
            var text = node.data;
            var start = 0;
            var end = text.search(/\S\s*$/) + 1;
            if (!end) {
                return;
            }
            var fontSize = getPropertyValue(style, 'font-size');
            var lineHeight = getPropertyValue(style, 'line-height');
            var font = [
                getPropertyValue(style, 'font-style'),
                getPropertyValue(style, 'font-variant'),
                getPropertyValue(style, 'font-weight'),
                fontSize,
                getPropertyValue(style, 'font-family')
            ].join(' ');
            fontSize = parseFloat(fontSize);
            lineHeight = parseFloat(lineHeight);
            if (fontSize === 0) {
                return;
            }
            var color = getPropertyValue(style, 'color');
            var range = element.ownerDocument.createRange();
            var align$$1 = getPropertyValue(style, 'text-align');
            var isJustified = align$$1 == 'justify';
            var columnCount = getPropertyValue(style, 'column-count', 1);
            var whiteSpace = getPropertyValue(style, 'white-space');
            var textTransform = getPropertyValue(style, 'text-transform');
            var estimateLineLength = element.getBoundingClientRect().width / fontSize * 5;
            if (estimateLineLength === 0) {
                estimateLineLength = 500;
            }
            var prevLineBottom = null;
            var underline = nodeInfo['underline'];
            var lineThrough = nodeInfo['line-through'];
            var overline = nodeInfo['overline'];
            var hasDecoration = underline || lineThrough || overline;
            while (!doChunk()) {
            }
            if (hasDecoration) {
                range.selectNode(node);
                slice$1(range.getClientRects()).forEach(decorate);
            }
            return;
            function actuallyGetRangeBoundingRect(range) {
                if (microsoft || browser.chrome) {
                    var rectangles = range.getClientRects(), box = {
                            top: Infinity,
                            right: -Infinity,
                            bottom: -Infinity,
                            left: Infinity
                        }, done = false;
                    for (var i = 0; i < rectangles.length; ++i) {
                        var b = rectangles[i];
                        if (b.width <= 1 || b.bottom === prevLineBottom) {
                            continue;
                        }
                        box.left = Math.min(b.left, box.left);
                        box.top = Math.min(b.top, box.top);
                        box.right = Math.max(b.right, box.right);
                        box.bottom = Math.max(b.bottom, box.bottom);
                        done = true;
                    }
                    if (!done) {
                        return range.getBoundingClientRect();
                    }
                    box.width = box.right - box.left;
                    box.height = box.bottom - box.top;
                    return box;
                }
                return range.getBoundingClientRect();
            }
            function doChunk() {
                var origStart = start;
                var box, pos = text.substr(start).search(/\S/);
                start += pos;
                if (pos < 0 || start >= end) {
                    return true;
                }
                range.setStart(node, start);
                range.setEnd(node, start + 1);
                box = actuallyGetRangeBoundingRect(range);
                var found = false;
                if (isJustified || columnCount > 1) {
                    pos = text.substr(start).search(/\s/);
                    if (pos >= 0) {
                        range.setEnd(node, start + pos);
                        var r = actuallyGetRangeBoundingRect(range);
                        if (r.bottom == box.bottom) {
                            box = r;
                            found = true;
                            start += pos;
                        }
                    }
                }
                if (!found) {
                    pos = function findEOL(min, eol, max) {
                        range.setEnd(node, eol);
                        var r = actuallyGetRangeBoundingRect(range);
                        if (r.bottom != box.bottom && min < eol) {
                            return findEOL(min, min + eol >> 1, eol);
                        } else if (r.right != box.right) {
                            box = r;
                            if (eol < max) {
                                return findEOL(eol, eol + max >> 1, max);
                            } else {
                                return eol;
                            }
                        } else {
                            return eol;
                        }
                    }(start, Math.min(end, start + estimateLineLength), end);
                    if (pos == start) {
                        return true;
                    }
                    start = pos;
                    pos = range.toString().search(/\s+$/);
                    if (pos === 0) {
                        return false;
                    }
                    if (pos > 0) {
                        range.setEnd(node, range.startOffset + pos);
                        box = actuallyGetRangeBoundingRect(range);
                    }
                }
                if (microsoft) {
                    box = range.getClientRects()[0];
                }
                var str = range.toString();
                if (!/^(?:pre|pre-wrap)$/i.test(whiteSpace)) {
                    str = str.replace(/\s+/g, ' ');
                } else if (/\t/.test(str)) {
                    var cc = 0;
                    for (pos = origStart; pos < range.startOffset; ++pos) {
                        var code = text.charCodeAt(pos);
                        if (code == 9) {
                            cc += 8 - cc % 8;
                        } else if (code == 10 || code == 13) {
                            cc = 0;
                        } else {
                            cc++;
                        }
                    }
                    while ((pos = str.search('\t')) >= 0) {
                        var indent = '        '.substr(0, 8 - (cc + pos) % 8);
                        str = str.substr(0, pos) + indent + str.substr(pos + 1);
                    }
                }
                if (!found) {
                    prevLineBottom = box.bottom;
                }
                drawText(str, box);
            }
            function drawText(str, box) {
                if (microsoft && !isNaN(lineHeight)) {
                    var height = getFontHeight(font);
                    var top = (box.top + box.bottom - height) / 2;
                    box = {
                        top: top,
                        right: box.right,
                        bottom: top + height,
                        left: box.left,
                        height: height,
                        width: box.right - box.left
                    };
                }
                switch (textTransform) {
                case 'uppercase':
                    str = str.toUpperCase();
                    break;
                case 'lowercase':
                    str = str.toLowerCase();
                    break;
                case 'capitalize':
                    str = str.replace(/(?:^|\s)\S/g, function (l) {
                        return l.toUpperCase();
                    });
                    break;
                }
                var text = new TextRect(str, new Rect([
                    box.left,
                    box.top
                ], [
                    box.width,
                    box.height
                ]), {
                    font: font,
                    fill: { color: color }
                });
                group.append(text);
            }
            function decorate(box) {
                line(underline, box.bottom);
                line(lineThrough, box.bottom - box.height / 2.7);
                line(overline, box.top);
                function line(color, ypos) {
                    if (color) {
                        var width = fontSize / 12;
                        var path = new Path({
                            stroke: {
                                width: width,
                                color: color
                            }
                        });
                        ypos -= width;
                        path.moveTo(box.left, ypos).lineTo(box.right, ypos);
                        group.append(path);
                    }
                }
            }
        }
        function groupInStackingContext(element, group, zIndex) {
            var main;
            if (zIndex != 'auto') {
                main = nodeInfo._stackingContext.group;
                zIndex = parseFloat(zIndex);
            } else {
                main = group;
                zIndex = 0;
            }
            var a = main.children;
            for (var i = 0; i < a.length; ++i) {
                if (a[i]._dom_zIndex != null && a[i]._dom_zIndex > zIndex) {
                    break;
                }
            }
            var tmp = new Group();
            main.insert(i, tmp);
            tmp._dom_zIndex = zIndex;
            if (main !== group) {
                if (nodeInfo._clipbox) {
                    var m = nodeInfo._matrix.invert();
                    var r = nodeInfo._clipbox.transformCopy(m);
                    setClipping(tmp, Path.fromRect(r));
                }
            }
            return tmp;
        }
        function renderElement(element, container) {
            var style = getComputedStyle(element);
            updateCounters(style);
            if (/^(style|script|link|meta|iframe|svg|col|colgroup)$/i.test(element.tagName)) {
                return;
            }
            if (nodeInfo._clipbox == null) {
                return;
            }
            var opacity = parseFloat(getPropertyValue(style, 'opacity'));
            var visibility = getPropertyValue(style, 'visibility');
            var display = getPropertyValue(style, 'display');
            if (opacity === 0 || visibility == 'hidden' || display == 'none') {
                return;
            }
            var tr = getTransform(style);
            var group;
            var zIndex = getPropertyValue(style, 'z-index');
            if ((tr || opacity < 1) && zIndex == 'auto') {
                zIndex = 0;
            }
            group = groupInStackingContext(element, container, zIndex);
            if (opacity < 1) {
                group.opacity(opacity * group.opacity());
            }
            pushNodeInfo(element, style, group);
            if (!tr) {
                _renderWithPseudoElements(element, group);
            } else {
                saveStyle(element, function () {
                    pleaseSetPropertyValue(element.style, 'transform', 'none', 'important');
                    pleaseSetPropertyValue(element.style, 'transition', 'none', 'important');
                    if (getPropertyValue(style, 'position') == 'static') {
                        pleaseSetPropertyValue(element.style, 'position', 'relative', 'important');
                    }
                    var bbox = element.getBoundingClientRect();
                    var x = bbox.left + tr.origin[0];
                    var y = bbox.top + tr.origin[1];
                    var m = [
                        1,
                        0,
                        0,
                        1,
                        -x,
                        -y
                    ];
                    m = mmul(m, tr.matrix);
                    m = mmul(m, [
                        1,
                        0,
                        0,
                        1,
                        x,
                        y
                    ]);
                    m = setTransform(group, m);
                    nodeInfo._matrix = nodeInfo._matrix.multiplyCopy(m);
                    _renderWithPseudoElements(element, group);
                });
            }
            popNodeInfo();
        }
        function mmul(a, b) {
            var a1 = a[0], b1 = a[1], c1 = a[2], d1 = a[3], e1 = a[4], f1 = a[5];
            var a2 = b[0], b2 = b[1], c2 = b[2], d2 = b[3], e2 = b[4], f2 = b[5];
            return [
                a1 * a2 + b1 * c2,
                a1 * b2 + b1 * d2,
                c1 * a2 + d1 * c2,
                c1 * b2 + d1 * d2,
                e1 * a2 + f1 * c2 + e2,
                e1 * b2 + f1 * d2 + f2
            ];
        }
        var drawing = {
            svg: svg,
            canvas: canvas,
            util: util,
            PathParser: PathParser,
            Surface: Surface,
            BaseNode: BaseNode,
            SurfaceFactory: SurfaceFactory,
            OptionsStore: OptionsStore,
            exportImage: exportImage,
            exportSVG: exportSVG,
            QuadNode: QuadNode,
            ShapesQuadTree: ShapesQuadTree,
            ObserversMixin: ObserversMixin,
            Element: Element$1,
            Circle: Circle,
            Arc: Arc,
            Path: Path,
            MultiPath: MultiPath,
            Text: Text,
            Image: Image$1,
            Group: Group,
            Layout: Layout,
            Rect: Rect$2,
            align: align,
            vAlign: vAlign,
            stack: stack,
            vStack: vStack,
            wrap: wrap,
            vWrap: vWrap,
            fit: fit,
            LinearGradient: LinearGradient,
            RadialGradient: RadialGradient,
            GradientStop: GradientStop,
            Gradient: Gradient,
            Animation: Animation,
            AnimationFactory: AnimationFactory,
            drawDOM: drawDOM
        };
        kendo.deepExtend(kendo, {
            drawing: drawing,
            geometry: geometry
        });
        kendo.drawing.Segment = kendo.geometry.Segment;
        kendo.dataviz.drawing = kendo.drawing;
        kendo.dataviz.geometry = kendo.geometry;
        kendo.drawing.util.measureText = kendo.util.measureText;
        kendo.drawing.util.objectKey = kendo.util.objectKey;
        kendo.drawing.Color = kendo.Color;
        kendo.util.encodeBase64 = kendo.drawing.util.encodeBase64;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.popup', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'popup',
        name: 'Pop-up',
        category: 'framework',
        depends: ['core'],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, Class = kendo.Class, support = kendo.support, getOffset = kendo.getOffset, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, OPEN = 'open', CLOSE = 'close', DEACTIVATE = 'deactivate', ACTIVATE = 'activate', CENTER = 'center', LEFT = 'left', RIGHT = 'right', TOP = 'top', BOTTOM = 'bottom', ABSOLUTE = 'absolute', HIDDEN = 'hidden', BODY = 'body', LOCATION = 'location', POSITION = 'position', VISIBLE = 'visible', EFFECTS = 'effects', ACTIVE = 'k-state-active', ACTIVEBORDER = 'k-state-border', ACTIVEBORDERREGEXP = /k-state-border-(\w+)/, ACTIVECHILDREN = '.k-picker-wrap, .k-dropdown-wrap, .k-link', MOUSEDOWN = 'down', DOCUMENT_ELEMENT = $(document.documentElement), proxy = $.proxy, WINDOW = $(window), SCROLL = 'scroll', cssPrefix = support.transitions.css, TRANSFORM = cssPrefix + 'transform', extend = $.extend, NS = '.kendoPopup', styles = [
                'font-size',
                'font-family',
                'font-stretch',
                'font-style',
                'font-weight',
                'line-height'
            ];
        function contains(container, target) {
            if (!container || !target) {
                return false;
            }
            return container === target || $.contains(container, target);
        }
        var Popup = Widget.extend({
            init: function (element, options) {
                var that = this, parentPopup;
                options = options || {};
                if (options.isRtl) {
                    options.origin = options.origin || BOTTOM + ' ' + RIGHT;
                    options.position = options.position || TOP + ' ' + RIGHT;
                }
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                that.collisions = options.collision ? options.collision.split(' ') : [];
                that.downEvent = kendo.applyEventMap(MOUSEDOWN, kendo.guid());
                if (that.collisions.length === 1) {
                    that.collisions.push(that.collisions[0]);
                }
                parentPopup = $(that.options.anchor).closest('.k-popup,.k-group').filter(':not([class^=km-])');
                options.appendTo = $($(options.appendTo)[0] || parentPopup[0] || document.body);
                that.element.hide().addClass('k-popup k-group k-reset').toggleClass('k-rtl', !!options.isRtl).css({ position: ABSOLUTE }).appendTo(options.appendTo).attr('aria-hidden', true).on('mouseenter' + NS, function () {
                    that._hovered = true;
                }).on('wheel' + NS, function (e) {
                    var list = $(e.target).find('.k-list');
                    var scrollArea = list.parent();
                    if (list.length && list.is(':visible') && (scrollArea.scrollTop() === 0 && e.originalEvent.deltaY < 0 || scrollArea.scrollTop() === scrollArea.prop('scrollHeight') - scrollArea.prop('offsetHeight') && e.originalEvent.deltaY > 0)) {
                        e.preventDefault();
                    }
                }).on('mouseleave' + NS, function () {
                    that._hovered = false;
                });
                that.wrapper = $();
                if (options.animation === false) {
                    options.animation = {
                        open: { effects: {} },
                        close: {
                            hide: true,
                            effects: {}
                        }
                    };
                }
                extend(options.animation.open, {
                    complete: function () {
                        that.wrapper.css({ overflow: VISIBLE });
                        that._activated = true;
                        that._trigger(ACTIVATE);
                    }
                });
                extend(options.animation.close, {
                    complete: function () {
                        that._animationClose();
                    }
                });
                that._mousedownProxy = function (e) {
                    that._mousedown(e);
                };
                if (support.mobileOS.android) {
                    that._resizeProxy = function (e) {
                        setTimeout(function () {
                            that._resize(e);
                        }, 600);
                    };
                } else {
                    that._resizeProxy = function (e) {
                        that._resize(e);
                    };
                }
                if (options.toggleTarget) {
                    $(options.toggleTarget).on(options.toggleEvent + NS, $.proxy(that.toggle, that));
                }
            },
            events: [
                OPEN,
                ACTIVATE,
                CLOSE,
                DEACTIVATE
            ],
            options: {
                name: 'Popup',
                toggleEvent: 'click',
                origin: BOTTOM + ' ' + LEFT,
                position: TOP + ' ' + LEFT,
                anchor: BODY,
                appendTo: null,
                collision: 'flip fit',
                viewport: window,
                copyAnchorStyles: true,
                autosize: false,
                modal: false,
                adjustSize: {
                    width: 0,
                    height: 0
                },
                animation: {
                    open: {
                        effects: 'slideIn:down',
                        transition: true,
                        duration: 200
                    },
                    close: {
                        duration: 100,
                        hide: true
                    }
                }
            },
            _animationClose: function () {
                var that = this;
                var location = that.wrapper.data(LOCATION);
                that.wrapper.hide();
                if (location) {
                    that.wrapper.css(location);
                }
                if (that.options.anchor != BODY) {
                    that._hideDirClass();
                }
                that._closing = false;
                that._trigger(DEACTIVATE);
            },
            destroy: function () {
                var that = this, options = that.options, element = that.element.off(NS), parent;
                Widget.fn.destroy.call(that);
                if (options.toggleTarget) {
                    $(options.toggleTarget).off(NS);
                }
                if (!options.modal) {
                    DOCUMENT_ELEMENT.off(that.downEvent, that._mousedownProxy);
                    that._toggleResize(false);
                }
                kendo.destroy(that.element.children());
                element.removeData();
                if (options.appendTo[0] === document.body) {
                    parent = element.parent('.k-animation-container');
                    if (parent[0]) {
                        parent.remove();
                    } else {
                        element.remove();
                    }
                }
            },
            open: function (x, y) {
                var that = this, fixed = {
                        isFixed: !isNaN(parseInt(y, 10)),
                        x: x,
                        y: y
                    }, element = that.element, options = that.options, animation, wrapper, anchor = $(options.anchor), mobile = element[0] && element.hasClass('km-widget');
                if (!that.visible()) {
                    if (options.copyAnchorStyles) {
                        if (mobile && styles[0] == 'font-size') {
                            styles.shift();
                        }
                        element.css(kendo.getComputedStyles(anchor[0], styles));
                    }
                    if (element.data('animating') || that._trigger(OPEN)) {
                        return;
                    }
                    that._activated = false;
                    if (!options.modal) {
                        DOCUMENT_ELEMENT.off(that.downEvent, that._mousedownProxy).on(that.downEvent, that._mousedownProxy);
                        that._toggleResize(false);
                        that._toggleResize(true);
                    }
                    that.wrapper = wrapper = kendo.wrap(element, options.autosize).css({
                        overflow: HIDDEN,
                        display: 'block',
                        position: ABSOLUTE
                    }).attr('aria-hidden', false);
                    if (support.mobileOS.android) {
                        wrapper.css(TRANSFORM, 'translatez(0)');
                    }
                    wrapper.css(POSITION);
                    if ($(options.appendTo)[0] == document.body) {
                        wrapper.css(TOP, '-10000px');
                    }
                    that.flipped = that._position(fixed);
                    animation = that._openAnimation();
                    if (options.anchor != BODY) {
                        that._showDirClass(animation);
                    }
                    element.data(EFFECTS, animation.effects).kendoStop(true).kendoAnimate(animation).attr('aria-hidden', false);
                }
            },
            _location: function (isFixed) {
                var that = this, element = that.element, options = that.options, wrapper, anchor = $(options.anchor), mobile = element[0] && element.hasClass('km-widget');
                if (options.copyAnchorStyles) {
                    if (mobile && styles[0] == 'font-size') {
                        styles.shift();
                    }
                    element.css(kendo.getComputedStyles(anchor[0], styles));
                }
                that.wrapper = wrapper = kendo.wrap(element, options.autosize).css({
                    overflow: HIDDEN,
                    display: 'block',
                    position: ABSOLUTE
                });
                if (support.mobileOS.android) {
                    wrapper.css(TRANSFORM, 'translatez(0)');
                }
                wrapper.css(POSITION);
                if ($(options.appendTo)[0] == document.body) {
                    wrapper.css(TOP, '-10000px');
                }
                that._position(isFixed || {});
                var offset = wrapper.offset();
                return {
                    width: kendo._outerWidth(wrapper),
                    height: kendo._outerHeight(wrapper),
                    left: offset.left,
                    top: offset.top
                };
            },
            _openAnimation: function () {
                var animation = extend(true, {}, this.options.animation.open);
                animation.effects = kendo.parseEffects(animation.effects, this.flipped);
                return animation;
            },
            _hideDirClass: function () {
                var anchor = $(this.options.anchor);
                var direction = ((anchor.attr('class') || '').match(ACTIVEBORDERREGEXP) || [
                    '',
                    'down'
                ])[1];
                var dirClass = ACTIVEBORDER + '-' + direction;
                anchor.removeClass(dirClass).children(ACTIVECHILDREN).removeClass(ACTIVE).removeClass(dirClass);
                this.element.removeClass(ACTIVEBORDER + '-' + kendo.directions[direction].reverse);
            },
            _showDirClass: function (animation) {
                var direction = animation.effects.slideIn ? animation.effects.slideIn.direction : 'down';
                var dirClass = ACTIVEBORDER + '-' + direction;
                $(this.options.anchor).addClass(dirClass).children(ACTIVECHILDREN).addClass(ACTIVE).addClass(dirClass);
                this.element.addClass(ACTIVEBORDER + '-' + kendo.directions[direction].reverse);
            },
            position: function () {
                if (this.visible()) {
                    this.flipped = this._position();
                }
            },
            toggle: function () {
                var that = this;
                that[that.visible() ? CLOSE : OPEN]();
            },
            visible: function () {
                return this.element.is(':' + VISIBLE);
            },
            close: function (skipEffects) {
                var that = this, options = that.options, wrap, animation, openEffects, closeEffects;
                if (that.visible()) {
                    wrap = that.wrapper[0] ? that.wrapper : kendo.wrap(that.element).hide();
                    that._toggleResize(false);
                    if (that._closing || that._trigger(CLOSE)) {
                        that._toggleResize(true);
                        return;
                    }
                    that.element.find('.k-popup').each(function () {
                        var that = $(this), popup = that.data('kendoPopup');
                        if (popup) {
                            popup.close(skipEffects);
                        }
                    });
                    DOCUMENT_ELEMENT.off(that.downEvent, that._mousedownProxy);
                    if (skipEffects) {
                        animation = {
                            hide: true,
                            effects: {}
                        };
                    } else {
                        animation = extend(true, {}, options.animation.close);
                        openEffects = that.element.data(EFFECTS);
                        closeEffects = animation.effects;
                        if (!closeEffects && !kendo.size(closeEffects) && openEffects && kendo.size(openEffects)) {
                            animation.effects = openEffects;
                            animation.reverse = true;
                        }
                        that._closing = true;
                    }
                    that.element.kendoStop(true).attr('aria-hidden', true);
                    wrap.css({ overflow: HIDDEN }).attr('aria-hidden', true);
                    that.element.kendoAnimate(animation);
                    if (skipEffects) {
                        that._animationClose();
                    }
                }
            },
            _trigger: function (ev) {
                return this.trigger(ev, { type: ev });
            },
            _resize: function (e) {
                var that = this;
                if (support.resize.indexOf(e.type) !== -1) {
                    clearTimeout(that._resizeTimeout);
                    that._resizeTimeout = setTimeout(function () {
                        that._position();
                        that._resizeTimeout = null;
                    }, 50);
                } else {
                    if (!that._hovered || that._activated && that.element.hasClass('k-list-container')) {
                        that.close();
                    }
                }
            },
            _toggleResize: function (toggle) {
                var method = toggle ? 'on' : 'off';
                var eventNames = support.resize;
                if (!(support.mobileOS.ios || support.mobileOS.android)) {
                    eventNames += ' ' + SCROLL;
                }
                if (toggle && !this.scrollableParents) {
                    this.scrollableParents = this._scrollableParents();
                }
                if (this.scrollableParents && this.scrollableParents.length) {
                    this.scrollableParents[method](SCROLL, this._resizeProxy);
                }
                WINDOW[method](eventNames, this._resizeProxy);
            },
            _mousedown: function (e) {
                var that = this, container = that.element[0], options = that.options, anchor = $(options.anchor)[0], toggleTarget = options.toggleTarget, target = kendo.eventTarget(e), popup = $(target).closest('.k-popup'), mobile = popup.parent().parent('.km-shim').length;
                popup = popup[0];
                if (!mobile && popup && popup !== that.element[0]) {
                    return;
                }
                if ($(e.target).closest('a').data('rel') === 'popover') {
                    return;
                }
                if (!contains(container, target) && !contains(anchor, target) && !(toggleTarget && contains($(toggleTarget)[0], target))) {
                    that.close();
                }
            },
            _fit: function (position, size, viewPortSize) {
                var output = 0;
                if (position + size > viewPortSize) {
                    output = viewPortSize - (position + size);
                }
                if (position < 0) {
                    output = -position;
                }
                return output;
            },
            _flip: function (offset, size, anchorSize, viewPortSize, origin, position, boxSize) {
                var output = 0;
                boxSize = boxSize || size;
                if (position !== origin && position !== CENTER && origin !== CENTER) {
                    if (offset + boxSize > viewPortSize) {
                        output += -(anchorSize + size);
                    }
                    if (offset + output < 0) {
                        output += anchorSize + size;
                    }
                }
                return output;
            },
            _scrollableParents: function () {
                return $(this.options.anchor).parentsUntil('body').filter(function (index, element) {
                    return kendo.isScrollable(element);
                });
            },
            _position: function (fixed) {
                var that = this, element = that.element, wrapper = that.wrapper, options = that.options, viewport = $(options.viewport), zoomLevel = support.zoomLevel(), isWindow = !!(viewport[0] == window && window.innerWidth && zoomLevel <= 1.02), anchor = $(options.anchor), origins = options.origin.toLowerCase().split(' '), positions = options.position.toLowerCase().split(' '), collisions = that.collisions, siblingContainer, parents, parentZIndex, zIndex = 10002, idx = 0, docEl = document.documentElement, length, viewportOffset, viewportWidth, viewportHeight;
                if (options.viewport === window) {
                    viewportOffset = {
                        top: window.pageYOffset || document.documentElement.scrollTop || 0,
                        left: window.pageXOffset || document.documentElement.scrollLeft || 0
                    };
                } else {
                    viewportOffset = viewport.offset();
                }
                if (isWindow) {
                    viewportWidth = window.innerWidth;
                    viewportHeight = window.innerHeight;
                } else {
                    viewportWidth = viewport.width();
                    viewportHeight = viewport.height();
                }
                if (isWindow && docEl.scrollHeight - docEl.clientHeight > 0) {
                    var sign = options.isRtl ? -1 : 1;
                    viewportWidth -= sign * kendo.support.scrollbar();
                }
                siblingContainer = anchor.parents().filter(wrapper.siblings());
                if (siblingContainer[0]) {
                    parentZIndex = Math.max(Number(siblingContainer.css('zIndex')), 0);
                    if (parentZIndex) {
                        zIndex = parentZIndex + 10;
                    } else {
                        parents = anchor.parentsUntil(siblingContainer);
                        for (length = parents.length; idx < length; idx++) {
                            parentZIndex = Number($(parents[idx]).css('zIndex'));
                            if (parentZIndex && zIndex < parentZIndex) {
                                zIndex = parentZIndex + 10;
                            }
                        }
                    }
                }
                wrapper.css('zIndex', zIndex);
                if (fixed && fixed.isFixed) {
                    wrapper.css({
                        left: fixed.x,
                        top: fixed.y
                    });
                } else {
                    wrapper.css(that._align(origins, positions));
                }
                var pos = getOffset(wrapper, POSITION, anchor[0] === wrapper.offsetParent()[0]), offset = getOffset(wrapper), anchorParent = anchor.offsetParent().parent('.k-animation-container,.k-popup,.k-group');
                if (anchorParent.length) {
                    pos = getOffset(wrapper, POSITION, true);
                    offset = getOffset(wrapper);
                }
                offset.top -= viewportOffset.top;
                offset.left -= viewportOffset.left;
                if (!that.wrapper.data(LOCATION)) {
                    wrapper.data(LOCATION, extend({}, pos));
                }
                var offsets = extend({}, offset), location = extend({}, pos), adjustSize = options.adjustSize;
                if (collisions[0] === 'fit') {
                    location.top += that._fit(offsets.top, outerHeight(wrapper) + adjustSize.height, viewportHeight / zoomLevel);
                }
                if (collisions[1] === 'fit') {
                    location.left += that._fit(offsets.left, outerWidth(wrapper) + adjustSize.width, viewportWidth / zoomLevel);
                }
                var flipPos = extend({}, location);
                var elementHeight = outerHeight(element);
                var wrapperHeight = outerHeight(wrapper);
                if (!wrapper.height() && elementHeight) {
                    wrapperHeight = wrapperHeight + elementHeight;
                }
                if (collisions[0] === 'flip') {
                    location.top += that._flip(offsets.top, elementHeight, outerHeight(anchor), viewportHeight / zoomLevel, origins[0], positions[0], wrapperHeight);
                }
                if (collisions[1] === 'flip') {
                    location.left += that._flip(offsets.left, outerWidth(element), outerWidth(anchor), viewportWidth / zoomLevel, origins[1], positions[1], outerWidth(wrapper));
                }
                element.css(POSITION, ABSOLUTE);
                wrapper.css(location);
                return location.left != flipPos.left || location.top != flipPos.top;
            },
            _align: function (origin, position) {
                var that = this, element = that.wrapper, anchor = $(that.options.anchor), verticalOrigin = origin[0], horizontalOrigin = origin[1], verticalPosition = position[0], horizontalPosition = position[1], anchorOffset = getOffset(anchor), appendTo = $(that.options.appendTo), appendToOffset, width = outerWidth(element), height = outerHeight(element) || outerHeight(element.children().first()), anchorWidth = outerWidth(anchor), anchorHeight = outerHeight(anchor), top = anchorOffset.top, left = anchorOffset.left, round = Math.round;
                if (appendTo[0] != document.body) {
                    appendToOffset = getOffset(appendTo);
                    top -= appendToOffset.top;
                    left -= appendToOffset.left;
                }
                if (verticalOrigin === BOTTOM) {
                    top += anchorHeight;
                }
                if (verticalOrigin === CENTER) {
                    top += round(anchorHeight / 2);
                }
                if (verticalPosition === BOTTOM) {
                    top -= height;
                }
                if (verticalPosition === CENTER) {
                    top -= round(height / 2);
                }
                if (horizontalOrigin === RIGHT) {
                    left += anchorWidth;
                }
                if (horizontalOrigin === CENTER) {
                    left += round(anchorWidth / 2);
                }
                if (horizontalPosition === RIGHT) {
                    left -= width;
                }
                if (horizontalPosition === CENTER) {
                    left -= round(width / 2);
                }
                return {
                    top: top,
                    left: left
                };
            }
        });
        ui.plugin(Popup);
        var stableSort = kendo.support.stableSort;
        var tabKeyTrapNS = 'kendoTabKeyTrap';
        var focusableNodesSelector = 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex], *[contenteditable]';
        var TabKeyTrap = Class.extend({
            init: function (element) {
                this.element = $(element);
                this.element.autoApplyNS(tabKeyTrapNS);
            },
            trap: function () {
                this.element.on('keydown', proxy(this._keepInTrap, this));
            },
            removeTrap: function () {
                this.element.kendoDestroy(tabKeyTrapNS);
            },
            destroy: function () {
                this.element.kendoDestroy(tabKeyTrapNS);
                this.element = undefined;
            },
            shouldTrap: function () {
                return true;
            },
            _keepInTrap: function (e) {
                if (e.which !== 9 || !this.shouldTrap() || e.isDefaultPrevented()) {
                    return;
                }
                var elements = this._focusableElements();
                var sortedElements = this._sortFocusableElements(elements);
                var next = this._nextFocusable(e, sortedElements);
                this._focus(next);
                e.preventDefault();
            },
            _focusableElements: function () {
                var elements = this.element.find(focusableNodesSelector).filter(function (i, item) {
                    return item.tabIndex >= 0 && $(item).is(':visible') && !$(item).is('[disabled]');
                });
                if (this.element.is('[tabindex]')) {
                    elements.push(this.element[0]);
                }
                return elements;
            },
            _sortFocusableElements: function (elements) {
                var sortedElements;
                if (stableSort) {
                    sortedElements = elements.sort(function (prev, next) {
                        return prev.tabIndex - next.tabIndex;
                    });
                } else {
                    var attrName = '__k_index';
                    elements.each(function (i, item) {
                        item.setAttribute(attrName, i);
                    });
                    sortedElements = elements.sort(function (prev, next) {
                        return prev.tabIndex === next.tabIndex ? parseInt(prev.getAttribute(attrName), 10) - parseInt(next.getAttribute(attrName), 10) : prev.tabIndex - next.tabIndex;
                    });
                    elements.removeAttr(attrName);
                }
                return sortedElements;
            },
            _nextFocusable: function (e, elements) {
                var count = elements.length;
                var current = elements.index(e.target);
                return elements.get((current + (e.shiftKey ? -1 : 1)) % count);
            },
            _focus: function (element) {
                if (element.nodeName == 'IFRAME') {
                    element.contentWindow.document.body.focus();
                    return;
                }
                element.focus();
                if (element.nodeName == 'INPUT' && element.setSelectionRange && this._haveSelectionRange(element)) {
                    element.setSelectionRange(0, element.value.length);
                }
            },
            _haveSelectionRange: function (element) {
                var elementType = element.type.toLowerCase();
                return elementType === 'text' || elementType === 'search' || elementType === 'url' || elementType === 'tel' || elementType === 'password';
            }
        });
        ui.Popup.TabKeyTrap = TabKeyTrap;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/surface-tooltip', [
        'kendo.popup',
        'drawing/kendo-drawing'
    ], f);
}(function () {
    (function ($) {
        var NS = '.kendo';
        var kendo = window.kendo;
        var deepExtend = kendo.deepExtend;
        var utils = kendo.drawing.util;
        var defined = utils.defined;
        var limitValue = utils.limitValue;
        var eventCoordinates = utils.eventCoordinates;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var proxy = $.proxy;
        var TOOLTIP_TEMPLATE = '<div class="k-tooltip">' + '<div class="k-tooltip-content"></div>' + '</div>';
        var TOOLTIP_CLOSE_TEMPLATE = '<div class="k-tooltip-button"><a href="\\#" class="k-icon k-i-close">close</a></div>';
        var SurfaceTooltip = kendo.Class.extend({
            init: function (surface, options) {
                this.element = $(TOOLTIP_TEMPLATE);
                this.content = this.element.children('.k-tooltip-content');
                options = options || {};
                this.options = deepExtend({}, this.options, this._tooltipOptions(options));
                this.popupOptions = {
                    appendTo: options.appendTo,
                    animation: options.animation,
                    copyAnchorStyles: false,
                    collision: 'fit fit'
                };
                this._openPopupHandler = $.proxy(this._openPopup, this);
                this.surface = surface;
                this._bindEvents();
            },
            options: {
                position: 'top',
                showOn: 'mouseenter',
                offset: 7,
                autoHide: true,
                hideDelay: 0,
                showAfter: 100
            },
            _bindEvents: function () {
                this._showHandler = proxy(this._showEvent, this);
                this._surfaceLeaveHandler = proxy(this._surfaceLeave, this);
                this._mouseleaveHandler = proxy(this._mouseleave, this);
                this._mousemoveHandler = proxy(this._mousemove, this);
                this.surface.bind('click', this._showHandler);
                this.surface.bind('mouseenter', this._showHandler);
                this.surface.bind('mouseleave', this._mouseleaveHandler);
                this.surface.bind('mousemove', this._mousemoveHandler);
                this.surface.element.on('mouseleave' + NS, this._surfaceLeaveHandler);
                this.element.on('click' + NS, '.k-tooltip-button', proxy(this._hideClick, this));
                this.element.on('mouseleave' + NS, proxy(this._tooltipLeave, this));
            },
            getPopup: function () {
                if (!this.popup) {
                    this.popup = new kendo.ui.Popup(this.element, this.popupOptions);
                }
                return this.popup;
            },
            destroy: function () {
                var popup = this.popup;
                this.surface.unbind('click', this._showHandler);
                this.surface.unbind('mouseenter', this._showHandler);
                this.surface.unbind('mouseleave', this._mouseleaveHandler);
                this.surface.unbind('mousemove', this._mousemoveHandler);
                this.surface.element.off('mouseleave' + NS, this._surfaceLeaveHandler);
                this.element.off('click' + NS);
                this.element.off('mouseleave' + NS);
                if (popup) {
                    popup.destroy();
                    delete this.popup;
                }
                delete this.popupOptions;
                clearTimeout(this._timeout);
                delete this.element;
                delete this.content;
                delete this.surface;
            },
            _tooltipOptions: function (options) {
                options = options || {};
                return {
                    position: options.position,
                    showOn: options.showOn,
                    offset: options.offset,
                    autoHide: options.autoHide,
                    width: options.width,
                    height: options.height,
                    content: options.content,
                    shared: options.shared,
                    hideDelay: options.hideDelay,
                    showAfter: options.showAfter
                };
            },
            _tooltipShape: function (shape) {
                while (shape && !shape.options.tooltip) {
                    shape = shape.parent;
                }
                return shape;
            },
            _updateContent: function (target, shape, options) {
                var content = options.content;
                if (kendo.isFunction(content)) {
                    content = content({
                        element: shape,
                        target: target
                    });
                }
                if (content) {
                    this.content.html(content);
                    return true;
                }
            },
            _position: function (shape, options, elementSize, event) {
                var position = options.position;
                var tooltipOffset = options.offset || 0;
                var surface = this.surface;
                var offset = surface._instance._elementOffset();
                var size = surface.getSize();
                var surfaceOffset = surface._instance._offset;
                var bbox = shape.bbox();
                var width = elementSize.width;
                var height = elementSize.height;
                var left = 0, top = 0;
                bbox.origin.translate(offset.left, offset.top);
                if (surfaceOffset) {
                    bbox.origin.translate(-surfaceOffset.x, -surfaceOffset.y);
                }
                if (position == 'cursor' && event) {
                    var coord = eventCoordinates(event);
                    left = coord.x - width / 2;
                    top = coord.y - height - tooltipOffset;
                } else if (position == 'left') {
                    left = bbox.origin.x - width - tooltipOffset;
                    top = bbox.center().y - height / 2;
                } else if (position == 'right') {
                    left = bbox.bottomRight().x + tooltipOffset;
                    top = bbox.center().y - height / 2;
                } else if (position == 'bottom') {
                    left = bbox.center().x - width / 2;
                    top = bbox.bottomRight().y + tooltipOffset;
                } else {
                    left = bbox.center().x - width / 2;
                    top = bbox.origin.y - height - tooltipOffset;
                }
                return {
                    left: limitValue(left, offset.left, offset.left + size.width),
                    top: limitValue(top, offset.top, offset.top + size.height)
                };
            },
            show: function (shape, options) {
                this._show(shape, shape, deepExtend({}, this.options, this._tooltipOptions(shape.options.tooltip), options));
            },
            hide: function () {
                var popup = this.popup;
                var current = this._current;
                delete this._current;
                clearTimeout(this._showTimeout);
                if (popup && popup.visible() && current && !this.surface.trigger('tooltipClose', {
                        element: current.shape,
                        target: current.target,
                        popup: popup
                    })) {
                    popup.close();
                }
            },
            _hideClick: function (e) {
                e.preventDefault();
                this.hide();
            },
            _show: function (target, shape, options, event, delay) {
                var current = this._current;
                clearTimeout(this._timeout);
                if (current && (current.shape === shape && options.shared || current.target === target)) {
                    return;
                }
                clearTimeout(this._showTimeout);
                var popup = this.getPopup();
                if (!this.surface.trigger('tooltipOpen', {
                        element: shape,
                        target: target,
                        popup: popup
                    }) && this._updateContent(target, shape, options)) {
                    this._autoHide(options);
                    var elementSize = this._measure(options);
                    if (popup.visible()) {
                        popup.close(true);
                    }
                    this._current = {
                        options: options,
                        elementSize: elementSize,
                        shape: shape,
                        target: target,
                        position: this._position(options.shared ? shape : target, options, elementSize, event)
                    };
                    if (delay) {
                        this._showTimeout = setTimeout(this._openPopupHandler, options.showAfter || 0);
                    } else {
                        this._openPopup();
                    }
                }
            },
            _openPopup: function () {
                var current = this._current;
                var position = current.position;
                this.getPopup().open(position.left, position.top);
            },
            _autoHide: function (options) {
                if (options.autoHide && this._closeButton) {
                    this.element.removeClass('k-tooltip-closable');
                    this._closeButton.remove();
                    delete this._closeButton;
                }
                if (!options.autoHide && !this._closeButton) {
                    this.element.addClass('k-tooltip-closable');
                    this._closeButton = $(TOOLTIP_CLOSE_TEMPLATE).prependTo(this.element);
                }
            },
            _showEvent: function (e) {
                var shape = this._tooltipShape(e.element);
                if (shape) {
                    var options = deepExtend({}, this.options, this._tooltipOptions(shape.options.tooltip));
                    if (options && options.showOn == e.type) {
                        this._show(e.element, shape, options, e.originalEvent, true);
                    }
                }
            },
            _measure: function (options) {
                var popup = this.getPopup();
                var width, height;
                this.element.css({
                    width: 'auto',
                    height: 'auto'
                });
                var visible = popup.visible();
                if (!visible) {
                    popup.wrapper.show();
                }
                this.element.css({
                    width: defined(options.width) ? options.width : 'auto',
                    height: defined(options.height) ? options.height : 'auto'
                });
                width = outerWidth(this.element);
                height = outerHeight(this.element);
                if (!visible) {
                    popup.wrapper.hide();
                }
                return {
                    width: width,
                    height: height
                };
            },
            _mouseleave: function (e) {
                if (this.popup && !this._popupRelatedTarget(e.originalEvent)) {
                    var tooltip = this;
                    var current = tooltip._current;
                    if (current && current.options.autoHide) {
                        tooltip._timeout = setTimeout(function () {
                            clearTimeout(tooltip._showTimeout);
                            tooltip.hide();
                        }, current.options.hideDelay || 0);
                    }
                }
            },
            _mousemove: function (e) {
                var current = this._current;
                if (current && e.element) {
                    var options = current.options;
                    if (options.position == 'cursor') {
                        var position = this._position(e.element, options, current.elementSize, e.originalEvent);
                        current.position = position;
                        this.getPopup().wrapper.css({
                            left: position.left,
                            top: position.top
                        });
                    }
                }
            },
            _surfaceLeave: function (e) {
                if (this.popup && !this._popupRelatedTarget(e)) {
                    clearTimeout(this._showTimeout);
                    this.hide();
                }
            },
            _popupRelatedTarget: function (e) {
                return e.relatedTarget && $(e.relatedTarget).closest(this.popup.wrapper).length;
            },
            _tooltipLeave: function () {
                var tooltip = this;
                var current = tooltip._current;
                if (current && current.options.autoHide) {
                    tooltip._timeout = setTimeout(function () {
                        tooltip.hide();
                    }, current.options.hideDelay || 0);
                }
            }
        });
        kendo.drawing.SurfaceTooltip = SurfaceTooltip;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/surface', [
        'drawing/kendo-drawing',
        'drawing/surface-tooltip'
    ], f);
}(function () {
    (function ($) {
        var kendo = window.kendo;
        var draw = kendo.drawing;
        var DrawingSurface = draw.Surface;
        var Widget = kendo.ui.Widget;
        var deepExtend = kendo.deepExtend;
        var proxy = $.proxy;
        kendo.support.svg = DrawingSurface.support.svg;
        kendo.support.canvas = DrawingSurface.support.canvas;
        var Surface = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, {});
                this.options = deepExtend({}, this.options, options);
                this._instance = DrawingSurface.create(this.element[0], options);
                if (this._instance.translate) {
                    this.translate = translate;
                }
                this._triggerInstanceHandler = proxy(this._triggerInstanceEvent, this);
                this._bindHandler('click');
                this._bindHandler('mouseenter');
                this._bindHandler('mouseleave');
                this._bindHandler('mousemove');
                this._enableTracking();
            },
            options: {
                name: 'Surface',
                tooltip: {}
            },
            events: [
                'click',
                'mouseenter',
                'mouseleave',
                'mousemove',
                'resize',
                'tooltipOpen',
                'tooltipClose'
            ],
            _triggerInstanceEvent: function (e) {
                this.trigger(e.type, e);
            },
            _bindHandler: function (event) {
                this._instance.bind(event, this._triggerInstanceHandler);
            },
            draw: function (element) {
                this._instance.draw(element);
            },
            clear: function () {
                if (this._instance) {
                    this._instance.clear();
                }
                this.hideTooltip();
            },
            destroy: function () {
                if (this._instance) {
                    this._instance.destroy();
                    delete this._instance;
                }
                if (this._tooltip) {
                    this._tooltip.destroy();
                    delete this._tooltip;
                }
                Widget.fn.destroy.call(this);
            },
            exportVisual: function () {
                return this._instance.exportVisual();
            },
            eventTarget: function (e) {
                return this._instance.eventTarget(e);
            },
            showTooltip: function (shape, options) {
                if (this._tooltip) {
                    this._tooltip.show(shape, options);
                }
            },
            hideTooltip: function () {
                if (this._tooltip) {
                    this._tooltip.hide();
                }
            },
            suspendTracking: function () {
                this._instance.suspendTracking();
                this.hideTooltip();
            },
            resumeTracking: function () {
                this._instance.resumeTracking();
            },
            getSize: function () {
                return {
                    width: this.element.width(),
                    height: this.element.height()
                };
            },
            setSize: function (size) {
                this.element.css({
                    width: size.width,
                    height: size.height
                });
                this._size = size;
                this._instance.currentSize(size);
                this._resize();
            },
            _resize: function () {
                this._instance.currentSize(this._size);
                this._instance._resize();
            },
            _enableTracking: function () {
                if (kendo.ui.Popup) {
                    this._tooltip = new draw.SurfaceTooltip(this, this.options.tooltip || {});
                }
            }
        });
        kendo.ui.plugin(Surface);
        Surface.create = function (element, options) {
            return new Surface(element, options);
        };
        kendo.drawing.Surface = Surface;
        function translate(offset) {
            this._instance.translate(offset);
        }
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/html', ['drawing/kendo-drawing'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo;
        var drawing = kendo.drawing;
        var drawDOM = drawing.drawDOM;
        drawing.drawDOM = function (element, options) {
            return drawDOM($(element)[0], options);
        };
        drawing.drawDOM.drawText = drawDOM.drawText;
        drawing.drawDOM.getFontFaces = drawDOM.getFontFaces;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.drawing', [
        'drawing/util',
        'drawing/kendo-drawing',
        'drawing/surface-tooltip',
        'drawing/surface',
        'drawing/html'
    ], f);
}(function () {
    var __meta__ = {
        id: 'drawing',
        name: 'Drawing API',
        category: 'framework',
        description: 'The Kendo UI low-level drawing API',
        depends: [
            'core',
            'color',
            'popup'
        ]
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.validator', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'validator',
        name: 'Validator',
        category: 'web',
        description: 'The Validator offers an easy way to do a client-side form validation.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, NS = '.kendoValidator', INVALIDMSG = 'k-invalid-msg', invalidMsgRegExp = new RegExp(INVALIDMSG, 'i'), INVALIDINPUT = 'k-invalid', VALIDINPUT = 'k-valid', emailRegExp = /^[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])?)*$/i, urlRegExp = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([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])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i, INPUTSELECTOR = ':input:not(:button,[type=submit],[type=reset],[disabled],[readonly])', CHECKBOXSELECTOR = ':checkbox:not([disabled],[readonly])', NUMBERINPUTSELECTOR = '[type=number],[type=range]', BLUR = 'blur', NAME = 'name', FORM = 'form', NOVALIDATE = 'novalidate', VALIDATE = 'validate', CHANGE = 'change', VALIDATE_INPUT = 'validateInput', proxy = $.proxy, patternMatcher = function (value, pattern) {
                if (typeof pattern === 'string') {
                    pattern = new RegExp('^(?:' + pattern + ')$');
                }
                return pattern.test(value);
            }, matcher = function (input, selector, pattern) {
                var value = input.val();
                if (input.filter(selector).length && value !== '') {
                    return patternMatcher(value, pattern);
                }
                return true;
            }, hasAttribute = function (input, name) {
                if (input.length) {
                    return input[0].attributes[name] != null;
                }
                return false;
            };
        if (!kendo.ui.validator) {
            kendo.ui.validator = {
                rules: {},
                messages: {}
            };
        }
        function resolveRules(element) {
            var resolvers = kendo.ui.validator.ruleResolvers || {}, rules = {}, name;
            for (name in resolvers) {
                $.extend(true, rules, resolvers[name].resolve(element));
            }
            return rules;
        }
        function decode(value) {
            return value.replace(/&amp/g, '&amp;').replace(/&quot;/g, '"').replace(/&#39;/g, '\'').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
        }
        function numberOfDecimalDigits(value) {
            value = (value + '').split('.');
            if (value.length > 1) {
                return value[1].length;
            }
            return 0;
        }
        function parseHtml(text) {
            if ($.parseHTML) {
                return $($.parseHTML(text));
            }
            return $(text);
        }
        function searchForMessageContainer(elements, fieldName) {
            var containers = $(), element, attr;
            for (var idx = 0, length = elements.length; idx < length; idx++) {
                element = elements[idx];
                if (invalidMsgRegExp.test(element.className)) {
                    attr = element.getAttribute(kendo.attr('for'));
                    if (attr === fieldName) {
                        containers = containers.add(element);
                    }
                }
            }
            return containers;
        }
        var Validator = Widget.extend({
            init: function (element, options) {
                var that = this, resolved = resolveRules(element), validateAttributeSelector = '[' + kendo.attr('validate') + '!=false]';
                options = options || {};
                options.rules = $.extend({}, kendo.ui.validator.rules, resolved.rules, options.rules);
                options.messages = $.extend({}, kendo.ui.validator.messages, resolved.messages, options.messages);
                Widget.fn.init.call(that, element, options);
                that._errorTemplate = kendo.template(that.options.errorTemplate);
                if (that.element.is(FORM)) {
                    that.element.attr(NOVALIDATE, NOVALIDATE);
                }
                that._inputSelector = INPUTSELECTOR + validateAttributeSelector;
                that._checkboxSelector = CHECKBOXSELECTOR + validateAttributeSelector;
                that._errors = {};
                that._attachEvents();
                that._isValidated = false;
            },
            events: [
                VALIDATE,
                CHANGE,
                VALIDATE_INPUT
            ],
            options: {
                name: 'Validator',
                errorTemplate: '<span class="k-widget k-tooltip k-tooltip-validation">' + '<span class="k-icon k-i-warning"> </span> #=message#</span>',
                messages: {
                    required: '{0} is required',
                    pattern: '{0} is not valid',
                    min: '{0} should be greater than or equal to {1}',
                    max: '{0} should be smaller than or equal to {1}',
                    step: '{0} is not valid',
                    email: '{0} is not valid email',
                    url: '{0} is not valid URL',
                    date: '{0} is not valid date',
                    dateCompare: 'End date should be greater than or equal to the start date'
                },
                rules: {
                    required: function (input) {
                        var checkbox = input.filter('[type=checkbox]').length && !input.is(':checked'), value = input.val();
                        return !(hasAttribute(input, 'required') && (!value || value === '' || value.length === 0 || checkbox));
                    },
                    pattern: function (input) {
                        if (input.filter('[type=text],[type=email],[type=url],[type=tel],[type=search],[type=password]').filter('[pattern]').length && input.val() !== '') {
                            return patternMatcher(input.val(), input.attr('pattern'));
                        }
                        return true;
                    },
                    min: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[min]').length && input.val() !== '') {
                            var min = parseFloat(input.attr('min')) || 0, val = kendo.parseFloat(input.val());
                            return min <= val;
                        }
                        return true;
                    },
                    max: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[max]').length && input.val() !== '') {
                            var max = parseFloat(input.attr('max')) || 0, val = kendo.parseFloat(input.val());
                            return max >= val;
                        }
                        return true;
                    },
                    step: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[step]').length && input.val() !== '') {
                            var min = parseFloat(input.attr('min')) || 0, step = parseFloat(input.attr('step')) || 1, val = parseFloat(input.val()), decimals = numberOfDecimalDigits(step), raise;
                            if (decimals) {
                                raise = Math.pow(10, decimals);
                                return Math.floor((val - min) * raise) % (step * raise) / Math.pow(100, decimals) === 0;
                            }
                            return (val - min) % step === 0;
                        }
                        return true;
                    },
                    email: function (input) {
                        return matcher(input, '[type=email],[' + kendo.attr('type') + '=email]', emailRegExp);
                    },
                    url: function (input) {
                        return matcher(input, '[type=url],[' + kendo.attr('type') + '=url]', urlRegExp);
                    },
                    date: function (input) {
                        if (input.filter('[type^=date],[' + kendo.attr('type') + '=date]').length && input.val() !== '') {
                            return kendo.parseDate(input.val(), input.attr(kendo.attr('format'))) !== null;
                        }
                        return true;
                    }
                },
                validateOnBlur: true
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.element.off(NS);
            },
            value: function () {
                if (!this._isValidated) {
                    return false;
                }
                return this.errors().length === 0;
            },
            _submit: function (e) {
                if (!this.validate()) {
                    e.stopPropagation();
                    e.stopImmediatePropagation();
                    e.preventDefault();
                    return false;
                }
                return true;
            },
            _checkElement: function (element) {
                var state = this.value();
                this.validateInput(element);
                if (this.value() !== state) {
                    this.trigger(CHANGE);
                }
            },
            _attachEvents: function () {
                var that = this;
                if (that.element.is(FORM)) {
                    that.element.on('submit' + NS, proxy(that._submit, that));
                }
                if (that.options.validateOnBlur) {
                    if (!that.element.is(INPUTSELECTOR)) {
                        that.element.on(BLUR + NS, that._inputSelector, function () {
                            that._checkElement($(this));
                        });
                        that.element.on('click' + NS, that._checkboxSelector, function () {
                            that._checkElement($(this));
                        });
                    } else {
                        that.element.on(BLUR + NS, function () {
                            that._checkElement(that.element);
                        });
                        if (that.element.is(CHECKBOXSELECTOR)) {
                            that.element.on('click' + NS, function () {
                                that._checkElement(that.element);
                            });
                        }
                    }
                }
            },
            validate: function () {
                var inputs;
                var idx;
                var result = false;
                var length;
                var isValid = this.value();
                this._errors = {};
                if (!this.element.is(INPUTSELECTOR)) {
                    var invalid = false;
                    inputs = this.element.find(this._inputSelector);
                    for (idx = 0, length = inputs.length; idx < length; idx++) {
                        if (!this.validateInput(inputs.eq(idx))) {
                            invalid = true;
                        }
                    }
                    result = !invalid;
                } else {
                    result = this.validateInput(this.element);
                }
                this.trigger(VALIDATE, { valid: result });
                if (isValid !== result) {
                    this.trigger(CHANGE);
                }
                return result;
            },
            validateInput: function (input) {
                input = $(input);
                this._isValidated = true;
                var that = this, template = that._errorTemplate, result = that._checkValidity(input), valid = result.valid, className = '.' + INVALIDMSG, fieldName = input.attr(NAME) || '', lbl = that._findMessageContainer(fieldName).add(input.next(className).filter(function () {
                        var element = $(this);
                        if (element.filter('[' + kendo.attr('for') + ']').length) {
                            return element.attr(kendo.attr('for')) === fieldName;
                        }
                        return true;
                    })).hide(), messageText, wasValid = !input.attr('aria-invalid');
                input.removeAttr('aria-invalid');
                if (!valid) {
                    messageText = that._extractMessage(input, result.key);
                    that._errors[fieldName] = messageText;
                    var messageLabel = parseHtml(template({ message: decode(messageText) }));
                    var lblId = lbl.attr('id');
                    that._decorateMessageContainer(messageLabel, fieldName);
                    if (lblId) {
                        messageLabel.attr('id', lblId);
                    }
                    if (!lbl.replaceWith(messageLabel).length) {
                        messageLabel.insertAfter(input);
                    }
                    messageLabel.show();
                    input.attr('aria-invalid', true);
                } else {
                    delete that._errors[fieldName];
                }
                if (wasValid !== valid) {
                    this.trigger(VALIDATE_INPUT, {
                        valid: valid,
                        input: input
                    });
                }
                input.toggleClass(INVALIDINPUT, !valid);
                input.toggleClass(VALIDINPUT, valid);
                if (kendo.widgetInstance(input)) {
                    var inputWrap = kendo.widgetInstance(input)._inputWrapper;
                    if (inputWrap) {
                        inputWrap.toggleClass(INVALIDINPUT, !valid);
                        inputWrap.toggleClass(INVALIDINPUT, !valid);
                    }
                }
                return valid;
            },
            hideMessages: function () {
                var that = this, className = '.' + INVALIDMSG, element = that.element;
                if (!element.is(INPUTSELECTOR)) {
                    element.find(className).hide();
                } else {
                    element.next(className).hide();
                }
            },
            _findMessageContainer: function (fieldName) {
                var locators = kendo.ui.validator.messageLocators, name, containers = $();
                for (var idx = 0, length = this.element.length; idx < length; idx++) {
                    containers = containers.add(searchForMessageContainer(this.element[idx].getElementsByTagName('*'), fieldName));
                }
                for (name in locators) {
                    containers = containers.add(locators[name].locate(this.element, fieldName));
                }
                return containers;
            },
            _decorateMessageContainer: function (container, fieldName) {
                var locators = kendo.ui.validator.messageLocators, name;
                container.addClass(INVALIDMSG).attr(kendo.attr('for'), fieldName || '');
                for (name in locators) {
                    locators[name].decorate(container, fieldName);
                }
                container.attr('role', 'alert');
            },
            _extractMessage: function (input, ruleKey) {
                var that = this, customMessage = that.options.messages[ruleKey], fieldName = input.attr(NAME), nonDefaultMessage;
                if (!kendo.ui.Validator.prototype.options.messages[ruleKey]) {
                    nonDefaultMessage = kendo.isFunction(customMessage) ? customMessage(input) : customMessage;
                }
                customMessage = kendo.isFunction(customMessage) ? customMessage(input) : customMessage;
                return kendo.format(input.attr(kendo.attr(ruleKey + '-msg')) || input.attr('validationMessage') || nonDefaultMessage || input.attr('title') || customMessage || '', fieldName, input.attr(ruleKey) || input.attr(kendo.attr(ruleKey)));
            },
            _checkValidity: function (input) {
                var rules = this.options.rules, rule;
                for (rule in rules) {
                    if (!rules[rule].call(this, input)) {
                        return {
                            valid: false,
                            key: rule
                        };
                    }
                }
                return { valid: true };
            },
            errors: function () {
                var results = [], errors = this._errors, error;
                for (error in errors) {
                    results.push(errors[error]);
                }
                return results;
            }
        });
        kendo.ui.plugin(Validator);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.userevents', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'userevents',
        name: 'User Events',
        category: 'framework',
        depends: ['core'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, support = kendo.support, Class = kendo.Class, Observable = kendo.Observable, now = $.now, extend = $.extend, OS = support.mobileOS, invalidZeroEvents = OS && OS.android, DEFAULT_MIN_HOLD = 800, CLICK_DELAY = 300, DEFAULT_THRESHOLD = support.browser.msie ? 5 : 0, PRESS = 'press', HOLD = 'hold', SELECT = 'select', START = 'start', MOVE = 'move', END = 'end', CANCEL = 'cancel', TAP = 'tap', DOUBLETAP = 'doubleTap', RELEASE = 'release', GESTURESTART = 'gesturestart', GESTURECHANGE = 'gesturechange', GESTUREEND = 'gestureend', GESTURETAP = 'gesturetap';
        var THRESHOLD = {
            'api': 0,
            'touch': 0,
            'mouse': 9,
            'pointer': 9
        };
        var ENABLE_GLOBAL_SURFACE = !support.touch || support.mouseAndTouchPresent;
        function touchDelta(touch1, touch2) {
            var x1 = touch1.x.location, y1 = touch1.y.location, x2 = touch2.x.location, y2 = touch2.y.location, dx = x1 - x2, dy = y1 - y2;
            return {
                center: {
                    x: (x1 + x2) / 2,
                    y: (y1 + y2) / 2
                },
                distance: Math.sqrt(dx * dx + dy * dy)
            };
        }
        function getTouches(e) {
            var touches = [], originalEvent = e.originalEvent, currentTarget = e.currentTarget, idx = 0, length, changedTouches, touch;
            if (e.api) {
                touches.push({
                    id: 2,
                    event: e,
                    target: e.target,
                    currentTarget: e.target,
                    location: e,
                    type: 'api'
                });
            } else if (e.type.match(/touch/)) {
                changedTouches = originalEvent ? originalEvent.changedTouches : [];
                for (length = changedTouches.length; idx < length; idx++) {
                    touch = changedTouches[idx];
                    touches.push({
                        location: touch,
                        event: e,
                        target: touch.target,
                        currentTarget: currentTarget,
                        id: touch.identifier,
                        type: 'touch'
                    });
                }
            } else if (support.pointers || support.msPointers) {
                touches.push({
                    location: originalEvent,
                    event: e,
                    target: e.target,
                    currentTarget: currentTarget,
                    id: originalEvent.pointerId,
                    type: 'pointer'
                });
            } else {
                touches.push({
                    id: 1,
                    event: e,
                    target: e.target,
                    currentTarget: currentTarget,
                    location: e,
                    type: 'mouse'
                });
            }
            return touches;
        }
        var TouchAxis = Class.extend({
            init: function (axis, location) {
                var that = this;
                that.axis = axis;
                that._updateLocationData(location);
                that.startLocation = that.location;
                that.velocity = that.delta = 0;
                that.timeStamp = now();
            },
            move: function (location) {
                var that = this, offset = location['page' + that.axis], timeStamp = now(), timeDelta = timeStamp - that.timeStamp || 1;
                if (!offset && invalidZeroEvents) {
                    return;
                }
                that.delta = offset - that.location;
                that._updateLocationData(location);
                that.initialDelta = offset - that.startLocation;
                that.velocity = that.delta / timeDelta;
                that.timeStamp = timeStamp;
            },
            _updateLocationData: function (location) {
                var that = this, axis = that.axis;
                that.location = location['page' + axis];
                that.client = location['client' + axis];
                that.screen = location['screen' + axis];
            }
        });
        var Touch = Class.extend({
            init: function (userEvents, target, touchInfo) {
                extend(this, {
                    x: new TouchAxis('X', touchInfo.location),
                    y: new TouchAxis('Y', touchInfo.location),
                    type: touchInfo.type,
                    useClickAsTap: userEvents.useClickAsTap,
                    threshold: userEvents.threshold || THRESHOLD[touchInfo.type],
                    userEvents: userEvents,
                    target: target,
                    currentTarget: touchInfo.currentTarget,
                    initialTouch: touchInfo.target,
                    id: touchInfo.id,
                    pressEvent: touchInfo,
                    _clicks: userEvents._clicks,
                    supportDoubleTap: userEvents.supportDoubleTap,
                    _moved: false,
                    _finished: false
                });
            },
            press: function () {
                this._holdTimeout = setTimeout($.proxy(this, '_hold'), this.userEvents.minHold);
                this._trigger(PRESS, this.pressEvent);
            },
            _tap: function (touchInfo) {
                var that = this;
                that.userEvents._clicks++;
                if (that.userEvents._clicks == 1) {
                    that._clickTimeout = setTimeout(function () {
                        if (that.userEvents._clicks == 1) {
                            that._trigger(TAP, touchInfo);
                        } else {
                            that._trigger(DOUBLETAP, touchInfo);
                        }
                        that.userEvents._clicks = 0;
                    }, CLICK_DELAY);
                }
            },
            _hold: function () {
                this._trigger(HOLD, this.pressEvent);
            },
            move: function (touchInfo) {
                var that = this;
                if (that._finished) {
                    return;
                }
                that.x.move(touchInfo.location);
                that.y.move(touchInfo.location);
                if (!that._moved) {
                    if (that._withinIgnoreThreshold()) {
                        return;
                    }
                    if (!UserEvents.current || UserEvents.current === that.userEvents) {
                        that._start(touchInfo);
                    } else {
                        return that.dispose();
                    }
                }
                if (!that._finished) {
                    that._trigger(MOVE, touchInfo);
                }
            },
            end: function (touchInfo) {
                this.endTime = now();
                if (this._finished) {
                    return;
                }
                this._finished = true;
                this._trigger(RELEASE, touchInfo);
                if (this._moved) {
                    this._trigger(END, touchInfo);
                } else {
                    if (!this.useClickAsTap) {
                        if (this.supportDoubleTap) {
                            this._tap(touchInfo);
                        } else {
                            this._trigger(TAP, touchInfo);
                        }
                    }
                }
                clearTimeout(this._holdTimeout);
                this.dispose();
            },
            dispose: function () {
                var userEvents = this.userEvents, activeTouches = userEvents.touches;
                this._finished = true;
                this.pressEvent = null;
                clearTimeout(this._holdTimeout);
                activeTouches.splice($.inArray(this, activeTouches), 1);
            },
            skip: function () {
                this.dispose();
            },
            cancel: function () {
                this.dispose();
            },
            isMoved: function () {
                return this._moved;
            },
            _start: function (touchInfo) {
                clearTimeout(this._holdTimeout);
                this.startTime = now();
                this._moved = true;
                this._trigger(START, touchInfo);
            },
            _trigger: function (name, touchInfo) {
                var that = this, jQueryEvent = touchInfo.event, data = {
                        touch: that,
                        x: that.x,
                        y: that.y,
                        target: that.target,
                        event: jQueryEvent
                    };
                if (that.userEvents.notify(name, data)) {
                    jQueryEvent.preventDefault();
                }
            },
            _withinIgnoreThreshold: function () {
                var xDelta = this.x.initialDelta, yDelta = this.y.initialDelta;
                return Math.sqrt(xDelta * xDelta + yDelta * yDelta) <= this.threshold;
            }
        });
        function withEachUpEvent(callback) {
            var downEvents = kendo.eventMap.up.split(' '), idx = 0, length = downEvents.length;
            for (; idx < length; idx++) {
                callback(downEvents[idx]);
            }
        }
        var UserEvents = Observable.extend({
            init: function (element, options) {
                var that = this, filter, ns = kendo.guid();
                options = options || {};
                filter = that.filter = options.filter;
                that.threshold = options.threshold || DEFAULT_THRESHOLD;
                that.minHold = options.minHold || DEFAULT_MIN_HOLD;
                that.touches = [];
                that._maxTouches = options.multiTouch ? 2 : 1;
                that.allowSelection = options.allowSelection;
                that.captureUpIfMoved = options.captureUpIfMoved;
                that.useClickAsTap = !options.fastTap && !support.delayedClick();
                that.eventNS = ns;
                that._clicks = 0;
                that.supportDoubleTap = options.supportDoubleTap;
                element = $(element).handler(that);
                Observable.fn.init.call(that);
                extend(that, {
                    element: element,
                    surface: options.global && ENABLE_GLOBAL_SURFACE ? $(element[0].ownerDocument.documentElement) : $(options.surface || element),
                    stopPropagation: options.stopPropagation,
                    pressed: false
                });
                that.surface.handler(that).on(kendo.applyEventMap('move', ns), '_move').on(kendo.applyEventMap('up cancel', ns), '_end');
                element.on(kendo.applyEventMap('down', ns), filter, '_start');
                if (that.useClickAsTap) {
                    element.on(kendo.applyEventMap('click', ns), filter, '_click');
                }
                if (support.pointers || support.msPointers) {
                    if (support.browser.version < 11) {
                        var defaultAction = 'pinch-zoom double-tap-zoom';
                        element.css('-ms-touch-action', options.touchAction && options.touchAction != 'none' ? defaultAction + ' ' + options.touchAction : defaultAction);
                    } else {
                        element.css('touch-action', options.touchAction || 'none');
                    }
                }
                if (options.preventDragEvent) {
                    element.on(kendo.applyEventMap('dragstart', ns), kendo.preventDefault);
                }
                element.on(kendo.applyEventMap('mousedown', ns), filter, { root: element }, '_select');
                if (that.captureUpIfMoved && support.eventCapture) {
                    var surfaceElement = that.surface[0], preventIfMovingProxy = $.proxy(that.preventIfMoving, that);
                    withEachUpEvent(function (eventName) {
                        surfaceElement.addEventListener(eventName, preventIfMovingProxy, true);
                    });
                }
                that.bind([
                    PRESS,
                    HOLD,
                    TAP,
                    DOUBLETAP,
                    START,
                    MOVE,
                    END,
                    RELEASE,
                    CANCEL,
                    GESTURESTART,
                    GESTURECHANGE,
                    GESTUREEND,
                    GESTURETAP,
                    SELECT
                ], options);
            },
            preventIfMoving: function (e) {
                if (this._isMoved()) {
                    e.preventDefault();
                }
            },
            destroy: function () {
                var that = this;
                if (that._destroyed) {
                    return;
                }
                that._destroyed = true;
                if (that.captureUpIfMoved && support.eventCapture) {
                    var surfaceElement = that.surface[0];
                    withEachUpEvent(function (eventName) {
                        surfaceElement.removeEventListener(eventName, that.preventIfMoving);
                    });
                }
                that.element.kendoDestroy(that.eventNS);
                that.surface.kendoDestroy(that.eventNS);
                that.element.removeData('handler');
                that.surface.removeData('handler');
                that._disposeAll();
                that.unbind();
                delete that.surface;
                delete that.element;
                delete that.currentTarget;
            },
            capture: function () {
                UserEvents.current = this;
            },
            cancel: function () {
                this._disposeAll();
                this.trigger(CANCEL);
            },
            notify: function (eventName, data) {
                var that = this, touches = that.touches;
                if (this._isMultiTouch()) {
                    switch (eventName) {
                    case MOVE:
                        eventName = GESTURECHANGE;
                        break;
                    case END:
                        eventName = GESTUREEND;
                        break;
                    case TAP:
                        eventName = GESTURETAP;
                        break;
                    }
                    extend(data, { touches: touches }, touchDelta(touches[0], touches[1]));
                }
                return this.trigger(eventName, extend(data, { type: eventName }));
            },
            press: function (x, y, target) {
                this._apiCall('_start', x, y, target);
            },
            move: function (x, y) {
                this._apiCall('_move', x, y);
            },
            end: function (x, y) {
                this._apiCall('_end', x, y);
            },
            _isMultiTouch: function () {
                return this.touches.length > 1;
            },
            _maxTouchesReached: function () {
                return this.touches.length >= this._maxTouches;
            },
            _disposeAll: function () {
                var touches = this.touches;
                while (touches.length > 0) {
                    touches.pop().dispose();
                }
            },
            _isMoved: function () {
                return $.grep(this.touches, function (touch) {
                    return touch.isMoved();
                }).length;
            },
            _select: function (e) {
                if (!this.allowSelection || this.trigger(SELECT, { event: e })) {
                    e.preventDefault();
                }
            },
            _start: function (e) {
                var that = this, idx = 0, filter = that.filter, target, touches = getTouches(e), length = touches.length, touch, which = e.which;
                if (which && which > 1 || that._maxTouchesReached()) {
                    return;
                }
                UserEvents.current = null;
                that.currentTarget = e.currentTarget;
                if (that.stopPropagation) {
                    e.stopPropagation();
                }
                for (; idx < length; idx++) {
                    if (that._maxTouchesReached()) {
                        break;
                    }
                    touch = touches[idx];
                    if (filter) {
                        target = $(touch.currentTarget);
                    } else {
                        target = that.element;
                    }
                    if (!target.length) {
                        continue;
                    }
                    touch = new Touch(that, target, touch);
                    that.touches.push(touch);
                    touch.press();
                    if (that._isMultiTouch()) {
                        that.notify('gesturestart', {});
                    }
                }
            },
            _move: function (e) {
                this._eachTouch('move', e);
            },
            _end: function (e) {
                this._eachTouch('end', e);
            },
            _click: function (e) {
                var data = {
                    touch: {
                        initialTouch: e.target,
                        target: $(e.currentTarget),
                        endTime: now(),
                        x: {
                            location: e.pageX,
                            client: e.clientX
                        },
                        y: {
                            location: e.pageY,
                            client: e.clientY
                        }
                    },
                    x: e.pageX,
                    y: e.pageY,
                    target: $(e.currentTarget),
                    event: e,
                    type: 'tap'
                };
                if (this.trigger('tap', data)) {
                    e.preventDefault();
                }
            },
            _eachTouch: function (methodName, e) {
                var that = this, dict = {}, touches = getTouches(e), activeTouches = that.touches, idx, touch, touchInfo, matchingTouch;
                for (idx = 0; idx < activeTouches.length; idx++) {
                    touch = activeTouches[idx];
                    dict[touch.id] = touch;
                }
                for (idx = 0; idx < touches.length; idx++) {
                    touchInfo = touches[idx];
                    matchingTouch = dict[touchInfo.id];
                    if (matchingTouch) {
                        matchingTouch[methodName](touchInfo);
                    }
                }
            },
            _apiCall: function (type, x, y, target) {
                this[type]({
                    api: true,
                    pageX: x,
                    pageY: y,
                    clientX: x,
                    clientY: y,
                    target: $(target || this.element)[0],
                    stopPropagation: $.noop,
                    preventDefault: $.noop
                });
            }
        });
        UserEvents.defaultThreshold = function (value) {
            DEFAULT_THRESHOLD = value;
        };
        UserEvents.minHold = function (value) {
            DEFAULT_MIN_HOLD = value;
        };
        kendo.getTouches = getTouches;
        kendo.touchDelta = touchDelta;
        kendo.UserEvents = UserEvents;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.draganddrop', [
        'kendo.core',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'draganddrop',
        name: 'Drag & drop',
        category: 'framework',
        description: 'Drag & drop functionality for any DOM element.',
        depends: [
            'core',
            'userevents'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, support = kendo.support, document = window.document, $window = $(window), Class = kendo.Class, Widget = kendo.ui.Widget, Observable = kendo.Observable, UserEvents = kendo.UserEvents, proxy = $.proxy, extend = $.extend, getOffset = kendo.getOffset, draggables = {}, dropTargets = {}, dropAreas = {}, lastDropTarget, elementUnderCursor = kendo.elementUnderCursor, KEYUP = 'keyup', CHANGE = 'change', DRAGSTART = 'dragstart', HOLD = 'hold', DRAG = 'drag', DRAGEND = 'dragend', DRAGCANCEL = 'dragcancel', HINTDESTROYED = 'hintDestroyed', DRAGENTER = 'dragenter', DRAGLEAVE = 'dragleave', DROP = 'drop';
        function contains(parent, child) {
            try {
                return $.contains(parent, child) || parent == child;
            } catch (e) {
                return false;
            }
        }
        function numericCssPropery(element, property) {
            return parseInt(element.css(property), 10) || 0;
        }
        function within(value, range) {
            return Math.min(Math.max(value, range.min), range.max);
        }
        function containerBoundaries(container, element) {
            var offset = getOffset(container), outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, minX = offset.left + numericCssPropery(container, 'borderLeftWidth') + numericCssPropery(container, 'paddingLeft'), minY = offset.top + numericCssPropery(container, 'borderTopWidth') + numericCssPropery(container, 'paddingTop'), maxX = minX + container.width() - outerWidth(element, true), maxY = minY + container.height() - outerHeight(element, true);
            return {
                x: {
                    min: minX,
                    max: maxX
                },
                y: {
                    min: minY,
                    max: maxY
                }
            };
        }
        function checkTarget(target, targets, areas) {
            var theTarget, theFilter, i = 0, targetLen = targets && targets.length, areaLen = areas && areas.length;
            while (target && target.parentNode) {
                for (i = 0; i < targetLen; i++) {
                    theTarget = targets[i];
                    if (theTarget.element[0] === target) {
                        return {
                            target: theTarget,
                            targetElement: target
                        };
                    }
                }
                for (i = 0; i < areaLen; i++) {
                    theFilter = areas[i];
                    if ($.contains(theFilter.element[0], target) && support.matchesSelector.call(target, theFilter.options.filter)) {
                        return {
                            target: theFilter,
                            targetElement: target
                        };
                    }
                }
                target = target.parentNode;
            }
            return undefined;
        }
        var TapCapture = Observable.extend({
            init: function (element, options) {
                var that = this, domElement = element[0];
                that.capture = false;
                if (domElement.addEventListener) {
                    $.each(kendo.eventMap.down.split(' '), function () {
                        domElement.addEventListener(this, proxy(that._press, that), true);
                    });
                    $.each(kendo.eventMap.up.split(' '), function () {
                        domElement.addEventListener(this, proxy(that._release, that), true);
                    });
                } else {
                    $.each(kendo.eventMap.down.split(' '), function () {
                        domElement.attachEvent(this, proxy(that._press, that));
                    });
                    $.each(kendo.eventMap.up.split(' '), function () {
                        domElement.attachEvent(this, proxy(that._release, that));
                    });
                }
                Observable.fn.init.call(that);
                that.bind([
                    'press',
                    'release'
                ], options || {});
            },
            captureNext: function () {
                this.capture = true;
            },
            cancelCapture: function () {
                this.capture = false;
            },
            _press: function (e) {
                var that = this;
                that.trigger('press');
                if (that.capture) {
                    e.preventDefault();
                }
            },
            _release: function (e) {
                var that = this;
                that.trigger('release');
                if (that.capture) {
                    e.preventDefault();
                    that.cancelCapture();
                }
            }
        });
        var PaneDimension = Observable.extend({
            init: function (options) {
                var that = this;
                Observable.fn.init.call(that);
                that.forcedEnabled = false;
                $.extend(that, options);
                that.scale = 1;
                if (that.horizontal) {
                    that.measure = 'offsetWidth';
                    that.scrollSize = 'scrollWidth';
                    that.axis = 'x';
                } else {
                    that.measure = 'offsetHeight';
                    that.scrollSize = 'scrollHeight';
                    that.axis = 'y';
                }
            },
            makeVirtual: function () {
                $.extend(this, {
                    virtual: true,
                    forcedEnabled: true,
                    _virtualMin: 0,
                    _virtualMax: 0
                });
            },
            virtualSize: function (min, max) {
                if (this._virtualMin !== min || this._virtualMax !== max) {
                    this._virtualMin = min;
                    this._virtualMax = max;
                    this.update();
                }
            },
            outOfBounds: function (offset) {
                return offset > this.max || offset < this.min;
            },
            forceEnabled: function () {
                this.forcedEnabled = true;
            },
            getSize: function () {
                return this.container[0][this.measure];
            },
            getTotal: function () {
                return this.element[0][this.scrollSize];
            },
            rescale: function (scale) {
                this.scale = scale;
            },
            update: function (silent) {
                var that = this, total = that.virtual ? that._virtualMax : that.getTotal(), scaledTotal = total * that.scale, size = that.getSize();
                if (total === 0 && !that.forcedEnabled) {
                    return;
                }
                that.max = that.virtual ? -that._virtualMin : 0;
                that.size = size;
                that.total = scaledTotal;
                that.min = Math.min(that.max, size - scaledTotal);
                that.minScale = size / total;
                that.centerOffset = (scaledTotal - size) / 2;
                that.enabled = that.forcedEnabled || scaledTotal > size;
                if (!silent) {
                    that.trigger(CHANGE, that);
                }
            }
        });
        var PaneDimensions = Observable.extend({
            init: function (options) {
                var that = this;
                Observable.fn.init.call(that);
                that.x = new PaneDimension(extend({ horizontal: true }, options));
                that.y = new PaneDimension(extend({ horizontal: false }, options));
                that.container = options.container;
                that.forcedMinScale = options.minScale;
                that.maxScale = options.maxScale || 100;
                that.bind(CHANGE, options);
            },
            rescale: function (newScale) {
                this.x.rescale(newScale);
                this.y.rescale(newScale);
                this.refresh();
            },
            centerCoordinates: function () {
                return {
                    x: Math.min(0, -this.x.centerOffset),
                    y: Math.min(0, -this.y.centerOffset)
                };
            },
            refresh: function () {
                var that = this;
                that.x.update();
                that.y.update();
                that.enabled = that.x.enabled || that.y.enabled;
                that.minScale = that.forcedMinScale || Math.min(that.x.minScale, that.y.minScale);
                that.fitScale = Math.max(that.x.minScale, that.y.minScale);
                that.trigger(CHANGE);
            }
        });
        var PaneAxis = Observable.extend({
            init: function (options) {
                var that = this;
                extend(that, options);
                Observable.fn.init.call(that);
            },
            outOfBounds: function () {
                return this.dimension.outOfBounds(this.movable[this.axis]);
            },
            dragMove: function (delta) {
                var that = this, dimension = that.dimension, axis = that.axis, movable = that.movable, position = movable[axis] + delta;
                if (!dimension.enabled) {
                    return;
                }
                if (position < dimension.min && delta < 0 || position > dimension.max && delta > 0) {
                    delta *= that.resistance;
                }
                movable.translateAxis(axis, delta);
                that.trigger(CHANGE, that);
            }
        });
        var Pane = Class.extend({
            init: function (options) {
                var that = this, x, y, resistance, movable;
                extend(that, { elastic: true }, options);
                resistance = that.elastic ? 0.5 : 0;
                movable = that.movable;
                that.x = x = new PaneAxis({
                    axis: 'x',
                    dimension: that.dimensions.x,
                    resistance: resistance,
                    movable: movable
                });
                that.y = y = new PaneAxis({
                    axis: 'y',
                    dimension: that.dimensions.y,
                    resistance: resistance,
                    movable: movable
                });
                that.userEvents.bind([
                    'press',
                    'move',
                    'end',
                    'gesturestart',
                    'gesturechange'
                ], {
                    gesturestart: function (e) {
                        that.gesture = e;
                        that.offset = that.dimensions.container.offset();
                    },
                    press: function (e) {
                        if ($(e.event.target).closest('a').is('[data-navigate-on-press=true]')) {
                            e.sender.cancel();
                        }
                    },
                    gesturechange: function (e) {
                        var previousGesture = that.gesture, previousCenter = previousGesture.center, center = e.center, scaleDelta = e.distance / previousGesture.distance, minScale = that.dimensions.minScale, maxScale = that.dimensions.maxScale, coordinates;
                        if (movable.scale <= minScale && scaleDelta < 1) {
                            scaleDelta += (1 - scaleDelta) * 0.8;
                        }
                        if (movable.scale * scaleDelta >= maxScale) {
                            scaleDelta = maxScale / movable.scale;
                        }
                        var offsetX = movable.x + that.offset.left, offsetY = movable.y + that.offset.top;
                        coordinates = {
                            x: (offsetX - previousCenter.x) * scaleDelta + center.x - offsetX,
                            y: (offsetY - previousCenter.y) * scaleDelta + center.y - offsetY
                        };
                        movable.scaleWith(scaleDelta);
                        x.dragMove(coordinates.x);
                        y.dragMove(coordinates.y);
                        that.dimensions.rescale(movable.scale);
                        that.gesture = e;
                        e.preventDefault();
                    },
                    move: function (e) {
                        if (e.event.target.tagName.match(/textarea|input/i)) {
                            return;
                        }
                        if (x.dimension.enabled || y.dimension.enabled) {
                            x.dragMove(e.x.delta);
                            y.dragMove(e.y.delta);
                            e.preventDefault();
                        } else {
                            e.touch.skip();
                        }
                    },
                    end: function (e) {
                        e.preventDefault();
                    }
                });
            }
        });
        var TRANSFORM_STYLE = support.transitions.prefix + 'Transform', translate;
        if (support.hasHW3D) {
            translate = function (x, y, scale) {
                return 'translate3d(' + x + 'px,' + y + 'px,0) scale(' + scale + ')';
            };
        } else {
            translate = function (x, y, scale) {
                return 'translate(' + x + 'px,' + y + 'px) scale(' + scale + ')';
            };
        }
        var Movable = Observable.extend({
            init: function (element) {
                var that = this;
                Observable.fn.init.call(that);
                that.element = $(element);
                that.element[0].style.webkitTransformOrigin = 'left top';
                that.x = 0;
                that.y = 0;
                that.scale = 1;
                that._saveCoordinates(translate(that.x, that.y, that.scale));
            },
            translateAxis: function (axis, by) {
                this[axis] += by;
                this.refresh();
            },
            scaleTo: function (scale) {
                this.scale = scale;
                this.refresh();
            },
            scaleWith: function (scaleDelta) {
                this.scale *= scaleDelta;
                this.refresh();
            },
            translate: function (coordinates) {
                this.x += coordinates.x;
                this.y += coordinates.y;
                this.refresh();
            },
            moveAxis: function (axis, value) {
                this[axis] = value;
                this.refresh();
            },
            moveTo: function (coordinates) {
                extend(this, coordinates);
                this.refresh();
            },
            refresh: function () {
                var that = this, x = that.x, y = that.y, newCoordinates;
                if (that.round) {
                    x = Math.round(x);
                    y = Math.round(y);
                }
                newCoordinates = translate(x, y, that.scale);
                if (newCoordinates != that.coordinates) {
                    if (kendo.support.browser.msie && kendo.support.browser.version < 10) {
                        that.element[0].style.position = 'absolute';
                        that.element[0].style.left = that.x + 'px';
                        that.element[0].style.top = that.y + 'px';
                    } else {
                        that.element[0].style[TRANSFORM_STYLE] = newCoordinates;
                    }
                    that._saveCoordinates(newCoordinates);
                    that.trigger(CHANGE);
                }
            },
            _saveCoordinates: function (coordinates) {
                this.coordinates = coordinates;
            }
        });
        function destroyDroppable(collection, widget) {
            var groupName = widget.options.group, droppables = collection[groupName], i;
            Widget.fn.destroy.call(widget);
            if (droppables.length > 1) {
                for (i = 0; i < droppables.length; i++) {
                    if (droppables[i] == widget) {
                        droppables.splice(i, 1);
                        break;
                    }
                }
            } else {
                droppables.length = 0;
                delete collection[groupName];
            }
        }
        var DropTarget = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                var group = that.options.group;
                if (!(group in dropTargets)) {
                    dropTargets[group] = [that];
                } else {
                    dropTargets[group].push(that);
                }
            },
            events: [
                DRAGENTER,
                DRAGLEAVE,
                DROP
            ],
            options: {
                name: 'DropTarget',
                group: 'default'
            },
            destroy: function () {
                destroyDroppable(dropTargets, this);
            },
            _trigger: function (eventName, e) {
                var that = this, draggable = draggables[that.options.group];
                if (draggable) {
                    return that.trigger(eventName, extend({}, e.event, {
                        draggable: draggable,
                        dropTarget: e.dropTarget
                    }));
                }
            },
            _over: function (e) {
                this._trigger(DRAGENTER, e);
            },
            _out: function (e) {
                this._trigger(DRAGLEAVE, e);
            },
            _drop: function (e) {
                var that = this, draggable = draggables[that.options.group];
                if (draggable) {
                    draggable.dropped = !that._trigger(DROP, e);
                }
            }
        });
        DropTarget.destroyGroup = function (groupName) {
            var group = dropTargets[groupName] || dropAreas[groupName], i;
            if (group) {
                for (i = 0; i < group.length; i++) {
                    Widget.fn.destroy.call(group[i]);
                }
                group.length = 0;
                delete dropTargets[groupName];
                delete dropAreas[groupName];
            }
        };
        DropTarget._cache = dropTargets;
        var DropTargetArea = DropTarget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                var group = that.options.group;
                if (!(group in dropAreas)) {
                    dropAreas[group] = [that];
                } else {
                    dropAreas[group].push(that);
                }
            },
            destroy: function () {
                destroyDroppable(dropAreas, this);
            },
            options: {
                name: 'DropTargetArea',
                group: 'default',
                filter: null
            }
        });
        var Draggable = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that._activated = false;
                that.userEvents = new UserEvents(that.element, {
                    global: true,
                    allowSelection: true,
                    filter: that.options.filter,
                    threshold: that.options.distance,
                    start: proxy(that._start, that),
                    hold: proxy(that._hold, that),
                    move: proxy(that._drag, that),
                    end: proxy(that._end, that),
                    cancel: proxy(that._cancel, that),
                    select: proxy(that._select, that)
                });
                that._afterEndHandler = proxy(that._afterEnd, that);
                that._captureEscape = proxy(that._captureEscape, that);
            },
            events: [
                HOLD,
                DRAGSTART,
                DRAG,
                DRAGEND,
                DRAGCANCEL,
                HINTDESTROYED
            ],
            options: {
                name: 'Draggable',
                distance: kendo.support.touch ? 0 : 5,
                group: 'default',
                cursorOffset: null,
                axis: null,
                container: null,
                filter: null,
                ignore: null,
                holdToDrag: false,
                autoScroll: false,
                dropped: false
            },
            cancelHold: function () {
                this._activated = false;
            },
            _captureEscape: function (e) {
                var that = this;
                if (e.keyCode === kendo.keys.ESC) {
                    that._trigger(DRAGCANCEL, { event: e });
                    that.userEvents.cancel();
                }
            },
            _updateHint: function (e) {
                var that = this, coordinates, options = that.options, boundaries = that.boundaries, axis = options.axis, cursorOffset = that.options.cursorOffset;
                if (cursorOffset) {
                    coordinates = {
                        left: e.x.location + cursorOffset.left,
                        top: e.y.location + cursorOffset.top
                    };
                } else {
                    that.hintOffset.left += e.x.delta;
                    that.hintOffset.top += e.y.delta;
                    coordinates = $.extend({}, that.hintOffset);
                }
                if (boundaries) {
                    coordinates.top = within(coordinates.top, boundaries.y);
                    coordinates.left = within(coordinates.left, boundaries.x);
                }
                if (axis === 'x') {
                    delete coordinates.top;
                } else if (axis === 'y') {
                    delete coordinates.left;
                }
                that.hint.css(coordinates);
            },
            _shouldIgnoreTarget: function (target) {
                var ignoreSelector = this.options.ignore;
                return ignoreSelector && $(target).is(ignoreSelector);
            },
            _select: function (e) {
                if (!this._shouldIgnoreTarget(e.event.target)) {
                    e.preventDefault();
                }
            },
            _start: function (e) {
                var that = this, options = that.options, container = options.container ? $(options.container) : null, hint = options.hint;
                if (this._shouldIgnoreTarget(e.touch.initialTouch) || options.holdToDrag && !that._activated) {
                    that.userEvents.cancel();
                    return;
                }
                that.currentTarget = e.target;
                that.currentTargetOffset = getOffset(that.currentTarget);
                if (hint) {
                    if (that.hint) {
                        that.hint.stop(true, true).remove();
                    }
                    that.hint = kendo.isFunction(hint) ? $(hint.call(that, that.currentTarget)) : hint;
                    var offset = getOffset(that.currentTarget);
                    that.hintOffset = offset;
                    that.hint.css({
                        position: 'absolute',
                        zIndex: 20000,
                        left: offset.left,
                        top: offset.top
                    }).appendTo(document.body);
                    that.angular('compile', function () {
                        that.hint.removeAttr('ng-repeat');
                        var scopeTarget = $(e.target);
                        while (!scopeTarget.data('$$kendoScope') && scopeTarget.length) {
                            scopeTarget = scopeTarget.parent();
                        }
                        return {
                            elements: that.hint.get(),
                            scopeFrom: scopeTarget.data('$$kendoScope')
                        };
                    });
                }
                draggables[options.group] = that;
                that.dropped = false;
                if (container) {
                    that.boundaries = containerBoundaries(container, that.hint);
                }
                $(document).on(KEYUP, that._captureEscape);
                if (that._trigger(DRAGSTART, e)) {
                    that.userEvents.cancel();
                    that._afterEnd();
                }
                that.userEvents.capture();
            },
            _hold: function (e) {
                this.currentTarget = e.target;
                if (this.options.holdToDrag && this._trigger(HOLD, e)) {
                    this.userEvents.cancel();
                } else {
                    this._activated = true;
                }
            },
            _drag: function (e) {
                e.preventDefault();
                var cursorElement = this._elementUnderCursor(e);
                if (this.options.autoScroll && this._cursorElement !== cursorElement) {
                    this._scrollableParent = findScrollableParent(cursorElement);
                    this._cursorElement = cursorElement;
                }
                this._lastEvent = e;
                this._processMovement(e, cursorElement);
                if (this.options.autoScroll) {
                    if (this._scrollableParent[0]) {
                        var velocity = autoScrollVelocity(e.x.location, e.y.location, scrollableViewPort(this._scrollableParent));
                        this._scrollCompenstation = $.extend({}, this.hintOffset);
                        this._scrollVelocity = velocity;
                        if (velocity.y === 0 && velocity.x === 0) {
                            clearInterval(this._scrollInterval);
                            this._scrollInterval = null;
                        } else if (!this._scrollInterval) {
                            this._scrollInterval = setInterval($.proxy(this, '_autoScroll'), 50);
                        }
                    }
                }
                if (this.hint) {
                    this._updateHint(e);
                }
            },
            _processMovement: function (e, cursorElement) {
                this._withDropTarget(cursorElement, function (target, targetElement) {
                    if (!target) {
                        if (lastDropTarget) {
                            lastDropTarget._trigger(DRAGLEAVE, extend(e, { dropTarget: $(lastDropTarget.targetElement) }));
                            lastDropTarget = null;
                        }
                        return;
                    }
                    if (lastDropTarget) {
                        if (targetElement === lastDropTarget.targetElement) {
                            return;
                        }
                        lastDropTarget._trigger(DRAGLEAVE, extend(e, { dropTarget: $(lastDropTarget.targetElement) }));
                    }
                    target._trigger(DRAGENTER, extend(e, { dropTarget: $(targetElement) }));
                    lastDropTarget = extend(target, { targetElement: targetElement });
                });
                this._trigger(DRAG, extend(e, {
                    dropTarget: lastDropTarget,
                    elementUnderCursor: cursorElement
                }));
            },
            _autoScroll: function () {
                var parent = this._scrollableParent[0], velocity = this._scrollVelocity, compensation = this._scrollCompenstation;
                if (!parent) {
                    return;
                }
                var cursorElement = this._elementUnderCursor(this._lastEvent);
                this._processMovement(this._lastEvent, cursorElement);
                var yIsScrollable, xIsScrollable;
                var isRootNode = parent === scrollableRoot()[0];
                if (isRootNode) {
                    yIsScrollable = document.body.scrollHeight > $window.height();
                    xIsScrollable = document.body.scrollWidth > $window.width();
                } else {
                    yIsScrollable = parent.offsetHeight <= parent.scrollHeight;
                    xIsScrollable = parent.offsetWidth <= parent.scrollWidth;
                }
                var yDelta = parent.scrollTop + velocity.y;
                var yInBounds = yIsScrollable && yDelta > 0 && yDelta < parent.scrollHeight;
                var xDelta = parent.scrollLeft + velocity.x;
                var xInBounds = xIsScrollable && xDelta > 0 && xDelta < parent.scrollWidth;
                if (yInBounds) {
                    parent.scrollTop += velocity.y;
                }
                if (xInBounds) {
                    parent.scrollLeft += velocity.x;
                }
                if (this.hint && isRootNode && (xInBounds || yInBounds)) {
                    if (yInBounds) {
                        compensation.top += velocity.y;
                    }
                    if (xInBounds) {
                        compensation.left += velocity.x;
                    }
                    this.hint.css(compensation);
                }
            },
            _end: function (e) {
                this._withDropTarget(this._elementUnderCursor(e), function (target, targetElement) {
                    if (target) {
                        target._drop(extend({}, e, { dropTarget: $(targetElement) }));
                        lastDropTarget = null;
                    }
                });
                this._cancel(this._trigger(DRAGEND, e));
            },
            _cancel: function (isDefaultPrevented) {
                var that = this;
                that._scrollableParent = null;
                this._cursorElement = null;
                clearInterval(this._scrollInterval);
                that._activated = false;
                if (that.hint && !that.dropped) {
                    setTimeout(function () {
                        that.hint.stop(true, true);
                        if (isDefaultPrevented) {
                            that._afterEndHandler();
                        } else {
                            that.hint.animate(that.currentTargetOffset, 'fast', that._afterEndHandler);
                        }
                    }, 0);
                } else {
                    that._afterEnd();
                }
            },
            _trigger: function (eventName, e) {
                var that = this;
                return that.trigger(eventName, extend({}, e.event, {
                    x: e.x,
                    y: e.y,
                    currentTarget: that.currentTarget,
                    initialTarget: e.touch ? e.touch.initialTouch : null,
                    dropTarget: e.dropTarget,
                    elementUnderCursor: e.elementUnderCursor
                }));
            },
            _elementUnderCursor: function (e) {
                var target = elementUnderCursor(e), hint = this.hint;
                if (hint && contains(hint[0], target)) {
                    hint.hide();
                    target = elementUnderCursor(e);
                    if (!target) {
                        target = elementUnderCursor(e);
                    }
                    hint.show();
                }
                return target;
            },
            _withDropTarget: function (element, callback) {
                var result, group = this.options.group, targets = dropTargets[group], areas = dropAreas[group];
                if (targets && targets.length || areas && areas.length) {
                    result = checkTarget(element, targets, areas);
                    if (result) {
                        callback(result.target, result.targetElement);
                    } else {
                        callback();
                    }
                }
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that._afterEnd();
                that.userEvents.destroy();
                this._scrollableParent = null;
                this._cursorElement = null;
                clearInterval(this._scrollInterval);
                that.currentTarget = null;
            },
            _afterEnd: function () {
                var that = this;
                if (that.hint) {
                    that.hint.remove();
                }
                delete draggables[that.options.group];
                that.trigger('destroy');
                that.trigger(HINTDESTROYED);
                $(document).off(KEYUP, that._captureEscape);
            }
        });
        kendo.ui.plugin(DropTarget);
        kendo.ui.plugin(DropTargetArea);
        kendo.ui.plugin(Draggable);
        kendo.TapCapture = TapCapture;
        kendo.containerBoundaries = containerBoundaries;
        extend(kendo.ui, {
            Pane: Pane,
            PaneDimensions: PaneDimensions,
            Movable: Movable
        });
        function scrollableViewPort(element) {
            var root = scrollableRoot()[0], offset, top, left;
            if (element[0] === root) {
                top = root.scrollTop;
                left = root.scrollLeft;
                return {
                    top: top,
                    left: left,
                    bottom: top + $window.height(),
                    right: left + $window.width()
                };
            } else {
                offset = element.offset();
                offset.bottom = offset.top + element.height();
                offset.right = offset.left + element.width();
                return offset;
            }
        }
        function scrollableRoot() {
            return $(kendo.support.browser.edge || kendo.support.browser.safari ? document.body : document.documentElement);
        }
        function findScrollableParent(element) {
            var root = scrollableRoot();
            if (!element || element === document.body || element === document.documentElement) {
                return root;
            }
            var parent = $(element)[0];
            while (parent && !kendo.isScrollable(parent) && parent !== document.body) {
                parent = parent.parentNode;
            }
            if (parent === document.body) {
                return root;
            }
            return $(parent);
        }
        function autoScrollVelocity(mouseX, mouseY, rect) {
            var velocity = {
                x: 0,
                y: 0
            };
            var AUTO_SCROLL_AREA = 50;
            if (mouseX - rect.left < AUTO_SCROLL_AREA) {
                velocity.x = -(AUTO_SCROLL_AREA - (mouseX - rect.left));
            } else if (rect.right - mouseX < AUTO_SCROLL_AREA) {
                velocity.x = AUTO_SCROLL_AREA - (rect.right - mouseX);
            }
            if (mouseY - rect.top < AUTO_SCROLL_AREA) {
                velocity.y = -(AUTO_SCROLL_AREA - (mouseY - rect.top));
            } else if (rect.bottom - mouseY < AUTO_SCROLL_AREA) {
                velocity.y = AUTO_SCROLL_AREA - (rect.bottom - mouseY);
            }
            return velocity;
        }
        kendo.ui.Draggable.utils = {
            autoScrollVelocity: autoScrollVelocity,
            scrollableViewPort: scrollableViewPort,
            findScrollableParent: findScrollableParent
        };
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.scroller', [
        'kendo.fx',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.scroller',
        name: 'Scroller',
        category: 'mobile',
        description: 'The Kendo Mobile Scroller widget enables touch friendly kinetic scrolling for the contents of a given DOM element.',
        depends: [
            'fx',
            'draganddrop'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, mobile = kendo.mobile, fx = kendo.effects, ui = mobile.ui, proxy = $.proxy, extend = $.extend, Widget = ui.Widget, Class = kendo.Class, Movable = kendo.ui.Movable, Pane = kendo.ui.Pane, PaneDimensions = kendo.ui.PaneDimensions, Transition = fx.Transition, Animation = fx.Animation, abs = Math.abs, SNAPBACK_DURATION = 500, SCROLLBAR_OPACITY = 0.7, FRICTION = 0.96, VELOCITY_MULTIPLIER = 10, MAX_VELOCITY = 55, OUT_OF_BOUNDS_FRICTION = 0.5, ANIMATED_SCROLLER_PRECISION = 5, RELEASECLASS = 'km-scroller-release', REFRESHCLASS = 'km-scroller-refresh', PULL = 'pull', CHANGE = 'change', RESIZE = 'resize', SCROLL = 'scroll', MOUSE_WHEEL_ID = 2;
        var ZoomSnapBack = Animation.extend({
            init: function (options) {
                var that = this;
                Animation.fn.init.call(that);
                extend(that, options);
                that.userEvents.bind('gestureend', proxy(that.start, that));
                that.tapCapture.bind('press', proxy(that.cancel, that));
            },
            enabled: function () {
                return this.movable.scale < this.dimensions.minScale;
            },
            done: function () {
                return this.dimensions.minScale - this.movable.scale < 0.01;
            },
            tick: function () {
                var movable = this.movable;
                movable.scaleWith(1.1);
                this.dimensions.rescale(movable.scale);
            },
            onEnd: function () {
                var movable = this.movable;
                movable.scaleTo(this.dimensions.minScale);
                this.dimensions.rescale(movable.scale);
            }
        });
        var DragInertia = Animation.extend({
            init: function (options) {
                var that = this;
                Animation.fn.init.call(that);
                extend(that, options, {
                    transition: new Transition({
                        axis: options.axis,
                        movable: options.movable,
                        onEnd: function () {
                            that._end();
                        }
                    })
                });
                that.tapCapture.bind('press', function () {
                    that.cancel();
                });
                that.userEvents.bind('end', proxy(that.start, that));
                that.userEvents.bind('gestureend', proxy(that.start, that));
                that.userEvents.bind('tap', proxy(that.onEnd, that));
            },
            onCancel: function () {
                this.transition.cancel();
            },
            freeze: function (location) {
                var that = this;
                that.cancel();
                that._moveTo(location);
            },
            onEnd: function () {
                var that = this;
                if (that.paneAxis.outOfBounds()) {
                    that._snapBack();
                } else {
                    that._end();
                }
            },
            done: function () {
                return abs(this.velocity) < 1;
            },
            start: function (e) {
                var that = this, velocity;
                if (!that.dimension.enabled) {
                    return;
                }
                if (that.paneAxis.outOfBounds()) {
                    that._snapBack();
                } else {
                    velocity = e.touch.id === MOUSE_WHEEL_ID ? 0 : e.touch[that.axis].velocity;
                    that.velocity = Math.max(Math.min(velocity * that.velocityMultiplier, MAX_VELOCITY), -MAX_VELOCITY);
                    that.tapCapture.captureNext();
                    Animation.fn.start.call(that);
                }
            },
            tick: function () {
                var that = this, dimension = that.dimension, friction = that.paneAxis.outOfBounds() ? OUT_OF_BOUNDS_FRICTION : that.friction, delta = that.velocity *= friction, location = that.movable[that.axis] + delta;
                if (!that.elastic && dimension.outOfBounds(location)) {
                    location = Math.max(Math.min(location, dimension.max), dimension.min);
                    that.velocity = 0;
                }
                that.movable.moveAxis(that.axis, location);
            },
            _end: function () {
                this.tapCapture.cancelCapture();
                this.end();
            },
            _snapBack: function () {
                var that = this, dimension = that.dimension, snapBack = that.movable[that.axis] > dimension.max ? dimension.max : dimension.min;
                that._moveTo(snapBack);
            },
            _moveTo: function (location) {
                this.transition.moveTo({
                    location: location,
                    duration: SNAPBACK_DURATION,
                    ease: Transition.easeOutExpo
                });
            }
        });
        var AnimatedScroller = Animation.extend({
            init: function (options) {
                var that = this;
                kendo.effects.Animation.fn.init.call(this);
                extend(that, options, {
                    origin: {},
                    destination: {},
                    offset: {}
                });
            },
            tick: function () {
                this._updateCoordinates();
                this.moveTo(this.origin);
            },
            done: function () {
                return abs(this.offset.y) < ANIMATED_SCROLLER_PRECISION && abs(this.offset.x) < ANIMATED_SCROLLER_PRECISION;
            },
            onEnd: function () {
                this.moveTo(this.destination);
                if (this.callback) {
                    this.callback.call();
                }
            },
            setCoordinates: function (from, to) {
                this.offset = {};
                this.origin = from;
                this.destination = to;
            },
            setCallback: function (callback) {
                if (callback && kendo.isFunction(callback)) {
                    this.callback = callback;
                } else {
                    callback = undefined;
                }
            },
            _updateCoordinates: function () {
                this.offset = {
                    x: (this.destination.x - this.origin.x) / 4,
                    y: (this.destination.y - this.origin.y) / 4
                };
                this.origin = {
                    y: this.origin.y + this.offset.y,
                    x: this.origin.x + this.offset.x
                };
            }
        });
        var ScrollBar = Class.extend({
            init: function (options) {
                var that = this, horizontal = options.axis === 'x', element = $('<div class="km-touch-scrollbar km-' + (horizontal ? 'horizontal' : 'vertical') + '-scrollbar" />');
                extend(that, options, {
                    element: element,
                    elementSize: 0,
                    movable: new Movable(element),
                    scrollMovable: options.movable,
                    alwaysVisible: options.alwaysVisible,
                    size: horizontal ? 'width' : 'height'
                });
                that.scrollMovable.bind(CHANGE, proxy(that.refresh, that));
                that.container.append(element);
                if (options.alwaysVisible) {
                    that.show();
                }
            },
            refresh: function () {
                var that = this, axis = that.axis, dimension = that.dimension, paneSize = dimension.size, scrollMovable = that.scrollMovable, sizeRatio = paneSize / dimension.total, position = Math.round(-scrollMovable[axis] * sizeRatio), size = Math.round(paneSize * sizeRatio);
                if (sizeRatio >= 1) {
                    this.element.css('display', 'none');
                } else {
                    this.element.css('display', '');
                }
                if (position + size > paneSize) {
                    size = paneSize - position;
                } else if (position < 0) {
                    size += position;
                    position = 0;
                }
                if (that.elementSize != size) {
                    that.element.css(that.size, size + 'px');
                    that.elementSize = size;
                }
                that.movable.moveAxis(axis, position);
            },
            show: function () {
                this.element.css({
                    opacity: SCROLLBAR_OPACITY,
                    visibility: 'visible'
                });
            },
            hide: function () {
                if (!this.alwaysVisible) {
                    this.element.css({ opacity: 0 });
                }
            }
        });
        var Scroller = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                that._native = that.options.useNative && kendo.support.hasNativeScrolling;
                if (that._native) {
                    element.addClass('km-native-scroller').prepend('<div class="km-scroll-header"/>');
                    extend(that, {
                        scrollElement: element,
                        fixedContainer: element.children().first()
                    });
                    return;
                }
                element.css('overflow', 'hidden').addClass('km-scroll-wrapper').wrapInner('<div class="km-scroll-container"/>').prepend('<div class="km-scroll-header"/>');
                var inner = element.children().eq(1), tapCapture = new kendo.TapCapture(element), movable = new Movable(inner), dimensions = new PaneDimensions({
                        element: inner,
                        container: element,
                        forcedEnabled: that.options.zoom
                    }), avoidScrolling = this.options.avoidScrolling, userEvents = new kendo.UserEvents(element, {
                        touchAction: 'pan-y',
                        fastTap: true,
                        allowSelection: true,
                        preventDragEvent: true,
                        captureUpIfMoved: true,
                        multiTouch: that.options.zoom,
                        supportDoubleTap: that.options.supportDoubleTap,
                        start: function (e) {
                            dimensions.refresh();
                            var velocityX = abs(e.x.velocity), velocityY = abs(e.y.velocity), horizontalSwipe = velocityX * 2 >= velocityY, originatedFromFixedContainer = $.contains(that.fixedContainer[0], e.event.target), verticalSwipe = velocityY * 2 >= velocityX;
                            if (!originatedFromFixedContainer && !avoidScrolling(e) && that.enabled && (dimensions.x.enabled && horizontalSwipe || dimensions.y.enabled && verticalSwipe)) {
                                userEvents.capture();
                            } else {
                                userEvents.cancel();
                            }
                        }
                    }), pane = new Pane({
                        movable: movable,
                        dimensions: dimensions,
                        userEvents: userEvents,
                        elastic: that.options.elastic
                    }), zoomSnapBack = new ZoomSnapBack({
                        movable: movable,
                        dimensions: dimensions,
                        userEvents: userEvents,
                        tapCapture: tapCapture
                    }), animatedScroller = new AnimatedScroller({
                        moveTo: function (coordinates) {
                            that.scrollTo(coordinates.x, coordinates.y);
                        }
                    });
                movable.bind(CHANGE, function () {
                    that.scrollTop = -movable.y;
                    that.scrollLeft = -movable.x;
                    that.trigger(SCROLL, {
                        scrollTop: that.scrollTop,
                        scrollLeft: that.scrollLeft
                    });
                });
                if (that.options.mousewheelScrolling) {
                    element.on('DOMMouseScroll mousewheel', proxy(this, '_wheelScroll'));
                }
                extend(that, {
                    movable: movable,
                    dimensions: dimensions,
                    zoomSnapBack: zoomSnapBack,
                    animatedScroller: animatedScroller,
                    userEvents: userEvents,
                    pane: pane,
                    tapCapture: tapCapture,
                    pulled: false,
                    enabled: true,
                    scrollElement: inner,
                    scrollTop: 0,
                    scrollLeft: 0,
                    fixedContainer: element.children().first()
                });
                that._initAxis('x');
                that._initAxis('y');
                that._wheelEnd = function () {
                    that._wheel = false;
                    that.userEvents.end(0, that._wheelY);
                };
                dimensions.refresh();
                if (that.options.pullToRefresh) {
                    that._initPullToRefresh();
                }
            },
            _wheelScroll: function (e) {
                if (!this._wheel) {
                    this._wheel = true;
                    this._wheelY = 0;
                    this.userEvents.press(0, this._wheelY);
                }
                clearTimeout(this._wheelTimeout);
                this._wheelTimeout = setTimeout(this._wheelEnd, 50);
                var delta = kendo.wheelDeltaY(e);
                if (delta) {
                    this._wheelY += delta;
                    this.userEvents.move(0, this._wheelY);
                }
                e.preventDefault();
            },
            makeVirtual: function () {
                this.dimensions.y.makeVirtual();
            },
            virtualSize: function (min, max) {
                this.dimensions.y.virtualSize(min, max);
            },
            height: function () {
                return this.dimensions.y.size;
            },
            scrollHeight: function () {
                return this.scrollElement[0].scrollHeight;
            },
            scrollWidth: function () {
                return this.scrollElement[0].scrollWidth;
            },
            options: {
                name: 'Scroller',
                zoom: false,
                pullOffset: 140,
                visibleScrollHints: false,
                elastic: true,
                useNative: false,
                mousewheelScrolling: true,
                avoidScrolling: function () {
                    return false;
                },
                pullToRefresh: false,
                messages: {
                    pullTemplate: 'Pull to refresh',
                    releaseTemplate: 'Release to refresh',
                    refreshTemplate: 'Refreshing'
                }
            },
            events: [
                PULL,
                SCROLL,
                RESIZE
            ],
            _resize: function () {
                if (!this._native) {
                    this.contentResized();
                }
            },
            setOptions: function (options) {
                var that = this;
                Widget.fn.setOptions.call(that, options);
                if (options.pullToRefresh) {
                    that._initPullToRefresh();
                }
            },
            reset: function () {
                if (this._native) {
                    this.scrollElement.scrollTop(0);
                } else {
                    this.movable.moveTo({
                        x: 0,
                        y: 0
                    });
                    this._scale(1);
                }
            },
            contentResized: function () {
                this.dimensions.refresh();
                if (this.pane.x.outOfBounds()) {
                    this.movable.moveAxis('x', this.dimensions.x.min);
                }
                if (this.pane.y.outOfBounds()) {
                    this.movable.moveAxis('y', this.dimensions.y.min);
                }
            },
            zoomOut: function () {
                var dimensions = this.dimensions;
                dimensions.refresh();
                this._scale(dimensions.fitScale);
                this.movable.moveTo(dimensions.centerCoordinates());
            },
            enable: function () {
                this.enabled = true;
            },
            disable: function () {
                this.enabled = false;
            },
            scrollTo: function (x, y) {
                if (this._native) {
                    this.scrollElement.scrollLeft(abs(x));
                    this.scrollElement.scrollTop(abs(y));
                } else {
                    this.dimensions.refresh();
                    this.movable.moveTo({
                        x: x,
                        y: y
                    });
                }
            },
            animatedScrollTo: function (x, y, callback) {
                var from, to;
                if (this._native) {
                    this.scrollTo(x, y);
                } else {
                    from = {
                        x: this.movable.x,
                        y: this.movable.y
                    };
                    to = {
                        x: x,
                        y: y
                    };
                    this.animatedScroller.setCoordinates(from, to);
                    this.animatedScroller.setCallback(callback);
                    this.animatedScroller.start();
                }
            },
            pullHandled: function () {
                var that = this;
                that.refreshHint.removeClass(REFRESHCLASS);
                that.hintContainer.html(that.pullTemplate({}));
                that.yinertia.onEnd();
                that.xinertia.onEnd();
                that.userEvents.cancel();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (this.userEvents) {
                    this.userEvents.destroy();
                }
            },
            _scale: function (scale) {
                this.dimensions.rescale(scale);
                this.movable.scaleTo(scale);
            },
            _initPullToRefresh: function () {
                var that = this;
                that.dimensions.y.forceEnabled();
                that.pullTemplate = kendo.template(that.options.messages.pullTemplate);
                that.releaseTemplate = kendo.template(that.options.messages.releaseTemplate);
                that.refreshTemplate = kendo.template(that.options.messages.refreshTemplate);
                that.scrollElement.prepend('<span class="km-scroller-pull"><span class="km-icon"></span><span class="km-loading-left"></span><span class="km-loading-right"></span><span class="km-template">' + that.pullTemplate({}) + '</span></span>');
                that.refreshHint = that.scrollElement.children().first();
                that.hintContainer = that.refreshHint.children('.km-template');
                that.pane.y.bind('change', proxy(that._paneChange, that));
                that.userEvents.bind('end', proxy(that._dragEnd, that));
            },
            _dragEnd: function () {
                var that = this;
                if (!that.pulled) {
                    return;
                }
                that.pulled = false;
                that.refreshHint.removeClass(RELEASECLASS).addClass(REFRESHCLASS);
                that.hintContainer.html(that.refreshTemplate({}));
                that.yinertia.freeze(that.options.pullOffset / 2);
                that.trigger('pull');
            },
            _paneChange: function () {
                var that = this;
                if (that.movable.y / OUT_OF_BOUNDS_FRICTION > that.options.pullOffset) {
                    if (!that.pulled) {
                        that.pulled = true;
                        that.refreshHint.removeClass(REFRESHCLASS).addClass(RELEASECLASS);
                        that.hintContainer.html(that.releaseTemplate({}));
                    }
                } else if (that.pulled) {
                    that.pulled = false;
                    that.refreshHint.removeClass(RELEASECLASS);
                    that.hintContainer.html(that.pullTemplate({}));
                }
            },
            _initAxis: function (axis) {
                var that = this, movable = that.movable, dimension = that.dimensions[axis], tapCapture = that.tapCapture, paneAxis = that.pane[axis], scrollBar = new ScrollBar({
                        axis: axis,
                        movable: movable,
                        dimension: dimension,
                        container: that.element,
                        alwaysVisible: that.options.visibleScrollHints
                    });
                dimension.bind(CHANGE, function () {
                    scrollBar.refresh();
                });
                paneAxis.bind(CHANGE, function () {
                    scrollBar.show();
                });
                that[axis + 'inertia'] = new DragInertia({
                    axis: axis,
                    paneAxis: paneAxis,
                    movable: movable,
                    tapCapture: tapCapture,
                    userEvents: that.userEvents,
                    dimension: dimension,
                    elastic: that.options.elastic,
                    friction: that.options.friction || FRICTION,
                    velocityMultiplier: that.options.velocityMultiplier || VELOCITY_MULTIPLIER,
                    end: function () {
                        scrollBar.hide();
                        that.trigger('scrollEnd', {
                            axis: axis,
                            scrollTop: that.scrollTop,
                            scrollLeft: that.scrollLeft
                        });
                    }
                });
            }
        });
        ui.plugin(Scroller);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.groupable', [
        'kendo.core',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'groupable',
        name: 'Groupable',
        category: 'framework',
        depends: [
            'core',
            'draganddrop'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, outerWidth = kendo._outerWidth, kendoAttr = kendo.attr, extend = $.extend, each = $.each, proxy = $.proxy, isRtl = false, DIR = 'dir', FIELD = 'field', TITLE = 'title', ASCENDING = 'asc', DESCENDING = 'desc', GROUP_SORT = 'group-sort', NS = '.kendoGroupable', CHANGE = 'change', indicatorTmpl = kendo.template('<div class="k-group-indicator" data-#=data.ns#field="${data.field}" data-#=data.ns#title="${data.title || ""}" data-#=data.ns#dir="${data.dir || "asc"}">' + '<a href="\\#" class="k-link">' + '<span class="k-icon k-i-sort-${(data.dir || "asc") == "asc" ? "asc-sm" : "desc-sm"}" title="(sorted ${(data.dir || "asc") == "asc" ? "ascending": "descending"})"></span>' + '${data.title ? data.title: data.field}' + '</a>' + '<a class="k-button k-button-icon k-bare">' + '<span class="k-icon k-i-close"></span>' + '</a>' + '</div>', { useWithBlock: false }), hint = function (target) {
                var title = target.attr(kendo.attr('title'));
                if (title) {
                    title = kendo.htmlEncode(title);
                }
                return $('<div class="k-header k-group-clue k-drag-clue" />').html(title || target.attr(kendo.attr('field'))).prepend('<span class="k-icon k-drag-status k-i-cancel" />');
            }, dropCue = $('<div class="k-grouping-dropclue"/>');
        var Groupable = Widget.extend({
            init: function (element, options) {
                var that = this, group = kendo.guid(), intializePositions = proxy(that._intializePositions, that), draggable, horizontalCuePosition, dropCuePositions = that._dropCuePositions = [];
                Widget.fn.init.call(that, element, options);
                isRtl = kendo.support.isRtl(element);
                horizontalCuePosition = isRtl ? 'right' : 'left';
                that.draggable = draggable = that.options.draggable || new kendo.ui.Draggable(that.element, {
                    filter: that.options.draggableElements,
                    hint: hint,
                    group: group
                });
                that.groupContainer = $(that.options.groupContainer, that.element).kendoDropTarget({
                    group: draggable.options.group,
                    dragenter: function (e) {
                        if (that._canDrag(e.draggable.currentTarget)) {
                            e.draggable.hint.find('.k-drag-status').removeClass('k-i-cancel').addClass('k-i-plus');
                            dropCue.css(horizontalCuePosition, 0).appendTo(that.groupContainer);
                        }
                    },
                    dragleave: function (e) {
                        e.draggable.hint.find('.k-drag-status').removeClass('k-i-plus').addClass('k-i-cancel');
                        dropCue.remove();
                    },
                    drop: function (e) {
                        var targetElement = e.draggable.currentTarget, field = targetElement.attr(kendo.attr('field')), title = targetElement.attr(kendo.attr('title')), sourceIndicator = that.indicator(field), dropCuePositions = that._dropCuePositions, lastCuePosition = dropCuePositions[dropCuePositions.length - 1], position;
                        var sortOptions = extend({}, that.options.sort, targetElement.data(GROUP_SORT));
                        var dir = sortOptions.dir;
                        if (!targetElement.hasClass('k-group-indicator') && !that._canDrag(targetElement)) {
                            return;
                        }
                        if (lastCuePosition) {
                            position = that._dropCuePosition(kendo.getOffset(dropCue).left + parseInt(lastCuePosition.element.css('marginLeft'), 10) * (isRtl ? -1 : 1) + parseInt(lastCuePosition.element.css('marginRight'), 10));
                            if (position && that._canDrop($(sourceIndicator), position.element, position.left)) {
                                if (position.before) {
                                    position.element.before(sourceIndicator || that.buildIndicator(field, title, dir));
                                } else {
                                    position.element.after(sourceIndicator || that.buildIndicator(field, title, dir));
                                }
                                that._setIndicatorSortOptions(field, sortOptions);
                                that._change();
                            }
                        } else {
                            that.groupContainer.empty();
                            that.groupContainer.append(that.buildIndicator(field, title, dir));
                            that._setIndicatorSortOptions(field, sortOptions);
                            that._change();
                        }
                    }
                }).kendoDraggable({
                    filter: 'div.k-group-indicator',
                    hint: hint,
                    group: draggable.options.group,
                    dragcancel: proxy(that._dragCancel, that),
                    dragstart: function (e) {
                        var element = e.currentTarget, marginLeft = parseInt(element.css('marginLeft'), 10), elementPosition = element.position(), left = isRtl ? elementPosition.left - marginLeft : elementPosition.left + outerWidth(element);
                        intializePositions();
                        dropCue.css('left', left).appendTo(that.groupContainer);
                        this.hint.find('.k-drag-status').removeClass('k-i-cancel').addClass('k-i-plus');
                    },
                    dragend: function () {
                        that._dragEnd(this);
                    },
                    drag: proxy(that._drag, that)
                }).on('click' + NS, '.k-button', function (e) {
                    e.preventDefault();
                    that._removeIndicator($(this).parent());
                }).on('click' + NS, '.k-link', function (e) {
                    var indicator = $(this).parent();
                    var newDir = indicator.attr(kendoAttr(DIR)) === ASCENDING ? DESCENDING : ASCENDING;
                    indicator.attr(kendoAttr(DIR), newDir);
                    that._change();
                    e.preventDefault();
                });
                draggable.bind([
                    'dragend',
                    'dragcancel',
                    'dragstart',
                    'drag'
                ], {
                    dragend: function () {
                        that._dragEnd(this);
                    },
                    dragcancel: proxy(that._dragCancel, that),
                    dragstart: function (e) {
                        var element, marginRight, left;
                        if (!that.options.allowDrag && !that._canDrag(e.currentTarget)) {
                            e.preventDefault();
                            return;
                        }
                        intializePositions();
                        if (dropCuePositions.length) {
                            element = dropCuePositions[dropCuePositions.length - 1].element;
                            marginRight = parseInt(element.css('marginRight'), 10);
                            left = element.position().left + outerWidth(element) + marginRight;
                        } else {
                            left = 0;
                        }
                    },
                    drag: proxy(that._drag, that)
                });
                that.dataSource = that.options.dataSource;
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                } else {
                    that._refreshHandler = proxy(that.refresh, that);
                }
                if (that.dataSource) {
                    that.dataSource.bind('change', that._refreshHandler);
                    that.refresh();
                }
            },
            refresh: function () {
                var that = this, dataSource = that.dataSource;
                var groups = dataSource.group() || [];
                var fieldAttr = kendoAttr(FIELD);
                var titleAttr = kendoAttr(TITLE);
                var indicatorHtml;
                if (that.groupContainer) {
                    that.groupContainer.empty();
                    each(groups, function (index, group) {
                        var field = group.field;
                        var dir = group.dir;
                        var element = that.element.find(that.options.filter).filter(function () {
                            return $(this).attr(fieldAttr) === field;
                        });
                        indicatorHtml = that.buildIndicator(field, element.attr(titleAttr), dir);
                        that.groupContainer.append(indicatorHtml);
                        that._setIndicatorSortOptions(field, extend({}, that.options.sort, {
                            dir: dir,
                            compare: group.compare
                        }));
                    });
                }
                that._invalidateGroupContainer();
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.groupContainer.off(NS);
                if (that.groupContainer.data('kendoDropTarget')) {
                    that.groupContainer.data('kendoDropTarget').destroy();
                }
                if (that.groupContainer.data('kendoDraggable')) {
                    that.groupContainer.data('kendoDraggable').destroy();
                }
                if (!that.options.draggable) {
                    that.draggable.destroy();
                }
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind('change', that._refreshHandler);
                    that._refreshHandler = null;
                }
                that.groupContainer = that.element = that.draggable = null;
            },
            events: ['change'],
            options: {
                name: 'Groupable',
                filter: 'th',
                draggableElements: 'th',
                messages: { empty: 'Drag a column header and drop it here to group by that column' },
                sort: {
                    dir: ASCENDING,
                    compare: null
                }
            },
            indicator: function (field) {
                var indicators = $('.k-group-indicator', this.groupContainer);
                return $.grep(indicators, function (item) {
                    return $(item).attr(kendo.attr('field')) === field;
                })[0];
            },
            buildIndicator: function (field, title, dir) {
                var that = this;
                var indicator = indicatorTmpl({
                    ns: kendo.ns,
                    field: field.replace(/"/g, '\''),
                    title: title,
                    dir: dir || (that.options.sort || {}).dir || ASCENDING
                });
                return indicator;
            },
            _setIndicatorSortOptions: function (field, options) {
                var indicator = $(this.indicator(field));
                indicator.data(GROUP_SORT, options);
            },
            aggregates: function () {
                var that = this;
                var names;
                var idx;
                var length;
                return that.element.find(that.options.filter).map(function () {
                    var cell = $(this), aggregate = cell.attr(kendo.attr('aggregates')), member = cell.attr(kendo.attr('field'));
                    if (aggregate && aggregate !== '') {
                        names = aggregate.split(',');
                        aggregate = [];
                        for (idx = 0, length = names.length; idx < length; idx++) {
                            aggregate.push({
                                field: member,
                                aggregate: names[idx]
                            });
                        }
                    }
                    return aggregate;
                }).toArray();
            },
            descriptors: function () {
                var that = this, indicators = $('.k-group-indicator', that.groupContainer), field, aggregates = that.aggregates();
                return $.map(indicators, function (item) {
                    item = $(item);
                    field = item.attr(kendo.attr('field'));
                    var sortOptions = that.options.sort || {};
                    var indicatorSortOptions = item.data(GROUP_SORT) || {};
                    return {
                        field: field,
                        dir: item.attr(kendo.attr('dir')),
                        aggregates: aggregates || [],
                        compare: indicatorSortOptions.compare || sortOptions.compare
                    };
                });
            },
            _removeIndicator: function (indicator) {
                var that = this;
                indicator.off();
                indicator.removeData();
                indicator.remove();
                that._invalidateGroupContainer();
                that._change();
            },
            _change: function () {
                var that = this;
                if (that.dataSource) {
                    var descriptors = that.descriptors();
                    if (that.trigger('change', { groups: descriptors })) {
                        that.refresh();
                        return;
                    }
                    that.dataSource.group(descriptors);
                }
            },
            _dropCuePosition: function (position) {
                var dropCuePositions = this._dropCuePositions;
                if (!dropCue.is(':visible') || dropCuePositions.length === 0) {
                    return;
                }
                position = Math.ceil(position);
                var lastCuePosition = dropCuePositions[dropCuePositions.length - 1], left = lastCuePosition.left, right = lastCuePosition.right, marginLeft = parseInt(lastCuePosition.element.css('marginLeft'), 10), marginRight = parseInt(lastCuePosition.element.css('marginRight'), 10);
                if (position >= right && !isRtl || position < left && isRtl) {
                    position = {
                        left: lastCuePosition.element.position().left + (!isRtl ? outerWidth(lastCuePosition.element) + marginRight : -marginLeft),
                        element: lastCuePosition.element,
                        before: false
                    };
                } else {
                    position = $.grep(dropCuePositions, function (item) {
                        return item.left <= position && position <= item.right || isRtl && position > item.right;
                    })[0];
                    if (position) {
                        position = {
                            left: isRtl ? position.element.position().left + outerWidth(position.element) + marginRight : position.element.position().left - marginLeft,
                            element: position.element,
                            before: true
                        };
                    }
                }
                return position;
            },
            _drag: function (event) {
                var position = this._dropCuePosition(event.x.location);
                if (position) {
                    dropCue.css({
                        left: position.left,
                        right: 'auto'
                    });
                }
            },
            _canDrag: function (element) {
                var field = element.attr(kendo.attr('field'));
                return element.attr(kendo.attr('groupable')) != 'false' && field && (element.hasClass('k-group-indicator') || !this.indicator(field));
            },
            _canDrop: function (source, target, position) {
                var next = source.next(), result = source[0] !== target[0] && (!next[0] || target[0] !== next[0] || (!isRtl && position > next.position().left || isRtl && position < next.position().left));
                return result;
            },
            _dragEnd: function (draggable) {
                var that = this, field = draggable.currentTarget.attr(kendo.attr('field')), sourceIndicator = that.indicator(field);
                if (draggable !== that.options.draggable && !draggable.dropped && sourceIndicator) {
                    that._removeIndicator($(sourceIndicator));
                }
                that._dragCancel();
            },
            _dragCancel: function () {
                dropCue.remove();
                this._dropCuePositions = [];
            },
            _intializePositions: function () {
                var that = this, indicators = $('.k-group-indicator', that.groupContainer), left;
                that._dropCuePositions = $.map(indicators, function (item) {
                    item = $(item);
                    left = kendo.getOffset(item).left;
                    return {
                        left: parseInt(left, 10),
                        right: parseInt(left + outerWidth(item), 10),
                        element: item
                    };
                });
            },
            _invalidateGroupContainer: function () {
                var groupContainer = this.groupContainer;
                if (groupContainer && groupContainer.is(':empty')) {
                    groupContainer.html(this.options.messages.empty);
                }
            }
        });
        kendo.ui.plugin(Groupable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.reorderable', [
        'kendo.core',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'reorderable',
        name: 'Reorderable',
        category: 'framework',
        depends: [
            'core',
            'draganddrop'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, getOffset = kendo.getOffset, Widget = kendo.ui.Widget, CHANGE = 'change', KREORDERABLE = 'k-reorderable';
        function toggleHintClass(hint, denied) {
            hint = $(hint);
            if (denied) {
                hint.find('.k-drag-status').removeClass('k-i-plus').addClass('k-i-cancel');
            } else {
                hint.find('.k-drag-status').removeClass('k-i-cancel').addClass('k-i-plus');
            }
        }
        var Reorderable = Widget.extend({
            init: function (element, options) {
                var that = this, draggable, group = kendo.guid() + '-reorderable';
                Widget.fn.init.call(that, element, options);
                element = that.element.addClass(KREORDERABLE);
                options = that.options;
                that.draggable = draggable = options.draggable || new kendo.ui.Draggable(element, {
                    group: group,
                    autoScroll: true,
                    filter: options.filter,
                    hint: options.hint
                });
                that.reorderDropCue = $('<div class="k-reorder-cue"></div></div>');
                element.find(draggable.options.filter).kendoDropTarget({
                    group: draggable.options.group,
                    dragenter: function (e) {
                        if (!that._draggable) {
                            return;
                        }
                        var dropTarget = this.element, offset;
                        var denied = !that._dropTargetAllowed(dropTarget) || that._isLastDraggable();
                        toggleHintClass(e.draggable.hint, denied);
                        if (!denied) {
                            offset = getOffset(dropTarget);
                            var left = offset.left;
                            if (options.inSameContainer && !options.inSameContainer({
                                    source: dropTarget,
                                    target: that._draggable,
                                    sourceIndex: that._index(dropTarget),
                                    targetIndex: that._index(that._draggable)
                                })) {
                                that._dropTarget = dropTarget;
                            } else {
                                if (that._index(dropTarget) > that._index(that._draggable)) {
                                    left += outerWidth(dropTarget);
                                }
                            }
                            that.reorderDropCue.css({
                                height: outerHeight(dropTarget),
                                top: offset.top,
                                left: left
                            }).appendTo(document.body);
                        }
                    },
                    dragleave: function (e) {
                        toggleHintClass(e.draggable.hint, true);
                        that.reorderDropCue.remove();
                        that._dropTarget = null;
                    },
                    drop: function () {
                        that._dropTarget = null;
                        if (!that._draggable) {
                            return;
                        }
                        var dropTarget = this.element;
                        var draggable = that._draggable;
                        if (that._dropTargetAllowed(dropTarget) && !that._isLastDraggable()) {
                            that.trigger(CHANGE, {
                                element: that._draggable,
                                target: dropTarget,
                                oldIndex: that._index(draggable),
                                newIndex: that._index(dropTarget),
                                position: getOffset(that.reorderDropCue).left > getOffset(dropTarget).left ? 'after' : 'before'
                            });
                        }
                    }
                });
                draggable.bind([
                    'dragcancel',
                    'dragend',
                    'dragstart',
                    'drag'
                ], {
                    dragcancel: function () {
                        that.reorderDropCue.remove();
                        that._draggable = null;
                        that._elements = null;
                    },
                    dragend: function () {
                        that.reorderDropCue.remove();
                        that._draggable = null;
                        that._elements = null;
                    },
                    dragstart: function (e) {
                        that._draggable = e.currentTarget;
                        that._elements = that.element.find(that.draggable.options.filter);
                    },
                    drag: function (e) {
                        if (!that._dropTarget || this.hint.find('.k-drag-status').hasClass('k-i-cancel')) {
                            return;
                        }
                        var dropStartOffset = getOffset(that._dropTarget).left;
                        var width = outerWidth(that._dropTarget);
                        if (e.pageX > dropStartOffset + width / 2) {
                            that.reorderDropCue.css({ left: dropStartOffset + width });
                        } else {
                            that.reorderDropCue.css({ left: dropStartOffset });
                        }
                    }
                });
            },
            options: {
                name: 'Reorderable',
                filter: '*'
            },
            events: [CHANGE],
            _isLastDraggable: function () {
                var inSameContainer = this.options.inSameContainer, draggable = this._draggable[0], elements = this._elements.get(), found = false, item;
                if (!inSameContainer) {
                    return false;
                }
                while (!found && elements.length > 0) {
                    item = elements.pop();
                    found = draggable !== item && inSameContainer({
                        source: draggable,
                        target: item,
                        sourceIndex: this._index(draggable),
                        targetIndex: this._index(item)
                    });
                }
                return !found;
            },
            _dropTargetAllowed: function (dropTarget) {
                var inSameContainer = this.options.inSameContainer, dragOverContainers = this.options.dragOverContainers, draggable = this._draggable;
                if (draggable[0] === dropTarget[0]) {
                    return false;
                }
                if (!inSameContainer || !dragOverContainers) {
                    return true;
                }
                if (inSameContainer({
                        source: draggable,
                        target: dropTarget,
                        sourceIndex: this._index(draggable),
                        targetIndex: this._index(dropTarget)
                    })) {
                    return true;
                }
                return dragOverContainers(this._index(draggable), this._index(dropTarget));
            },
            _index: function (element) {
                return this._elements.index(element);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.element.find(that.draggable.options.filter).each(function () {
                    var item = $(this);
                    if (item.data('kendoDropTarget')) {
                        item.data('kendoDropTarget').destroy();
                    }
                });
                if (that.draggable) {
                    that.draggable.destroy();
                    that.draggable.element = that.draggable = null;
                }
                that.elements = that.reorderDropCue = that._elements = that._draggable = null;
            }
        });
        kendo.ui.plugin(Reorderable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.resizable', [
        'kendo.core',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'resizable',
        name: 'Resizable',
        category: 'framework',
        depends: [
            'core',
            'draganddrop'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, proxy = $.proxy, isFunction = kendo.isFunction, extend = $.extend, HORIZONTAL = 'horizontal', VERTICAL = 'vertical', START = 'start', RESIZE = 'resize', RESIZEEND = 'resizeend';
        var Resizable = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.orientation = that.options.orientation.toLowerCase() != VERTICAL ? HORIZONTAL : VERTICAL;
                that._positionMouse = that.orientation == HORIZONTAL ? 'x' : 'y';
                that._position = that.orientation == HORIZONTAL ? 'left' : 'top';
                that._sizingDom = that.orientation == HORIZONTAL ? 'outerWidth' : 'outerHeight';
                that.draggable = new ui.Draggable(options.draggableElement || element, {
                    distance: 1,
                    filter: options.handle,
                    drag: proxy(that._resize, that),
                    dragcancel: proxy(that._cancel, that),
                    dragstart: proxy(that._start, that),
                    dragend: proxy(that._stop, that)
                });
                that.userEvents = that.draggable.userEvents;
            },
            events: [
                RESIZE,
                RESIZEEND,
                START
            ],
            options: {
                name: 'Resizable',
                orientation: HORIZONTAL
            },
            resize: function () {
            },
            _max: function (e) {
                var that = this, hintSize = that.hint ? that.hint[that._sizingDom]() : 0, size = that.options.max;
                return isFunction(size) ? size(e) : size !== undefined ? that._initialElementPosition + size - hintSize : size;
            },
            _min: function (e) {
                var that = this, size = that.options.min;
                return isFunction(size) ? size(e) : size !== undefined ? that._initialElementPosition + size : size;
            },
            _start: function (e) {
                var that = this, hint = that.options.hint, el = $(e.currentTarget);
                that._initialElementPosition = el.position()[that._position];
                that._initialMousePosition = e[that._positionMouse].startLocation;
                if (hint) {
                    that.hint = isFunction(hint) ? $(hint(el)) : hint;
                    that.hint.css({ position: 'absolute' }).css(that._position, that._initialElementPosition).appendTo(that.element);
                }
                that.trigger(START, e);
                that._maxPosition = that._max(e);
                that._minPosition = that._min(e);
                $(document.body).css('cursor', el.css('cursor'));
            },
            _resize: function (e) {
                var that = this, maxPosition = that._maxPosition, minPosition = that._minPosition, currentPosition = that._initialElementPosition + (e[that._positionMouse].location - that._initialMousePosition), position;
                position = minPosition !== undefined ? Math.max(minPosition, currentPosition) : currentPosition;
                that.position = position = maxPosition !== undefined ? Math.min(maxPosition, position) : position;
                if (that.hint) {
                    that.hint.toggleClass(that.options.invalidClass || '', position == maxPosition || position == minPosition).css(that._position, position);
                }
                that.resizing = true;
                that.trigger(RESIZE, extend(e, { position: position }));
            },
            _stop: function (e) {
                var that = this;
                if (that.hint) {
                    that.hint.remove();
                }
                that.resizing = false;
                that.trigger(RESIZEEND, extend(e, { position: that.position }));
                $(document.body).css('cursor', '');
            },
            _cancel: function (e) {
                var that = this;
                if (that.hint) {
                    that.position = undefined;
                    that.hint.css(that._position, that._initialElementPosition);
                    that._stop(e);
                }
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                if (that.draggable) {
                    that.draggable.destroy();
                }
            },
            press: function (target) {
                if (!target) {
                    return;
                }
                var position = target.position(), that = this;
                that.userEvents.press(position.left, position.top, target[0]);
                that.targetPosition = position;
                that.target = target;
            },
            move: function (delta) {
                var that = this, orientation = that._position, position = that.targetPosition, current = that.position;
                if (current === undefined) {
                    current = position[orientation];
                }
                position[orientation] = current + delta;
                that.userEvents.move(position.left, position.top);
            },
            end: function () {
                this.userEvents.end();
                this.target = this.position = undefined;
            }
        });
        kendo.ui.plugin(Resizable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.sortable', ['kendo.draganddrop'], f);
}(function () {
    var __meta__ = {
        id: 'sortable',
        name: 'Sortable',
        category: 'framework',
        depends: ['draganddrop']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, START = 'start', BEFORE_MOVE = 'beforeMove', MOVE = 'move', END = 'end', CHANGE = 'change', CANCEL = 'cancel', ACTION_SORT = 'sort', ACTION_REMOVE = 'remove', ACTION_RECEIVE = 'receive', DEFAULT_FILTER = '>*', MISSING_INDEX = -1;
        function containsOrEqualTo(parent, child) {
            try {
                return $.contains(parent, child) || parent == child;
            } catch (e) {
                return false;
            }
        }
        function defaultHint(element) {
            return element.clone();
        }
        function defaultPlaceholder(element) {
            return element.clone().removeAttr('id').css('visibility', 'hidden');
        }
        var Sortable = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                if (!that.options.placeholder) {
                    that.options.placeholder = defaultPlaceholder;
                }
                if (!that.options.hint) {
                    that.options.hint = defaultHint;
                }
                that.draggable = that._createDraggable();
            },
            events: [
                START,
                BEFORE_MOVE,
                MOVE,
                END,
                CHANGE,
                CANCEL
            ],
            options: {
                name: 'Sortable',
                hint: null,
                placeholder: null,
                filter: DEFAULT_FILTER,
                holdToDrag: false,
                disabled: null,
                container: null,
                connectWith: null,
                handler: null,
                cursorOffset: null,
                axis: null,
                ignore: null,
                autoScroll: false,
                cursor: 'auto',
                moveOnDragEnter: false
            },
            destroy: function () {
                this.draggable.destroy();
                Widget.fn.destroy.call(this);
            },
            _createDraggable: function () {
                var that = this, element = that.element, options = that.options;
                return new kendo.ui.Draggable(element, {
                    filter: options.filter,
                    hint: kendo.isFunction(options.hint) ? options.hint : $(options.hint),
                    holdToDrag: options.holdToDrag,
                    container: options.container ? $(options.container) : null,
                    cursorOffset: options.cursorOffset,
                    axis: options.axis,
                    ignore: options.ignore,
                    autoScroll: options.autoScroll,
                    dragstart: $.proxy(that._dragstart, that),
                    dragcancel: $.proxy(that._dragcancel, that),
                    drag: $.proxy(that._drag, that),
                    dragend: $.proxy(that._dragend, that)
                });
            },
            _dragstart: function (e) {
                var draggedElement = this.draggedElement = e.currentTarget, disabled = this.options.disabled, handler = this.options.handler, _placeholder = this.options.placeholder, placeholder = this.placeholder = kendo.isFunction(_placeholder) ? $(_placeholder.call(this, draggedElement)) : $(_placeholder);
                if (disabled && draggedElement.is(disabled)) {
                    e.preventDefault();
                } else if (handler && !$(e.initialTarget).is(handler)) {
                    e.preventDefault();
                } else {
                    if (this.trigger(START, {
                            item: draggedElement,
                            draggableEvent: e
                        })) {
                        e.preventDefault();
                    } else {
                        draggedElement.css('display', 'none');
                        draggedElement.before(placeholder);
                        this._setCursor();
                    }
                }
            },
            _dragcancel: function () {
                this._cancel();
                this.trigger(CANCEL, { item: this.draggedElement });
                this._resetCursor();
            },
            _drag: function (e) {
                var draggedElement = this.draggedElement, target = this._findTarget(e), targetCenter, cursorOffset = {
                        left: e.x.location,
                        top: e.y.location
                    }, offsetDelta, axisDelta = {
                        x: e.x.delta,
                        y: e.y.delta
                    }, direction, sibling, getSibling, axis = this.options.axis, moveOnDragEnter = this.options.moveOnDragEnter, eventData = {
                        item: draggedElement,
                        list: this,
                        draggableEvent: e
                    };
                if (axis === 'x' || axis === 'y') {
                    this._movementByAxis(axis, cursorOffset, axisDelta[axis], eventData);
                    return;
                }
                if (target) {
                    targetCenter = this._getElementCenter(target.element);
                    offsetDelta = {
                        left: Math.round(cursorOffset.left - targetCenter.left),
                        top: Math.round(cursorOffset.top - targetCenter.top)
                    };
                    $.extend(eventData, { target: target.element });
                    if (target.appendToBottom) {
                        this._movePlaceholder(target, null, eventData);
                        return;
                    }
                    if (target.appendAfterHidden) {
                        this._movePlaceholder(target, 'next', eventData);
                    }
                    if (this._isFloating(target.element)) {
                        if (axisDelta.x < 0 && moveOnDragEnter || !moveOnDragEnter && offsetDelta.left < 0) {
                            direction = 'prev';
                        } else if (axisDelta.x > 0 && moveOnDragEnter || !moveOnDragEnter && offsetDelta.left > 0) {
                            direction = 'next';
                        }
                    } else {
                        if (axisDelta.y < 0 && moveOnDragEnter || !moveOnDragEnter && offsetDelta.top < 0) {
                            direction = 'prev';
                        } else if (axisDelta.y > 0 && moveOnDragEnter || !moveOnDragEnter && offsetDelta.top > 0) {
                            direction = 'next';
                        }
                    }
                    if (direction) {
                        getSibling = direction === 'prev' ? jQuery.fn.prev : jQuery.fn.next;
                        sibling = getSibling.call(target.element);
                        while (sibling.length && !sibling.is(':visible')) {
                            sibling = getSibling.call(sibling);
                        }
                        if (sibling[0] != this.placeholder[0]) {
                            this._movePlaceholder(target, direction, eventData);
                        }
                    }
                }
            },
            _dragend: function (e) {
                var placeholder = this.placeholder, draggedElement = this.draggedElement, draggedIndex = this.indexOf(draggedElement), placeholderIndex = this.indexOf(placeholder), connectWith = this.options.connectWith, connectedList, isDefaultPrevented, eventData, connectedListEventData;
                this._resetCursor();
                eventData = {
                    action: ACTION_SORT,
                    item: draggedElement,
                    oldIndex: draggedIndex,
                    newIndex: placeholderIndex,
                    draggableEvent: e
                };
                if (placeholderIndex >= 0) {
                    isDefaultPrevented = this.trigger(END, eventData);
                } else {
                    connectedList = placeholder.parents(connectWith).getKendoSortable();
                    eventData.action = ACTION_REMOVE;
                    connectedListEventData = $.extend({}, eventData, {
                        action: ACTION_RECEIVE,
                        oldIndex: MISSING_INDEX,
                        newIndex: connectedList.indexOf(placeholder)
                    });
                    isDefaultPrevented = !(!this.trigger(END, eventData) && !connectedList.trigger(END, connectedListEventData));
                }
                if (isDefaultPrevented || placeholderIndex === draggedIndex) {
                    this._cancel();
                    return;
                }
                placeholder.replaceWith(draggedElement);
                draggedElement.show();
                this.draggable.dropped = true;
                eventData = {
                    action: this.indexOf(draggedElement) != MISSING_INDEX ? ACTION_SORT : ACTION_REMOVE,
                    item: draggedElement,
                    oldIndex: draggedIndex,
                    newIndex: this.indexOf(draggedElement),
                    draggableEvent: e
                };
                this.trigger(CHANGE, eventData);
                if (connectedList) {
                    connectedListEventData = $.extend({}, eventData, {
                        action: ACTION_RECEIVE,
                        oldIndex: MISSING_INDEX,
                        newIndex: connectedList.indexOf(draggedElement)
                    });
                    connectedList.trigger(CHANGE, connectedListEventData);
                }
            },
            _findTarget: function (e) {
                var element = this._findElementUnderCursor(e), items, connectWith = this.options.connectWith, node;
                if ($.contains(this.element[0], element)) {
                    items = this.items();
                    node = items.filter(element)[0] || items.has(element)[0];
                    return node ? {
                        element: $(node),
                        sortable: this
                    } : null;
                } else if (this.element[0] == element && this._isEmpty()) {
                    return {
                        element: this.element,
                        sortable: this,
                        appendToBottom: true
                    };
                } else if (this.element[0] == element && this._isLastHidden()) {
                    node = this.items().eq(0);
                    return {
                        element: node,
                        sortable: this,
                        appendAfterHidden: true
                    };
                } else if (connectWith) {
                    return this._searchConnectedTargets(element, e);
                }
            },
            _findElementUnderCursor: function (e) {
                var elementUnderCursor = kendo.elementUnderCursor(e), draggable = e.sender;
                if (containsOrEqualTo(draggable.hint[0], elementUnderCursor)) {
                    draggable.hint.hide();
                    elementUnderCursor = kendo.elementUnderCursor(e);
                    if (!elementUnderCursor) {
                        elementUnderCursor = kendo.elementUnderCursor(e);
                    }
                    draggable.hint.show();
                }
                return elementUnderCursor;
            },
            _searchConnectedTargets: function (element, e) {
                var connected = $(this.options.connectWith), sortableInstance, items, node;
                for (var i = 0; i < connected.length; i++) {
                    sortableInstance = connected.eq(i).getKendoSortable();
                    if ($.contains(connected[i], element)) {
                        if (sortableInstance) {
                            items = sortableInstance.items();
                            node = items.filter(element)[0] || items.has(element)[0];
                            if (node) {
                                sortableInstance.placeholder = this.placeholder;
                                return {
                                    element: $(node),
                                    sortable: sortableInstance
                                };
                            } else {
                                return null;
                            }
                        }
                    } else if (connected[i] == element) {
                        if (sortableInstance && sortableInstance._isEmpty()) {
                            return {
                                element: connected.eq(i),
                                sortable: sortableInstance,
                                appendToBottom: true
                            };
                        } else if (this._isCursorAfterLast(sortableInstance, e)) {
                            node = sortableInstance.items().last();
                            return {
                                element: node,
                                sortable: sortableInstance
                            };
                        }
                    }
                }
            },
            _isCursorAfterLast: function (sortable, e) {
                var lastItem = sortable.items().last(), cursorOffset = {
                        left: e.x.location,
                        top: e.y.location
                    }, lastItemOffset, delta;
                lastItemOffset = kendo.getOffset(lastItem);
                lastItemOffset.top += outerHeight(lastItem);
                lastItemOffset.left += outerWidth(lastItem);
                if (this._isFloating(lastItem)) {
                    delta = lastItemOffset.left - cursorOffset.left;
                } else {
                    delta = lastItemOffset.top - cursorOffset.top;
                }
                return delta < 0 ? true : false;
            },
            _movementByAxis: function (axis, cursorOffset, delta, eventData) {
                var cursorPosition = axis === 'x' ? cursorOffset.left : cursorOffset.top, target = delta < 0 ? this.placeholder.prev() : this.placeholder.next(), items = this.items(), targetCenter;
                if (target.length && !target.is(':visible')) {
                    target = delta < 0 ? target.prev() : target.next();
                }
                if (!items.filter(target).length) {
                    return;
                }
                $.extend(eventData, { target: target });
                targetCenter = this._getElementCenter(target);
                if (targetCenter) {
                    targetCenter = axis === 'x' ? targetCenter.left : targetCenter.top;
                }
                if (target.length && delta < 0 && cursorPosition - targetCenter < 0) {
                    this._movePlaceholder({
                        element: target,
                        sortable: this
                    }, 'prev', eventData);
                } else if (target.length && delta > 0 && cursorPosition - targetCenter > 0) {
                    this._movePlaceholder({
                        element: target,
                        sortable: this
                    }, 'next', eventData);
                }
            },
            _movePlaceholder: function (target, direction, eventData) {
                var placeholder = this.placeholder;
                if (!target.sortable.trigger(BEFORE_MOVE, eventData)) {
                    if (!direction) {
                        target.element.append(placeholder);
                    } else if (direction === 'prev') {
                        target.element.before(placeholder);
                    } else if (direction === 'next') {
                        target.element.after(placeholder);
                    }
                    target.sortable.trigger(MOVE, eventData);
                }
            },
            _setCursor: function () {
                var cursor = this.options.cursor, body;
                if (cursor && cursor !== 'auto') {
                    body = $(document.body);
                    this._originalCursorType = body.css('cursor');
                    body.css({ 'cursor': cursor });
                    if (!this._cursorStylesheet) {
                        this._cursorStylesheet = $('<style>* { cursor: ' + cursor + ' !important; }</style>');
                    }
                    this._cursorStylesheet.appendTo(body);
                }
            },
            _resetCursor: function () {
                if (this._originalCursorType) {
                    $(document.body).css('cursor', this._originalCursorType);
                    this._originalCursorType = null;
                    this._cursorStylesheet.remove();
                }
            },
            _getElementCenter: function (element) {
                var center = element.length ? kendo.getOffset(element) : null;
                if (center) {
                    center.top += outerHeight(element) / 2;
                    center.left += outerWidth(element) / 2;
                }
                return center;
            },
            _isFloating: function (item) {
                return /left|right/.test(item.css('float')) || /inline|table-cell/.test(item.css('display'));
            },
            _cancel: function () {
                this.draggedElement.show();
                this.placeholder.remove();
            },
            _items: function () {
                var filter = this.options.filter, items;
                if (filter) {
                    items = this.element.find(filter);
                } else {
                    items = this.element.children();
                }
                return items;
            },
            indexOf: function (element) {
                var items = this._items(), placeholder = this.placeholder, draggedElement = this.draggedElement;
                if (placeholder && element[0] == placeholder[0]) {
                    return items.not(draggedElement).index(element);
                } else {
                    return items.not(placeholder).index(element);
                }
            },
            items: function () {
                var placeholder = this.placeholder, items = this._items();
                if (placeholder) {
                    items = items.not(placeholder);
                }
                return items;
            },
            _isEmpty: function () {
                return !this.items().length;
            },
            _isLastHidden: function () {
                return this.items().length === 1 && this.items().is(':hidden');
            }
        });
        kendo.ui.plugin(Sortable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.selectable', [
        'kendo.core',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'selectable',
        name: 'Selectable',
        category: 'framework',
        depends: [
            'core',
            'userevents'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, proxy = $.proxy, abs = Math.abs, ARIASELECTED = 'aria-selected', SELECTED = 'k-state-selected', ACTIVE = 'k-state-selecting', SELECTABLE = 'k-selectable', CHANGE = 'change', NS = '.kendoSelectable', UNSELECT = 'unselect', UNSELECTING = 'k-state-unselecting', INPUTSELECTOR = 'input,a,textarea,.k-multiselect-wrap,select,button,.k-button>span,.k-button>img,span.k-icon.k-i-arrow-60-down,span.k-icon.k-i-arrow-60-up,label.k-checkbox-label.k-no-text,.k-icon.k-i-collapse,.k-icon.k-i-expand', msie = kendo.support.browser.msie, supportEventDelegation = false;
        (function ($) {
            (function () {
                $('<div class="parent"><span /></div>').on('click', '>*', function () {
                    supportEventDelegation = true;
                }).find('span').trigger('click').end().off();
            }());
        }($));
        var Selectable = Widget.extend({
            init: function (element, options) {
                var that = this, multiple;
                Widget.fn.init.call(that, element, options);
                that._marquee = $('<div class=\'k-marquee\'><div class=\'k-marquee-color\'></div></div>');
                that._lastActive = null;
                that.element.addClass(SELECTABLE);
                that.relatedTarget = that.options.relatedTarget;
                multiple = that.options.multiple;
                if (this.options.aria && multiple) {
                    that.element.attr('aria-multiselectable', true);
                }
                that.userEvents = new kendo.UserEvents(that.element, {
                    global: true,
                    allowSelection: true,
                    filter: (!supportEventDelegation ? '.' + SELECTABLE + ' ' : '') + that.options.filter,
                    tap: proxy(that._tap, that),
                    touchAction: multiple ? 'none' : 'pan-x pan-y'
                });
                if (multiple) {
                    that.userEvents.bind('start', proxy(that._start, that)).bind('move', proxy(that._move, that)).bind('end', proxy(that._end, that)).bind('select', proxy(that._select, that));
                }
            },
            events: [
                CHANGE,
                UNSELECT
            ],
            options: {
                name: 'Selectable',
                filter: '>*',
                inputSelectors: INPUTSELECTOR,
                multiple: false,
                relatedTarget: $.noop
            },
            _isElement: function (target) {
                var elements = this.element;
                var idx, length = elements.length, result = false;
                target = target[0];
                for (idx = 0; idx < length; idx++) {
                    if (elements[idx] === target) {
                        result = true;
                        break;
                    }
                }
                return result;
            },
            _tap: function (e) {
                var target = $(e.target), that = this, ctrlKey = e.event.ctrlKey || e.event.metaKey, multiple = that.options.multiple, shiftKey = multiple && e.event.shiftKey, selected, whichCode = e.event.which, buttonCode = e.event.button;
                if (!that._isElement(target.closest('.' + SELECTABLE)) || whichCode && whichCode == 3 || buttonCode && buttonCode == 2) {
                    return;
                }
                if (!this._allowSelection(e.event.target)) {
                    return;
                }
                selected = target.hasClass(SELECTED);
                if (!multiple || !ctrlKey) {
                    that.clear();
                }
                target = target.add(that.relatedTarget(target));
                if (shiftKey) {
                    that.selectRange(that._firstSelectee(), target, e);
                } else {
                    if (selected && ctrlKey) {
                        that._unselect(target);
                        that._notify(CHANGE, e);
                    } else {
                        that.value(target, e);
                    }
                    that._lastActive = that._downTarget = target;
                }
            },
            _start: function (e) {
                var that = this, target = $(e.target), selected = target.hasClass(SELECTED), currentElement, ctrlKey = e.event.ctrlKey || e.event.metaKey;
                if (!this._allowSelection(e.event.target)) {
                    return;
                }
                that._downTarget = target;
                if (!that._isElement(target.closest('.' + SELECTABLE))) {
                    that.userEvents.cancel();
                    return;
                }
                if (that.options.useAllItems) {
                    that._items = that.element.find(that.options.filter);
                } else {
                    currentElement = target.closest(that.element);
                    that._items = currentElement.find(that.options.filter);
                }
                e.sender.capture();
                that._marquee.appendTo(document.body).css({
                    left: e.x.client + 1,
                    top: e.y.client + 1,
                    width: 0,
                    height: 0
                });
                if (!ctrlKey) {
                    that.clear();
                }
                target = target.add(that.relatedTarget(target));
                if (selected) {
                    that._selectElement(target, true);
                    if (ctrlKey) {
                        target.addClass(UNSELECTING);
                    }
                }
            },
            _move: function (e) {
                var that = this, position = {
                        left: e.x.startLocation > e.x.location ? e.x.location : e.x.startLocation,
                        top: e.y.startLocation > e.y.location ? e.y.location : e.y.startLocation,
                        width: abs(e.x.initialDelta),
                        height: abs(e.y.initialDelta)
                    };
                that._marquee.css(position);
                that._invalidateSelectables(position, e.event.ctrlKey || e.event.metaKey);
                e.preventDefault();
            },
            _end: function (e) {
                var that = this;
                that._marquee.remove();
                that._unselect(that.element.find(that.options.filter + '.' + UNSELECTING)).removeClass(UNSELECTING);
                var target = that.element.find(that.options.filter + '.' + ACTIVE);
                target = target.add(that.relatedTarget(target));
                that.value(target, e);
                that._lastActive = that._downTarget;
                that._items = null;
            },
            _invalidateSelectables: function (position, ctrlKey) {
                var idx, length, target = this._downTarget[0], items = this._items, related, toSelect;
                for (idx = 0, length = items.length; idx < length; idx++) {
                    toSelect = items.eq(idx);
                    related = toSelect.add(this.relatedTarget(toSelect));
                    if (collision(toSelect, position)) {
                        if (toSelect.hasClass(SELECTED)) {
                            if (ctrlKey && target !== toSelect[0]) {
                                related.removeClass(SELECTED).addClass(UNSELECTING);
                            }
                        } else if (!toSelect.hasClass(ACTIVE) && !toSelect.hasClass(UNSELECTING)) {
                            related.addClass(ACTIVE);
                        }
                    } else {
                        if (toSelect.hasClass(ACTIVE)) {
                            related.removeClass(ACTIVE);
                        } else if (ctrlKey && toSelect.hasClass(UNSELECTING)) {
                            related.removeClass(UNSELECTING).addClass(SELECTED);
                        }
                    }
                }
            },
            value: function (val, e) {
                var that = this, selectElement = proxy(that._selectElement, that);
                if (val) {
                    val.each(function () {
                        selectElement(this);
                    });
                    that._notify(CHANGE, e);
                    return;
                }
                return that.element.find(that.options.filter + '.' + SELECTED);
            },
            _firstSelectee: function () {
                var that = this, selected;
                if (that._lastActive !== null) {
                    return that._lastActive;
                }
                selected = that.value();
                return selected.length > 0 ? selected[0] : that.element.find(that.options.filter)[0];
            },
            _selectElement: function (element, preventNotify) {
                var toSelect = $(element), isPrevented = !preventNotify && this._notify('select', { element: element });
                toSelect.removeClass(ACTIVE);
                if (!isPrevented) {
                    toSelect.addClass(SELECTED);
                    if (this.options.aria) {
                        toSelect.attr(ARIASELECTED, true);
                    }
                }
            },
            _notify: function (name, args) {
                args = args || {};
                return this.trigger(name, args);
            },
            _unselect: function (element) {
                if (this.trigger(UNSELECT, { element: element })) {
                    return;
                }
                element.removeClass(SELECTED);
                if (this.options.aria) {
                    element.attr(ARIASELECTED, false);
                }
                return element;
            },
            _select: function (e) {
                if (this._allowSelection(e.event.target)) {
                    if (!msie || msie && !$(kendo._activeElement()).is(this.options.inputSelectors)) {
                        e.preventDefault();
                    }
                }
            },
            _allowSelection: function (target) {
                if ($(target).is(this.options.inputSelectors)) {
                    this.userEvents.cancel();
                    this._downTarget = null;
                    return false;
                }
                return true;
            },
            resetTouchEvents: function () {
                this.userEvents.cancel();
            },
            clear: function () {
                var items = this.element.find(this.options.filter + '.' + SELECTED);
                this._unselect(items);
            },
            selectRange: function (start, end, e) {
                var that = this, idx, tmp, items;
                that.clear();
                if (that.element.length > 1) {
                    items = that.options.continuousItems();
                }
                if (!items || !items.length) {
                    items = that.element.find(that.options.filter);
                }
                start = $.inArray($(start)[0], items);
                end = $.inArray($(end)[0], items);
                if (start > end) {
                    tmp = start;
                    start = end;
                    end = tmp;
                }
                if (!that.options.useAllItems) {
                    end += that.element.length - 1;
                }
                for (idx = start; idx <= end; idx++) {
                    that._selectElement(items[idx]);
                }
                that._notify(CHANGE, e);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.element.off(NS);
                that.userEvents.destroy();
                that._marquee = that._lastActive = that.element = that.userEvents = null;
            }
        });
        Selectable.parseOptions = function (selectable) {
            var asLowerString = typeof selectable === 'string' && selectable.toLowerCase();
            return {
                multiple: asLowerString && asLowerString.indexOf('multiple') > -1,
                cell: asLowerString && asLowerString.indexOf('cell') > -1
            };
        };
        function collision(element, position) {
            if (!element.is(':visible')) {
                return false;
            }
            var elementPosition = kendo.getOffset(element), right = position.left + position.width, bottom = position.top + position.height;
            elementPosition.right = elementPosition.left + kendo._outerWidth(element);
            elementPosition.bottom = elementPosition.top + kendo._outerHeight(element);
            return !(elementPosition.left > right || elementPosition.right < position.left || elementPosition.top > bottom || elementPosition.bottom < position.top);
        }
        kendo.ui.plugin(Selectable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('chat/messageBox', ['kendo.core'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo;
        var Widget = kendo.ui.Widget;
        var extend = $.extend;
        var proxy = $.proxy;
        var DOT = '.';
        var NS = '.kendoChat';
        var keys = kendo.keys;
        var SEND_ICON = '<svg version="1.1" ixmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 16 16" xml:space="preserve"><path d="M0,14.3c-0.1,0.6,0.3,0.8,0.8,0.6l14.8-6.5c0.5-0.2,0.5-0.6,0-0.8L0.8,1.1C0.3,0.9-0.1,1.1,0,1.7l0.7,4.2C0.8,6.5,1.4,7,1.9,7.1l8.8,0.8c0.6,0.1,0.6,0.1,0,0.2L1.9,8.9C1.4,9,0.8,9.5,0.7,10.1L0,14.3z"/></svg>';
        var TOGGLE_ICON = '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve"><g>   <path d="M128,240c0-26.4-21.6-48-48-48s-48,21.6-48,48s21.6,48,48,48S128,266.4,128,240z"/>   <path d="M192,240c0,26.4,21.6,48,48,48c26.4,0,48-21.6,48-48s-21.6-48-48-48C213.6,192,192,213.6,192,240z"/>   <path d="M352,240c0,26.4,21.6,48,48,48c26.4,0,48-21.6,48-48s-21.6-48-48-48C373.6,192,352,213.6,352,240z"/></g></svg>';
        var messageBoxStyles = {
            input: 'k-input',
            button: 'k-button',
            buttonFlat: 'k-flat',
            buttonIcon: 'k-button-icon',
            buttonSend: 'k-button-send',
            buttonToggle: 'k-button-toggle',
            iconAdd: 'k-icon k-i-add',
            hidden: 'k-hidden'
        };
        var ChatMessageBox = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this._wrapper();
                this._attachEvents();
                this._typing = false;
            },
            events: [],
            options: { messages: { placeholder: 'Type a message...' } },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (this.input) {
                    this.input.off(NS);
                    this.input.remove();
                    this.input = null;
                }
                this.element.off(NS);
                this.element.empty();
            },
            _wrapper: function () {
                var styles = ChatMessageBox.styles;
                var options = this.options;
                var messages = options.messages;
                var inputId = 'inputId_' + kendo.guid();
                $('<label>').addClass(styles.hidden).html(messages.placeholder).attr('for', inputId).appendTo(this.element);
                this.input = $('<input type=\'text\'>').addClass(styles.input).attr('id', inputId).attr('placeholder', messages.placeholder).appendTo(this.element);
                if (options.toolbar && options.toolbar.toggleable && options.toolbar.buttons) {
                    $('<button>').addClass(styles.button).addClass(styles.buttonFlat).addClass(styles.buttonIcon).addClass(styles.buttonToggle).attr('type', 'button').append($(TOGGLE_ICON)).appendTo(this.element);
                }
                $('<button>').addClass(styles.button).addClass(styles.buttonFlat).addClass(styles.buttonIcon).addClass(styles.buttonSend).append($(SEND_ICON)).appendTo(this.element);
            },
            _attachEvents: function () {
                var styles = ChatMessageBox.styles;
                this.input.on('keydown' + NS, proxy(this._keydown, this)).on('input' + NS, proxy(this._input, this)).on('focusout' + NS, proxy(this._inputFocusout, this));
                this.element.on('click' + NS, DOT + styles.buttonSend, proxy(this._buttonClick, this));
                this.element.on('click' + NS, DOT + styles.buttonToggle, proxy(this._toggleToolbar, this));
            },
            _input: function () {
                var currentValue = this.input.val();
                var start = currentValue.length > 0;
                this._triggerTyping(start);
            },
            _keydown: function (e) {
                var key = e.keyCode;
                switch (key) {
                case keys.ENTER:
                    e.preventDefault();
                    this._sendMessage();
                    break;
                }
            },
            _buttonClick: function (e) {
                e.preventDefault();
                this._sendMessage();
            },
            _sendMessage: function () {
                var value = this.input.val();
                if (!value.length) {
                    return;
                }
                this._triggerTyping(false);
                var args = { text: value };
                this.trigger('sendMessage', args);
                this.input.val('');
            },
            _inputFocusout: function () {
                this._triggerTyping(false);
            },
            _triggerTyping: function (start) {
                if (start) {
                    if (!this._typing) {
                        this.trigger('typingStart', {});
                        this._typing = true;
                    }
                } else {
                    if (this._typing) {
                        this.trigger('typingEnd', {});
                        this._typing = false;
                    }
                }
            },
            _toggleToolbar: function (ev) {
                this.trigger('toggleToolbar', { originalEvent: ev });
            }
        });
        extend(true, ChatMessageBox, { styles: messageBoxStyles });
        extend(kendo, { chat: { ChatMessageBox: ChatMessageBox } });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('chat/toolbar', ['kendo.core'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo;
        var Widget = kendo.ui.Widget;
        var extend = $.extend;
        var proxy = $.proxy;
        var DOT = '.';
        var NS = '.kendoChat';
        var DATA_K_BUTTON_NAME = 'kButtonName';
        var SCROLL_LEFT_NAME = 'chatToolbarScrollLeft';
        var SCROLL_RIGHT_NAME = 'chatToolbarScrollRight';
        var VISIBLE = ':visible';
        var DEFAULT_ANIMATION = {
            effects: 'expand:vertical',
            duration: 200
        };
        var NO_ANIMATION = {
            expand: { show: true },
            collapse: { hide: true }
        };
        var toolbarStyles = {
            button: 'k-button',
            buttonFlat: 'k-flat',
            buttonList: 'k-button-list',
            scrollButton: 'k-scroll-button',
            scrollButtonLeft: 'k-scroll-button-left',
            scrollButtonRight: 'k-scroll-button-right',
            scrollButtonLeftIcon: 'k-icon k-i-arrow-chevron-left',
            scrollButtonRightIcon: 'k-icon k-i-arrow-chevron-right',
            buttonIcon: 'k-button-icon'
        };
        var ChatToolBar = Widget.extend({
            init: function (element, options) {
                options = extend({}, options, { name: 'ChatToolbar' });
                var toolbarOptions = options.toolbar;
                var buttonsDefined = toolbarOptions.buttons && toolbarOptions.buttons.length;
                Widget.fn.init.call(this, element, options);
                if (buttonsDefined) {
                    this._createButtonList();
                }
                if (buttonsDefined && toolbarOptions.scrollable && this.buttonsWidth() > this.element.width()) {
                    this._initScrolling();
                }
                this._setupAnimation();
                if (toolbarOptions.toggleable) {
                    this.toggle(true);
                }
                this.element.on('click' + NS, proxy(this._onClick, this));
            },
            events: ['click'],
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.element.off(NS);
                this.element.empty();
            },
            _createButtonList: function () {
                var that = this;
                var styles = ChatToolBar.styles;
                var buttons = that.options.toolbar.buttons;
                var buttonList = $('<div class=\'' + styles.buttonList + '\'></div>');
                for (var i = 0; i < buttons.length; i++) {
                    var button = that._createButton(buttons[i]);
                    buttonList.append(button);
                }
                buttonList.appendTo(this.element);
                this.buttonList = buttonList;
            },
            _createButton: function (btnOptions) {
                var styles = ChatToolBar.styles;
                var buttonElm = $('<button>');
                if (typeof btnOptions === 'string') {
                    btnOptions = { name: btnOptions };
                }
                buttonElm.attr(btnOptions.attr || {}).attr('title', btnOptions.text).attr('type', 'button').addClass(btnOptions.name).data(DATA_K_BUTTON_NAME, btnOptions.name).addClass(styles.button);
                if (btnOptions.iconClass) {
                    buttonElm.addClass(styles.buttonIcon);
                    buttonElm.prepend('<span class=\'' + btnOptions.iconClass + '\'></span>');
                }
                return buttonElm;
            },
            _onClick: function (ev) {
                var styles = ChatToolBar.styles;
                var target = $(ev.target).closest(DOT + styles.button);
                if (target.is(DOT + styles.scrollButton) && !this._scrolling) {
                    this._scroll(target.data(DATA_K_BUTTON_NAME));
                }
                if (target.data(DATA_K_BUTTON_NAME)) {
                    this.trigger('click', {
                        button: target[0],
                        name: target.data(DATA_K_BUTTON_NAME),
                        originalEvent: ev
                    });
                }
            },
            _initScrolling: function () {
                var styles = ChatToolBar.styles;
                this.scrollButtonLeft = this._createButton({
                    name: SCROLL_LEFT_NAME,
                    iconClass: styles.scrollButtonLeftIcon,
                    attr: { 'class': styles.scrollButton + ' ' + styles.scrollButtonLeft }
                });
                this.scrollButtonRight = this._createButton({
                    name: SCROLL_RIGHT_NAME,
                    iconClass: styles.scrollButtonRightIcon,
                    attr: { 'class': styles.scrollButton + ' ' + styles.scrollButtonRight }
                });
                this.element.prepend(this.scrollButtonLeft);
                this.element.append(this.scrollButtonRight);
                this._refreshScrollButtons();
                this.element.on('keydown' + NS, proxy(this._refreshScrollButtons, this));
            },
            _scroll: function (commandName) {
                var that = this;
                var buttonWidth = that.buttonWidth();
                var maxScrollSize = this.maxScrollSize();
                var scrollAmmount = commandName === SCROLL_LEFT_NAME ? buttonWidth * -1 : buttonWidth;
                var currentScroll = this.currentScrollLeft();
                var scrollValue = currentScroll + scrollAmmount;
                scrollValue = Math.min(Math.max(scrollValue, 0), maxScrollSize);
                if (commandName !== SCROLL_LEFT_NAME && commandName !== SCROLL_RIGHT_NAME) {
                    return;
                }
                that.buttonList.scrollLeft(scrollValue);
                that._refreshScrollButtons(scrollValue);
            },
            _refreshScrollButtons: function (value) {
                var maxScrollSize = this.maxScrollSize();
                var currentScrollLeft = value === undefined || isNaN(parseInt(value, 10)) ? this.currentScrollLeft() : value;
                if (!this.scrollButtonLeft && !this.scrollButtonRight) {
                    return;
                }
                this.scrollButtonLeft.toggle(currentScrollLeft !== 0);
                this.scrollButtonRight.toggle(currentScrollLeft !== maxScrollSize);
            },
            _setupAnimation: function () {
                var animation = this.options.toolbar.animation;
                var defaultExpandAnimation = extend({}, DEFAULT_ANIMATION);
                var defaultCollapseAnimation = extend({
                    reverse: true,
                    hide: true
                }, DEFAULT_ANIMATION);
                if (animation === false) {
                    animation = extend(true, {}, NO_ANIMATION);
                } else {
                    animation = extend(true, {
                        expand: defaultExpandAnimation,
                        collapse: defaultCollapseAnimation
                    }, animation);
                }
                this.options.toolbar.animation = animation;
            },
            _animationComplete: function () {
                this._refreshScrollButtons();
            },
            currentScrollLeft: function () {
                return Math.round(this.buttonList.scrollLeft());
            },
            maxScrollSize: function () {
                return Math.round(this.buttonList[0].scrollWidth - this.buttonList[0].clientWidth);
            },
            buttons: function () {
                var styles = ChatToolBar.styles;
                return this.buttonList ? this.buttonList.children(DOT + styles.button) : null;
            },
            buttonWidth: function () {
                return Math.round(this.buttons().last().outerWidth(true));
            },
            buttonsWidth: function () {
                var width = 0;
                if (this.buttons()) {
                    width = this.buttonWidth() * this.buttons().length;
                }
                return width;
            },
            toggle: function (skipAnimation) {
                var animation = this.options.toolbar.animation;
                if (skipAnimation) {
                    animation = extend(true, {}, NO_ANIMATION);
                }
                animation.expand.complete = proxy(this._animationComplete, this);
                animation.collapse.complete = proxy(this._animationComplete, this);
                if (this.element.is(VISIBLE)) {
                    this.element.kendoStop().kendoAnimate(animation.collapse);
                } else {
                    this.element.kendoStop().kendoAnimate(animation.expand);
                }
            }
        });
        extend(true, ChatToolBar, { styles: toolbarStyles });
        extend(kendo.chat, { ChatToolBar: ChatToolBar });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('chat/view', [
        'kendo.core',
        'kendo.draganddrop'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo;
        var Widget = kendo.ui.Widget;
        var extend = $.extend;
        var proxy = $.proxy;
        var DOT = '.';
        var SPACE = ' ';
        var NS = '.kendoChat';
        var MESSAGE_GROUP_TEMPLATE = kendo.template('<div #:text# class="#=styles.messageGroup# #= url ? "" : styles.noAvatar #">' + '<p class="#=styles.author#">#:text#</p>' + '# if (url) { #' + '<img src="#=url#" alt="#:text#" class="#=styles.avatar#">' + '# } #' + '</div>');
        var SELF_MESSAGE_GROUP_TEMPLATE = kendo.template('<div me class="#=styles.messageGroup# #=styles.self# #= url ? "" : styles.noAvatar #">' + '# if (url) { #' + '<img src="#=url#" alt="#:text#" class="#=styles.avatar#">' + '# } #' + '</div>');
        var TEXT_MESSAGE_TEMPLATE = kendo.template('<div class="#=styles.message#">' + '<time class="#=styles.messageTime#">#= kendo.toString(kendo.parseDate(timestamp), "HH:mm:ss") #</time>' + '<div class="#=styles.bubble#">#:text#</div>' + '</div>');
        var TYPING_INDICATOR_TEMPLATE = kendo.template('<div class="#=styles.messageListContent# #=styles.typingIndicatorBubble#">' + '<p class="#=styles.author#">#:text#</p>' + '<div class="#=styles.message#">' + '<div class="#=styles.bubble#">' + '<div class="#=styles.typingIndicator#">' + '<span></span><span></span><span></span>' + '</div>' + '</div>' + '</div>' + '</div>');
        var SUGGESTED_ACTIONS_TEMPLATE = kendo.template('<div class="#=styles.suggestedActions#">' + '# for (var i = 0; i < suggestedActions.length; i++) { #' + '<span class="#=styles.suggestedAction#" data-value="#:suggestedActions[i].value#">#:suggestedActions[i].title#</span>' + '# } #' + '</div>');
        var HERO_CARD_TEMPLATE = kendo.template('<div class="#=styles.card# #=styles.cardRich#">' + '# if (typeof images !== "undefined" && images.length > 0) { #' + '<img src="#:images[0].url#" alt="#:images[0].alt#" class="#=styles.cardImage#" />' + '# } #' + '<div class="#=styles.cardBody#">' + '# if (typeof title !== "undefined") { #' + '<h5 class="#=styles.cardTitle#">#:title#</h5>' + '# } #' + '# if (typeof subtitle !== "undefined") { #' + '<h6 class="#=styles.cardSubtitle#">#:subtitle#</h6>' + '# } #' + '# if (typeof text !== "undefined") { #' + '<p>#:text#</p>' + '# } #' + '</div>' + '# if (typeof buttons !== "undefined" && buttons.length > 0) { #' + '<div class="#=styles.cardActions# #=styles.cardActionsVertical#">' + '# for (var i = 0; i < buttons.length; i++) { #' + '<span class="#=styles.cardAction#"><span class="#=styles.button# #=styles.buttonPrimary#" data-value="#:buttons[i].value#">#:buttons[i].title#</span></span>' + '# } #' + '</div>' + '# } #' + '</div>');
        extend(kendo.chat, {
            Templates: {},
            Components: {}
        });
        kendo.chat.registerTemplate = function (templateName, template) {
            kendo.chat.Templates[templateName] = kendo.template(template);
        };
        kendo.chat.getTemplate = function (templateName) {
            return kendo.chat.Templates[templateName] || TEXT_MESSAGE_TEMPLATE;
        };
        kendo.chat.registerTemplate('text', TEXT_MESSAGE_TEMPLATE);
        kendo.chat.registerTemplate('message', TEXT_MESSAGE_TEMPLATE);
        kendo.chat.registerTemplate('typing', TYPING_INDICATOR_TEMPLATE);
        kendo.chat.registerTemplate('suggestedAction', SUGGESTED_ACTIONS_TEMPLATE);
        kendo.chat.registerTemplate('heroCard', HERO_CARD_TEMPLATE);
        kendo.chat.registerTemplate('application/vnd.microsoft.card.hero', HERO_CARD_TEMPLATE);
        kendo.chat.registerComponent = function (componentName, component) {
            kendo.chat.Components[componentName] = component;
        };
        kendo.chat.getComponent = function (componentName) {
            return kendo.chat.Components[componentName] || null;
        };
        var Component = kendo.chat.Component = kendo.Class.extend({
            init: function (options, view) {
                this.element = $('<div></div>');
                this.options = options;
                this.view = view;
            },
            destroy: function () {
                kendo.destroy(this.element);
            }
        });
        var Calendar = Component.extend({
            init: function (options, view) {
                Component.fn.init.call(this, options, view);
                this.element.kendoCalendar({
                    change: function () {
                        view.trigger('suggestedAction', {
                            text: kendo.toString(this.value(), 'd'),
                            type: 'message'
                        });
                    }
                });
            },
            destroy: function () {
            }
        });
        kendo.chat.registerComponent('calendar', Calendar);
        var viewStyles = {
            wrapper: 'k-widget k-chat',
            messageList: 'k-avatars',
            messageListContent: 'k-message-list-content',
            messageTime: 'k-message-time',
            messageGroup: 'k-message-group',
            message: 'k-message',
            only: 'k-only',
            first: 'k-first',
            middle: 'k-middle',
            last: 'k-last',
            author: 'k-author',
            avatar: 'k-avatar',
            noAvatar: 'k-no-avatar',
            self: 'k-alt',
            button: 'k-button',
            iconButton: 'k-button-icon',
            buttonPrimary: 'k-flat k-primary',
            scrollButtonIcon: 'k-icon',
            scrollButtonIconLeft: 'k-i-arrow-chevron-left',
            scrollButtonIconRight: 'k-i-arrow-chevron-right',
            typingIndicator: 'k-typing-indicator',
            typingIndicatorBubble: 'k-typing-indicator-bubble',
            bubble: 'k-bubble',
            suggestedActions: 'k-quick-replies',
            suggestedAction: 'k-quick-reply',
            cardWrapper: 'k-card-container',
            cardDeckScrollWrap: 'k-card-deck-scrollwrap',
            cardDeck: 'k-card-deck',
            cardList: 'k-card-list',
            card: 'k-card',
            cardRich: 'k-card-type-rich',
            cardBody: 'k-card-body',
            cardImage: 'k-card-image',
            cardTitle: 'k-card-title',
            cardSubtitle: 'k-card-subtitle',
            cardActions: 'k-card-actions',
            cardActionsVertical: 'k-card-actions-vertical',
            cardAction: 'k-card-action',
            selected: 'k-state-selected'
        };
        var ChatView = kendo.chat.ChatView = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this._list();
                this._lastSender = null;
                this.typingParticipants = [];
                this._attachEvents();
                this._scrollable();
            },
            events: [],
            options: {
                messages: {
                    isTyping: ' is typing.',
                    areTyping: ' are typing.',
                    and: ' and '
                }
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (this._scrollDraggable) {
                    this._scrollDraggable.destroy();
                }
                this.element.empty();
                this.element.off(NS);
                this.list = null;
                this._lastSender = null;
            },
            _list: function () {
                var viewStyles = ChatView.styles;
                this.element.addClass(viewStyles.messageList).attr('aria-live', 'polite');
                this.list = $('<div>').addClass(viewStyles.messageListContent).appendTo(this.element);
            },
            _attachEvents: function () {
                var styles = ChatView.styles;
                this.element.on('click' + NS, proxy(this._listClick, this)).on('click' + NS, DOT + styles.message, proxy(this._messageClick, this)).on('click' + NS, DOT + styles.suggestedAction, proxy(this._suggestedActionClick, this)).on('click' + NS, DOT + styles.cardAction + SPACE + DOT + styles.button, proxy(this._cardActionClick, this));
            },
            _scrollable: function () {
                var viewStyles = ChatView.styles;
                this.element.on('click' + NS, DOT + viewStyles.cardDeckScrollWrap + SPACE + DOT + viewStyles.button, proxy(this._scrollButtonClick, this));
            },
            _scrollButtonClick: function (e) {
                var viewStyles = ChatView.styles;
                var button = $(e.currentTarget);
                var scrollToLeft = button.find(DOT + viewStyles.scrollButtonIconLeft).length !== 0;
                var scrollContainer = button.siblings(DOT + viewStyles.cardDeck);
                var lastCard = scrollContainer.find(DOT + viewStyles.card).last();
                var cardWidth = lastCard.outerWidth(true);
                if (scrollToLeft) {
                    scrollContainer.scrollLeft(scrollContainer.scrollLeft() - cardWidth);
                } else {
                    scrollContainer.scrollLeft(scrollContainer.scrollLeft() + cardWidth);
                }
            },
            getTemplate: function (templateName) {
                return kendo.chat.getTemplate(templateName);
            },
            getComponent: function (type) {
                return kendo.chat.getComponent(type);
            },
            renderMessage: function (message, sender) {
                if (!message.timestamp) {
                    message.timestamp = new Date();
                }
                if (!message.text) {
                    message.text = '';
                }
                var bubbleElement = this._renderTemplate(message.type, message);
                this._renderBubble(message.type, bubbleElement, sender);
                if (message.type == 'typing') {
                    if (this.typingParticipants.length > 0) {
                        this._removeTypingParticipant(sender);
                    }
                } else {
                    this._lastSender = sender.id;
                }
            },
            renderSuggestedActions: function (suggestedActions) {
                this._removeSuggestedActions();
                var element = this._renderTemplate('suggestedAction', { suggestedActions: suggestedActions });
                this.list.append(element);
                this._scrollToBottom();
            },
            renderAttachments: function (options) {
                var wrapper = this._renderAttachmentWrapper(options.attachmentLayout);
                var cardContainer = options.attachmentLayout === 'carousel' ? wrapper.find(DOT + ChatView.styles.cardDeck) : wrapper;
                var attachments = options.attachments;
                if (!attachments.length) {
                    return;
                }
                for (var i = 0; i < attachments.length; i++) {
                    var cardElement = this._renderTemplate(attachments[i].contentType, attachments[i].content);
                    cardContainer.append(cardElement);
                }
                this._removeSuggestedActions();
                this._removeTypingIndicator();
                this.list.append(wrapper);
                this._lastSender = null;
            },
            renderComponent: function (type) {
                var componentType = this.getComponent(type);
                var component = new componentType({}, this);
                this.list.append(component.element);
                this._scrollToBottom();
            },
            _renderAttachmentWrapper: function (layout) {
                var viewStyles = ChatView.styles;
                var wrapper = $('<div>');
                if (layout === 'carousel') {
                    wrapper.addClass(viewStyles.cardDeckScrollWrap);
                    var buttonLeft = this._renderScrollButton(viewStyles.scrollButtonIconLeft);
                    wrapper.append(buttonLeft);
                    wrapper.append($('<div>').addClass(viewStyles.cardDeck));
                    var buttonRight = this._renderScrollButton(viewStyles.scrollButtonIconRight);
                    wrapper.append(buttonRight);
                } else {
                    wrapper.addClass(viewStyles.cardList);
                }
                return wrapper;
            },
            _renderScrollButton: function (directionClass) {
                var viewStyles = ChatView.styles;
                return $('<button>').addClass(viewStyles.button).addClass(viewStyles.iconButton).append($('<span>').addClass(viewStyles.scrollButtonIcon).addClass(directionClass));
            },
            _removeSuggestedActions: function () {
                this.list.find(DOT + ChatView.styles.suggestedActions).remove();
            },
            _listClick: function (e) {
                var styles = ChatView.styles;
                var targetElement = $(e.target);
                if (targetElement.hasClass(styles.message) || targetElement.parents(DOT + styles.message).length) {
                    return;
                }
                this._clearSelection();
            },
            _messageClick: function (e) {
                this._clearSelection();
                $(e.currentTarget).addClass(ChatView.styles.selected);
            },
            _suggestedActionClick: function (e) {
                var text = $(e.target).data('value') || '';
                this.trigger('actionClick', { text: text });
                this._removeSuggestedActions();
            },
            _cardActionClick: function (e) {
                var text = $(e.target).data('value') || '';
                this.trigger('actionClick', { text: text });
            },
            _renderBubble: function (messageType, bubbleElement, sender) {
                this._removeSuggestedActions();
                this._removeTypingIndicator();
                var group = this._getMessageGroup(sender, messageType);
                this._appendToGroup(group, bubbleElement, messageType);
                this._scrollToBottom();
            },
            _renderTemplate: function (type, options) {
                var componentType = this.getComponent(type);
                var element;
                if (componentType) {
                    var component = new componentType(options, this);
                    element = component.element;
                } else {
                    var template = this.getTemplate(type);
                    var templateOptions = extend(true, {}, options, { styles: ChatView.styles });
                    element = $(template(templateOptions));
                }
                return element;
            },
            _getMessageGroup: function (sender, messageType) {
                var viewStyles = ChatView.styles;
                var template = this._getMessageGroupTemplate(sender, messageType);
                var appendTarget = messageType == 'typing' ? this.element : this.list;
                var group;
                if (sender.id === this._lastSender && this._lastSender !== null && messageType !== 'typing') {
                    group = this.list.find(DOT + viewStyles.messageGroup).last();
                    if (group.length) {
                        return group;
                    }
                }
                return $(template({
                    text: sender.name,
                    url: sender.iconUrl,
                    styles: viewStyles
                })).appendTo(appendTarget);
            },
            _getMessageGroupTemplate: function (sender, messageType) {
                var isOwnMessage = sender.id === this.options.user.id;
                var template = isOwnMessage ? SELF_MESSAGE_GROUP_TEMPLATE : MESSAGE_GROUP_TEMPLATE;
                if (messageType == 'typing') {
                    template = TYPING_INDICATOR_TEMPLATE;
                }
                return template;
            },
            _appendToGroup: function (group, messageElement, messageType) {
                var viewStyles = ChatView.styles;
                var children = group.find(DOT + viewStyles.message);
                var childrenCount = children.length;
                var indicator = this.element.find(DOT + viewStyles.typingIndicator);
                if (indicator.length && messageType == 'typing') {
                    return;
                }
                messageElement.addClass(childrenCount === 0 ? viewStyles.only : viewStyles.last);
                children.filter(DOT + viewStyles.only).removeClass(viewStyles.only).addClass(viewStyles.first);
                children.filter(DOT + viewStyles.last).removeClass(viewStyles.last).addClass(viewStyles.middle);
                group.append(messageElement);
            },
            _renderTypingIndicator: function (sender) {
                var indicator = this.element.find(DOT + viewStyles.typingIndicatorBubble), indicatorList, participants;
                this._addTypingParticipant(sender);
                if (indicator.length) {
                    participants = this._composeTypingParticipantsText(this.typingParticipants);
                    indicatorList = indicator.find(DOT + viewStyles.author).first();
                    indicatorList.text(participants);
                } else {
                    $(TYPING_INDICATOR_TEMPLATE({
                        text: sender.name + this.options.messages.isTyping,
                        styles: viewStyles
                    })).appendTo(this.element);
                }
                this._scrollToBottom();
            },
            _addTypingParticipant: function (sender) {
                var found = false;
                for (var i = 0; i < this.typingParticipants.length; i += 1) {
                    if (this.typingParticipants[i].id == sender.id) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    this.typingParticipants.push(sender);
                }
            },
            _removeTypingParticipant: function (sender) {
                var indicator = this.element.find(DOT + viewStyles.typingIndicatorBubble), indicatorList, participants;
                if (indicator.length) {
                    for (var i = 0; i < this.typingParticipants.length; i += 1) {
                        if (this.typingParticipants[i].id == sender.id) {
                            this.typingParticipants.splice(i, 1);
                        }
                    }
                    participants = this._composeTypingParticipantsText(this.typingParticipants);
                    if (participants === '') {
                        indicator.remove();
                    } else {
                        indicatorList = indicator.find(DOT + viewStyles.author).first();
                        indicatorList.text(participants);
                    }
                }
            },
            _composeTypingParticipantsText: function (participants) {
                var messages = this.options.messages, typingAction = participants.length == 1 ? messages.isTyping : messages.areTyping, typingText = '';
                if (participants.length === 0) {
                    return typingText;
                }
                typingText = this.typingParticipants.map(function (author) {
                    return author.name;
                }).join(', ').replace(/,(?!.*,)/gim, messages.and.trimRight()) + typingAction;
                return typingText;
            },
            _removeTypingIndicator: function () {
                var indicator = this.element.find(DOT + viewStyles.typingIndicatorBubble);
                if (indicator.length) {
                    this.typingParticipants = [];
                    indicator.remove();
                }
            },
            _clearSelection: function () {
                var selectedClass = ChatView.styles.selected;
                this.element.find(DOT + selectedClass).removeClass(selectedClass);
            },
            _scrollToBottom: function () {
                this.element.scrollTop(this.element.prop('scrollHeight'));
            }
        });
        extend(true, ChatView, { styles: viewStyles });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.chat', [
        'chat/messageBox',
        'chat/toolbar',
        'chat/view'
    ], f);
}(function () {
    var __meta__ = {
        id: 'chat',
        name: 'Chat',
        category: 'web',
        description: 'The Chat component.',
        depends: [
            'core',
            'draganddrop'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var Widget = kendo.ui.Widget;
        var extend = $.extend;
        var DOT = '.';
        var chatStyles = {
            wrapper: 'k-widget k-chat',
            canvas: 'k-chat-canvas',
            viewWrapper: 'k-message-list',
            messageBoxWrapper: 'k-message-box',
            toolbarBoxWrapper: 'k-toolbar-box'
        };
        var Chat = Widget.extend({
            init: function (element, options, events) {
                Widget.fn.init.call(this, element, options);
                if (events) {
                    this._events = events;
                }
                this._user();
                this._wrapper();
                this._view();
                this._messageBox();
                if (options && options.toolbar && options.toolbar.buttons) {
                    this._toolbar();
                }
                kendo.notify(this);
            },
            events: [
                'typingStart',
                'typingEnd',
                'post',
                'sendMessage',
                'actionClick',
                'toolClick'
            ],
            options: {
                user: {
                    name: 'User',
                    iconUrl: ''
                },
                name: 'Chat',
                messages: { placeholder: 'Type a message...' },
                toolbar: false
            },
            setOptions: function (options) {
                this._setEvents(options);
                $.extend(true, this.options, options);
                if (this.toolbar && 'toolbar' in options) {
                    this.toolbar.destroy();
                    this.toolbar = null;
                }
                if (this.messageBox) {
                    this.messageBox.unbind();
                    this.messageBox.destroy();
                    this.messageBox = null;
                }
                this._messageBox();
                if ('toolbar' in options) {
                    this._resetToolbarButtons(options);
                    this._toolbar();
                }
            },
            _resetToolbarButtons: function (options) {
                var toolbarBoxWrapper = this.wrapper.find(DOT + chatStyles.toolbarBoxWrapper);
                if (!toolbarBoxWrapper.is(':visible')) {
                    toolbarBoxWrapper.show();
                }
                if ('buttons' in options.toolbar) {
                    this.options.toolbar.buttons = options.toolbar.buttons;
                }
            },
            destroy: function () {
                if (this.view) {
                    this.view.unbind();
                    this.view.destroy();
                    this.view = null;
                }
                if (this.messageBox) {
                    this.messageBox.unbind();
                    this.messageBox.destroy();
                    this.messageBox = null;
                }
                if (this.toolbar) {
                    this.toolbar.destroy();
                    this.toolbar = null;
                }
                Widget.fn.destroy.call(this);
            },
            _user: function () {
                this.options.user.id = kendo.guid();
            },
            getUser: function () {
                return extend(true, {}, this.options.user);
            },
            _wrapper: function () {
                var chatStyles = Chat.styles;
                var options = this.options;
                var height = options.height;
                var width = options.width;
                var uiElements = '<div class=\'' + chatStyles.viewWrapper + '\'></div>' + '<div class=\'' + chatStyles.messageBoxWrapper + '\'></div>' + '<div class=\'' + chatStyles.toolbarBoxWrapper + '\' role=\'toolbar\' style=\'display:none;\'></div>';
                this.wrapper = this.element.addClass(chatStyles.wrapper).append(uiElements);
                if (options.toolbar && options.toolbar.buttons && options.toolbar.buttons.length) {
                    this.wrapper.find(DOT + chatStyles.toolbarBoxWrapper).show();
                }
                if (height) {
                    this.wrapper.height(height);
                }
                if (width) {
                    this.wrapper.css('max-width', width);
                }
            },
            _view: function () {
                var that = this;
                var chatStyles = Chat.styles;
                var options = extend(true, {}, this.options);
                var element = this.wrapper.find(DOT + chatStyles.viewWrapper + '');
                this.view = new kendo.chat.ChatView(element, options);
                this.view.bind('actionClick', function (args) {
                    that.trigger('actionClick', args);
                    that.postMessage(args.text);
                });
            },
            _messageBox: function () {
                var that = this;
                var chatStyles = Chat.styles;
                var options = extend(true, {}, this.options);
                var element = this.wrapper.find(DOT + chatStyles.messageBoxWrapper + '');
                this.messageBox = new kendo.chat.ChatMessageBox(element, options);
                this.messageBox.bind('typingStart', function (args) {
                    that.trigger('typingStart', args);
                }).bind('typingEnd', function (args) {
                    that.trigger('typingEnd', args);
                }).bind('sendMessage', function (args) {
                    that.trigger('sendMessage', args);
                    that.postMessage(args.text);
                }).bind('toggleToolbar', function () {
                    that.toggleToolbar();
                });
            },
            _toolbar: function () {
                var that = this;
                var chatStyles = Chat.styles;
                var options = extend(true, {}, that.options);
                var element = that.wrapper.find(DOT + chatStyles.toolbarBoxWrapper + '');
                if (options.toolbar.scrollable === undefined) {
                    this.options.toolbar.scrollable = options.toolbar.scrollable = true;
                }
                if (options.toolbar.toggleable === undefined) {
                    this.options.toolbar.toggleable = options.toolbar.toggleable = false;
                }
                that.toolbar = new kendo.chat.ChatToolBar(element, options);
                that.toolbar.bind('click', function (ev) {
                    that.trigger('toolClick', {
                        sender: that,
                        name: ev.name,
                        button: ev.button,
                        messageBox: that.messageBox.input[0],
                        originalEvent: ev.originalEvent
                    });
                });
            },
            postMessage: function (message) {
                var postArgs = extend(true, {}, {
                    text: message,
                    type: 'message',
                    timestamp: new Date(),
                    from: this.getUser()
                });
                this.trigger('post', postArgs);
                this.renderMessage(postArgs, postArgs.from);
            },
            renderMessage: function (message, sender) {
                this.view.renderMessage(message, sender);
            },
            renderSuggestedActions: function (suggestedActions) {
                this.view.renderSuggestedActions(suggestedActions);
            },
            renderAttachments: function (options, sender) {
                this.view.renderAttachments(options, sender);
            },
            toggleToolbar: function (skipAnimation) {
                this.toolbar.toggle(skipAnimation);
            },
            renderUserTypingIndicator: function (sender) {
                this.view._renderTypingIndicator(sender);
            },
            clearUserTypingIndicator: function (sender) {
                this.view._removeTypingParticipant(sender);
            },
            removeTypingIndicator: function () {
                this.view._removeTypingIndicator();
            }
        });
        kendo.ui.plugin(Chat);
        extend(true, Chat, { styles: chatStyles });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.button', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'button',
        name: 'Button',
        category: 'web',
        description: 'The Button widget displays styled buttons.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, proxy = $.proxy, keys = kendo.keys, CLICK = 'click', MOUSEDOWN = kendo.support.mousedown, MOUSEUP = kendo.support.mouseup, KBUTTON = 'k-button', KBUTTONICON = 'k-button-icon', KBUTTONICONTEXT = 'k-button-icontext', NS = '.kendoButton', DISABLED = 'disabled', DISABLEDSTATE = 'k-state-disabled', FOCUSEDSTATE = 'k-state-focused', SELECTEDSTATE = 'k-state-active';
        var Button = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                element = that.wrapper = that.element;
                options = that.options;
                element.addClass(KBUTTON).attr('role', 'button');
                options.enable = options.enable && !element.attr(DISABLED);
                that.enable(options.enable);
                if (options.enable) {
                    that._tabindex();
                }
                that.iconElement();
                element.on(CLICK + NS, proxy(that._click, that)).on('focus' + NS, proxy(that._focus, that)).on('blur' + NS, proxy(that._blur, that)).on('keydown' + NS, proxy(that._keydown, that)).on('keyup' + NS, proxy(that._removeActive, that)).on(MOUSEDOWN + NS, proxy(that._addActive, that)).on(MOUSEUP + NS, proxy(that._removeActive, that));
                kendo.notify(that);
            },
            destroy: function () {
                var that = this;
                that.wrapper.off(NS);
                Widget.fn.destroy.call(that);
            },
            events: [CLICK],
            options: {
                name: 'Button',
                icon: '',
                iconClass: '',
                spriteCssClass: '',
                imageUrl: '',
                enable: true
            },
            _isNativeButton: function () {
                return this.element.prop('tagName').toLowerCase() == 'button';
            },
            _click: function (e) {
                if (this.options.enable) {
                    if (this.trigger(CLICK, { event: e })) {
                        e.preventDefault();
                    }
                }
            },
            _focus: function () {
                if (this.options.enable) {
                    this.element.addClass(FOCUSEDSTATE);
                }
            },
            _blur: function () {
                var that = this;
                that.element.removeClass(FOCUSEDSTATE);
                setTimeout(function () {
                    that.element.removeClass(SELECTEDSTATE);
                });
            },
            _keydown: function (e) {
                var that = this;
                if (e.keyCode == keys.ENTER || e.keyCode == keys.SPACEBAR) {
                    that._addActive();
                    if (!that._isNativeButton()) {
                        if (e.keyCode == keys.SPACEBAR) {
                            e.preventDefault();
                        }
                        that._click(e);
                    }
                }
            },
            _removeActive: function () {
                this.element.removeClass(SELECTEDSTATE);
            },
            _addActive: function () {
                if (this.options.enable) {
                    this.element.addClass(SELECTEDSTATE);
                }
            },
            iconElement: function () {
                var that = this, element = that.element, options = that.options, icon = options.icon, iconClass = options.iconClass, spriteCssClass = options.spriteCssClass, imageUrl = options.imageUrl, span, img, isEmpty;
                if (spriteCssClass || imageUrl || icon || iconClass) {
                    isEmpty = true;
                    element.contents().filter(function () {
                        return !$(this).hasClass('k-sprite') && !$(this).hasClass('k-icon') && !$(this).hasClass('k-image');
                    }).each(function (idx, el) {
                        if (el.nodeType == 1 || el.nodeType == 3 && $.trim(el.nodeValue).length > 0) {
                            isEmpty = false;
                        }
                    });
                    if (isEmpty) {
                        element.addClass(KBUTTONICON);
                    } else {
                        element.addClass(KBUTTONICONTEXT);
                    }
                }
                if (imageUrl) {
                    img = element.children('img.k-image').first();
                    if (!img[0]) {
                        img = $('<img alt="icon" class="k-image" />').prependTo(element);
                    }
                    img.attr('src', imageUrl);
                } else if (icon || iconClass) {
                    span = element.children('span.k-icon').first();
                    if (!span[0]) {
                        span = $('<span></span>').prependTo(element);
                    }
                    span.attr('class', icon ? 'k-icon k-i-' + icon : iconClass);
                } else if (spriteCssClass) {
                    span = element.children('span.k-sprite').first();
                    if (!span[0]) {
                        span = $('<span class="k-sprite"></span>').prependTo(element);
                    }
                    span.addClass(spriteCssClass);
                }
            },
            enable: function (enable) {
                var that = this, element = that.element;
                if (enable === undefined) {
                    enable = true;
                }
                enable = !!enable;
                that.options.enable = enable;
                element.toggleClass(DISABLEDSTATE, !enable).attr('aria-disabled', !enable).attr(DISABLED, !enable);
                if (enable) {
                    that._tabindex();
                }
                try {
                    element.blur();
                } catch (err) {
                }
            }
        });
        kendo.ui.plugin(Button);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.buttongroup', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'buttongroup',
        name: 'ButtonGroup',
        category: 'web',
        description: 'The Kendo ButtonGroup widget is a linear set of grouped buttons.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var ui = kendo.ui;
        var Widget = ui.Widget;
        var keys = kendo.keys;
        var proxy = $.proxy;
        var template = kendo.template;
        var NS = '.kendoButtonGroup';
        var KWIDGET = 'k-widget';
        var KBUTTONGROUP = 'k-button-group';
        var KBUTTON = 'k-button';
        var KBUTTONICONTEXT = 'k-button-icontext';
        var KBUTTONICON = 'k-button-icon';
        var ACTIVE = 'k-state-active';
        var FOCUSED = 'k-state-focused';
        var DISABLED = 'k-state-disabled';
        var SELECT = 'select';
        var CLICK = 'click';
        var KEYDOWN = 'keydown';
        var FOCUS = 'focus';
        var BLUR = 'blur';
        var MOUSEDOWN = 'mousedown';
        var templates = {
            item: template('<span ' + '#= item.enabled === false ? "disabled" : "" # ' + '# if (item.badge) { #' + kendo.attr('badge') + '="#=item.badge#"' + '# } #' + '>' + '#= icon(iconClass) #' + '#= image(item) #' + '#= text #' + '</span>'),
            image: template('<img alt="icon" src="#=data.imageUrl#" />'),
            icon: template('<span class="#=data#" />'),
            empty: template('')
        };
        function createBadge(value, item) {
            if (value === undefined) {
                return;
            }
            $('<span class="k-badge">' + kendo.htmlEncode(value) + '</span>').appendTo(item);
        }
        var ButtonGroup = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.wrapper = that.element;
                if (that.options.items) {
                    that._renderItems(that.options.items);
                }
                that.selectedIndices = [];
                that.element.addClass(KWIDGET + ' ' + KBUTTONGROUP).attr('role', 'group').attr('tabindex', that.element.attr('tabindex') || '0').children().each(function () {
                    var item = $(this);
                    that._updateClasses.bind(that)(item);
                });
                that._enable = true;
                if (!that.options.enable) {
                    that._enable = false;
                    that.element.attr('aria-disabled', true).addClass(DISABLED);
                }
                that.select(that.options.index);
                that.element.on(CLICK + NS, '.' + KBUTTON, proxy(that._click, that)).on(FOCUS + NS, proxy(that._focus, that)).on(KEYDOWN + NS, proxy(that._keyDown, that)).on(BLUR + NS, function () {
                    that.preventFocus = false;
                    that.element.find('.' + KBUTTON).removeClass(FOCUSED);
                }).on(MOUSEDOWN + NS, function () {
                    that.preventFocus = true;
                });
            },
            events: [SELECT],
            options: {
                name: 'ButtonGroup',
                selection: 'single',
                index: -1,
                enable: true
            },
            current: function () {
                return this.element.find('.' + ACTIVE);
            },
            _renderItems: function (items) {
                var that = this;
                items.forEach(function (item) {
                    var renderedItem = $(templates.item({
                        image: item.imageUrl ? templates.image : templates.empty,
                        icon: !item.imageUrl && (item.iconClass || item.icon) ? templates.icon : templates.empty,
                        iconClass: item.iconClass || 'k-icon k-i-' + item.icon,
                        item: item,
                        text: item.text ? item.encoded === false ? item.text : kendo.htmlEncode(item.text) : ''
                    }));
                    if (item.attributes) {
                        renderedItem.attr(item.attributes);
                    }
                    if (item.selected) {
                        renderedItem.addClass(ACTIVE);
                    }
                    if (item.iconClass || item.icon || item.imageUrl) {
                        renderedItem.addClass(item.text ? 'k-button-icontext' : 'k-button-icon');
                    }
                    renderedItem.appendTo(that.element);
                });
            },
            _focus: function () {
                var element = $(this.element);
                if (this.preventFocus) {
                    return;
                }
                if (element.find('.' + ACTIVE).length) {
                    element.find('.' + ACTIVE).first().focus().addClass(FOCUSED);
                } else {
                    element.children().first().focus().addClass(FOCUSED);
                }
            },
            _keyDown: function (e) {
                var that = this;
                var buttonGroup = $(that.element);
                var focusableItems = buttonGroup.find('.' + KBUTTON);
                var focusedElement = buttonGroup.find('.' + FOCUSED);
                var currentIndex = focusableItems.index(focusedElement);
                var isRtl = kendo.support.isRtl(that.element);
                var itemToFocus;
                if (e.keyCode === keys.LEFT && !isRtl || e.keyCode === keys.RIGHT && isRtl) {
                    focusedElement.removeClass(FOCUSED);
                    itemToFocus = currentIndex === 0 ? focusableItems.eq(focusableItems.length - 1) : $(focusableItems[currentIndex - 1]);
                    itemToFocus.focus().addClass(FOCUSED);
                    e.preventDefault();
                } else if (e.keyCode === keys.LEFT && isRtl || e.keyCode === keys.RIGHT && !isRtl) {
                    focusedElement.removeClass(FOCUSED);
                    itemToFocus = currentIndex + 1 === focusableItems.length ? focusableItems.eq(0) : $(focusableItems[currentIndex + 1]);
                    itemToFocus.focus().addClass(FOCUSED);
                    e.preventDefault();
                } else if (e.keyCode === keys.ENTER || e.keyCode === keys.SPACEBAR) {
                    that._select(focusedElement);
                    e.preventDefault();
                }
            },
            select: function (button) {
                var that = this, ariaPressed, index = -1;
                if (button === undefined || button === -1) {
                    return;
                }
                that.element.find('.' + KBUTTON).removeClass(FOCUSED);
                if (typeof button === 'number') {
                    index = button;
                    button = that.element.children().eq(button);
                } else if (button.nodeType) {
                    button = $(button);
                    index = button.index();
                }
                if (that.options.selection === 'multiple') {
                    ariaPressed = button.attr('aria-pressed') === 'true';
                    button.attr('aria-pressed', !ariaPressed).toggleClass(ACTIVE);
                    if (that.selectedIndices.indexOf(index) === -1) {
                        that.selectedIndices.push(index);
                    } else {
                        that.selectedIndices.splice(that.selectedIndices.indexOf(index), 1);
                    }
                } else {
                    that.selectedIndices = [];
                    that.current().attr('aria-pressed', false).removeClass(ACTIVE);
                    button.attr('aria-pressed', true).addClass(ACTIVE);
                    that.selectedIndices.push(index);
                }
                that.trigger(SELECT, { indices: that.selectedIndices });
            },
            badge: function (item, value) {
                var buttongroup = this.element;
                var button = !isNaN(item) ? buttongroup.children().eq(item) : buttongroup.find(item);
                var validValue = value || value === 0;
                var badge;
                if (!button.length) {
                    return;
                }
                badge = button.children('.k-badge').eq(0);
                if (!badge.length && validValue) {
                    createBadge(kendo.htmlEncode(value), button);
                    return kendo.htmlEncode(value);
                }
                if (validValue) {
                    badge.html(kendo.htmlEncode(value));
                } else if (value === false) {
                    badge.empty().remove();
                    return;
                }
                return badge.html();
            },
            enable: function (enable) {
                if (typeof enable == 'undefined') {
                    enable = true;
                }
                this.element.attr('aria-disabled', !enable).toggleClass(DISABLED, !enable);
                this._enable = this.options.enable = enable;
            },
            destroy: function () {
                var that = this;
                that.element.off(NS);
                Widget.fn.destroy.call(that);
            },
            _updateClasses: function (button) {
                var icon = kendo.attrValue(button, 'icon');
                var badge = kendo.attrValue(button, 'badge');
                var image = button.find('img').addClass('k-image');
                var isEmpty = true;
                button.attr('aria-pressed', false).attr('role', 'button').addClass(KBUTTON);
                if (button.is('[disabled]') || button.hasClass(DISABLED)) {
                    button.addClass(DISABLED).attr('aria-disabled', true).removeAttr('disabled');
                }
                if (button.is('.' + ACTIVE)) {
                    button.removeClass(ACTIVE);
                    if (!button.hasClass(DISABLED) && this.options.selection === 'single' || this.options.selection === 'multiple') {
                        this.select(button[0]);
                    }
                }
                if (!image[0] && icon) {
                    button.prepend($(templates.icon('k-icon k-i-' + icon)));
                }
                button.contents().filter(function () {
                    return !$(this).hasClass('k-icon') && !$(this).hasClass('k-image');
                }).each(function () {
                    if (this.nodeType == 1 || this.nodeType == 3 && $.trim(this.nodeValue).length > 0) {
                        isEmpty = false;
                    }
                });
                if (image[0] || icon) {
                    button.addClass(isEmpty ? KBUTTONICON : KBUTTONICONTEXT);
                }
                if (badge || badge === 0) {
                    createBadge(badge, button);
                }
            },
            _click: function (e) {
                var target = $(e.target).closest('.' + KBUTTON);
                if (e.isDefaultPrevented()) {
                    return;
                }
                this._select(target);
            },
            _select: function (target) {
                var button = target;
                this.element.find('.' + KBUTTON).removeClass(FOCUSED);
                if (!this._enable || button.is('.' + DISABLED)) {
                    button.addClass(FOCUSED);
                    return;
                }
                this.select(target[0]);
                button.addClass(FOCUSED);
            }
        });
        ui.plugin(ButtonGroup);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.switch', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'switch',
        name: 'Switch',
        category: 'web',
        description: 'The Switch widget is used to display two exclusive choices.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, NS = '.kendoSwitch', Widget = ui.Widget, support = kendo.support, CHANGE = 'change', switchStyles = {
                widget: 'k-switch k-widget',
                container: 'k-switch-container',
                handle: 'k-switch-handle',
                checked: 'k-switch-on',
                checkedLabel: 'k-switch-label-on',
                unchecked: 'k-switch-off',
                uncheckedLabel: 'k-switch-label-off',
                disabled: 'k-state-disabled',
                readonly: 'k-state-readonly',
                active: 'k-state-active'
            }, DISABLED = 'disabled', ARIA_DISABLED = 'aria-disabled', READONLY = 'readonly', ARIA_READONLY = 'aria-readonly', ARIA_CHECKED = 'aria-checked', CHECKED = 'checked', CLICK = support.click + NS, TOUCHEND = support.pointers ? 'pointerup' : 'touchend', KEYDOWN = 'keydown' + NS, LABELIDPART = '_label', proxy = $.proxy;
        var SWITCH_TEMPLATE = kendo.template('<span class="#=styles.widget#" role="switch"></span>');
        var SWITCH_CONTAINER_TEMPLATE = kendo.template('<span class=\'#=styles.container#\'>' + '<span class=\'#=styles.checkedLabel#\'>#=checked#</span>' + '<span class=\'#=styles.uncheckedLabel#\'>#=unchecked#</span>' + '<span class=\'#=styles.handle#\'></span>' + '</span>');
        var Switch = Widget.extend({
            init: function (element, options) {
                var that = this, wrapper;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element[0];
                element.type = 'checkbox';
                wrapper = $(SWITCH_TEMPLATE({ styles: switchStyles }));
                that.wrapper = that.element.wrap(wrapper).parent();
                that.wrapper.append($(SWITCH_CONTAINER_TEMPLATE({
                    styles: switchStyles,
                    checked: options.messages.checked,
                    unchecked: options.messages.unchecked
                }))).addClass(element.className);
                that.wrapper.on(CLICK, proxy(that._click, that)).on(TOUCHEND, proxy(that._touchEnd, that)).on(KEYDOWN, proxy(that._keydown, that));
                if (that.options.enabled) {
                    that._tabindex();
                }
                that._initSettings();
                that._aria();
                kendo.notify(that, kendo.ui);
            },
            setOptions: function (options) {
                var that = this, messages = options.messages, checkedLabel, uncheckedLabel;
                that.options = $.extend(that.options, options);
                if (messages && messages.checked !== undefined) {
                    checkedLabel = that.wrapper.find('.' + switchStyles.checkedLabel);
                    checkedLabel.text(messages.checked);
                }
                if (messages && messages.unchecked !== undefined) {
                    uncheckedLabel = that.wrapper.find('.' + switchStyles.uncheckedLabel);
                    uncheckedLabel.text(messages.unchecked);
                }
                if (options.width) {
                    that.wrapper.css({ width: options.width });
                }
                if (options.enabled !== undefined) {
                    that.enable(options.enabled);
                }
                if (options.readonly !== undefined) {
                    that.readonly(options.readonly);
                }
                that.check(options.checked);
            },
            _initSettings: function () {
                var that = this, element = that.element[0], options = that.options;
                if (options.width) {
                    that.wrapper.css({ width: options.width });
                }
                if (options.checked === null) {
                    options.checked = element.checked;
                }
                that.check(options.checked);
                options.enabled = options.enabled && !that.element.attr(DISABLED);
                that.enable(options.enabled);
                options.readonly = options.readonly || !!that.element.attr(READONLY);
                that.readonly(options.readonly);
            },
            _aria: function () {
                var that = this, element = that.element, wrapper = that.wrapper, id = element.attr('id'), labelFor = $('label[for="' + id + '"]'), ariaLabel = element.attr('aria-label'), ariaLabelledBy = element.attr('aria-labelledby');
                if (ariaLabel) {
                    wrapper.attr('aria-label', ariaLabel);
                } else if (ariaLabelledBy) {
                    wrapper.attr('aria-labelledby', ariaLabelledBy);
                } else if (labelFor.length) {
                    var labelId = labelFor.attr('id');
                    if (!labelId) {
                        labelId = (id || kendo.guid()) + LABELIDPART;
                        labelFor.attr('id', labelId);
                    }
                    wrapper.attr('aria-labelledby', labelId);
                }
            },
            events: [CHANGE],
            options: {
                name: 'Switch',
                messages: {
                    checked: 'On',
                    unchecked: 'Off'
                },
                width: null,
                checked: null,
                enabled: true,
                readonly: false
            },
            check: function (checked) {
                var that = this, element = that.element[0];
                if (checked === undefined) {
                    return element.checked;
                }
                if (element.checked !== checked) {
                    that.options.checked = element.checked = checked;
                }
                that.wrapper.attr(ARIA_CHECKED, checked).toggleClass(switchStyles.checked, checked).toggleClass(switchStyles.unchecked, !checked);
                if (checked) {
                    that.element.attr(CHECKED, CHECKED);
                } else {
                    that.element.removeAttr(CHECKED);
                }
            },
            value: function (value) {
                if (typeof value === 'string') {
                    value = value === 'true';
                }
                return this.check.apply(this, [value]);
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.wrapper.off(NS);
            },
            toggle: function () {
                var that = this;
                that.check(!that.element[0].checked);
            },
            enable: function (enable) {
                var element = this.element, wrapper = this.wrapper;
                if (typeof enable == 'undefined') {
                    enable = true;
                }
                this.options.enabled = enable;
                if (enable) {
                    element.removeAttr(DISABLED);
                    wrapper.removeAttr(ARIA_DISABLED);
                } else {
                    element.attr(DISABLED, DISABLED);
                    wrapper.attr(ARIA_DISABLED, true);
                }
                wrapper.toggleClass(switchStyles.disabled, !enable);
            },
            readonly: function (readonly) {
                var that = this, element = that.element, wrapper = that.wrapper;
                if (typeof readonly == 'undefined') {
                    readonly = true;
                }
                that.options.readonly = readonly;
                if (readonly) {
                    element.attr(READONLY, true);
                    wrapper.attr(ARIA_READONLY, true);
                } else {
                    element.removeAttr(READONLY);
                    wrapper.removeAttr(ARIA_READONLY);
                }
                wrapper.toggleClass(switchStyles.readonly, readonly);
            },
            _check: function () {
                var that = this, checked = that.element[0].checked = !that.element[0].checked;
                that.wrapper.focus();
                if (!that.options.enabled || that.options.readonly || that.trigger(CHANGE, { checked: checked })) {
                    that.element[0].checked = !checked;
                    return;
                }
                that.check(checked);
            },
            _keydown: function (e) {
                if (e.keyCode === kendo.keys.SPACEBAR) {
                    this._check();
                    e.preventDefault();
                }
            },
            _isTouch: function (event) {
                return /touch/.test(event.type) || event.originalEvent && /touch/.test(event.originalEvent.pointerType);
            },
            _click: function (e) {
                if (!this._isTouch(e) && e.which === 1) {
                    this._check();
                }
            },
            _touchEnd: function (e) {
                if (this._isTouch(e)) {
                    this._check();
                    e.preventDefault();
                }
            }
        });
        ui.plugin(Switch);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pager', ['kendo.data'], f);
}(function () {
    var __meta__ = {
        id: 'pager',
        name: 'Pager',
        category: 'framework',
        depends: ['data'],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, proxy = $.proxy, FIRST = '.k-i-arrow-end-left', LAST = '.k-i-arrow-end-right', PREV = '.k-i-arrow-60-left', NEXT = '.k-i-arrow-60-right', SIZE = 'k-pager-lg k-pager-md k-pager-sm', CHANGE = 'change', NS = '.kendoPager', CLICK = 'click', KEYDOWN = 'keydown', DISABLED = 'disabled', MOUSEDOWN = 'down', DOCUMENT_ELEMENT = $(document.documentElement), MAX_VALUE = Number.MAX_VALUE, iconTemplate = kendo.template('<a href="\\#" aria-label="#=text#" title="#=text#" class="k-link k-pager-nav #= wrapClassName #"><span class="k-icon #= className #"></span></a>');
        function button(template, idx, text, numeric, title) {
            return template({
                idx: idx,
                text: text,
                ns: kendo.ns,
                numeric: numeric,
                title: title || ''
            });
        }
        function icon(className, text, wrapClassName) {
            return iconTemplate({
                className: className.substring(1),
                text: text,
                wrapClassName: wrapClassName || ''
            });
        }
        function update(element, selector, page, disabled) {
            element.find(selector).parent().attr(kendo.attr('page'), page).attr('tabindex', -1).toggleClass('k-state-disabled', disabled);
        }
        function first(element, page) {
            update(element, FIRST, 1, page <= 1);
        }
        function prev(element, page) {
            update(element, PREV, Math.max(1, page - 1), page <= 1);
        }
        function next(element, page, totalPages) {
            update(element, NEXT, Math.min(totalPages, page + 1), page >= totalPages);
        }
        function last(element, page, totalPages) {
            update(element, LAST, totalPages, page >= totalPages);
        }
        var Pager = Widget.extend({
            init: function (element, options) {
                var that = this, page, totalPages;
                var sizeClassName = null;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                that._createDataSource(options);
                that.linkTemplate = kendo.template(that.options.linkTemplate);
                that.selectTemplate = kendo.template(that.options.selectTemplate);
                that.currentPageTemplate = kendo.template(that.options.currentPageTemplate);
                page = that.page();
                totalPages = that.totalPages();
                that._refreshHandler = proxy(that.refresh, that);
                that.dataSource.bind(CHANGE, that._refreshHandler);
                that.downEvent = kendo.applyEventMap(MOUSEDOWN, kendo.guid());
                if (options.previousNext) {
                    if (!that.element.find(FIRST).length) {
                        that.element.append(icon(FIRST, options.messages.first, 'k-pager-first'));
                        first(that.element, page, totalPages);
                    }
                    if (!that.element.find(PREV).length) {
                        that.element.append(icon(PREV, options.messages.previous));
                        prev(that.element, page, totalPages);
                    }
                }
                if (options.numeric) {
                    that.list = that.element.find('.k-pager-numbers');
                    if (!that.list.length) {
                        that.list = $('<ul class="k-pager-numbers k-reset" />').appendTo(that.element);
                    }
                    if (options.dataSource && !options.dataSource.total()) {
                        that.list.empty().append(that.currentPageTemplate({ text: 0 })).append(that.selectTemplate({ text: 0 }));
                    }
                    that.list.wrap('<div class="k-pager-numbers-wrap"></div>');
                }
                if (options.input) {
                    if (!that.element.find('.k-pager-input').length) {
                        that.element.append('<span class="k-pager-input k-label">' + options.messages.page + '<input class="k-textbox">' + kendo.format(options.messages.of, totalPages) + '</span>');
                    }
                    that.element.on(KEYDOWN + NS, '.k-pager-input input', proxy(that._keydown, that));
                }
                if (options.previousNext) {
                    if (!that.element.find(NEXT).length) {
                        that.element.append(icon(NEXT, options.messages.next));
                        next(that.element, page, totalPages);
                    }
                    if (!that.element.find(LAST).length) {
                        that.element.append(icon(LAST, options.messages.last, 'k-pager-last'));
                        last(that.element, page, totalPages);
                    }
                }
                if (options.pageSizes) {
                    if (!that.element.find('.k-pager-sizes').length) {
                        var pageSizes = options.pageSizes.length ? options.pageSizes : [
                            'all',
                            5,
                            10,
                            20
                        ];
                        var pageItems = $.map(pageSizes, function (size) {
                            if (size.toLowerCase && size.toLowerCase() === 'all') {
                                return '<option value=\'all\'>' + options.messages.allPages + '</option>';
                            }
                            return '<option>' + size + '</option>';
                        });
                        $('<span class="k-pager-sizes k-label"><select/>' + options.messages.itemsPerPage + '</span>').appendTo(that.element).find('select').html(pageItems.join('')).end().appendTo(that.element);
                    }
                    that.element.find('.k-pager-sizes select').val(that.pageSize());
                    if (kendo.ui.DropDownList) {
                        that.element.find('.k-pager-sizes select').show().kendoDropDownList();
                    }
                    that.element.on(CHANGE + NS, '.k-pager-sizes select', proxy(that._change, that));
                }
                if (options.refresh) {
                    if (!that.element.find('.k-pager-refresh').length) {
                        that.element.append('<a href="#" class="k-pager-refresh k-link" title="' + options.messages.refresh + '" aria-label="' + options.messages.refresh + '"><span class="k-icon k-i-reload"></span></a>');
                    }
                    that.element.on(CLICK + NS, '.k-pager-refresh', proxy(that._refreshClick, that));
                }
                if (options.info) {
                    if (!that.element.find('.k-pager-info').length) {
                        that.element.append('<span class="k-pager-info k-label" />');
                    }
                }
                that.element.on(CLICK + NS, 'a', proxy(that._click, that)).addClass('k-pager-wrap k-widget k-floatwrap');
                that.element.on(CLICK + NS, '.k-current-page', proxy(that._toggleActive, that));
                if (options.autoBind) {
                    that.refresh();
                }
                that._resizeHandler = proxy(that.resize, that, true);
                $(window).on('resize' + NS, that._resizeHandler);
                sizeClassName = that._getWidthSizeClass(that.element.width());
                if (sizeClassName) {
                    that.element.addClass(sizeClassName);
                }
                kendo.notify(that);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.element.off(NS);
                that.dataSource.unbind(CHANGE, that._refreshHandler);
                that._refreshHandler = null;
                $(window).off('resize' + NS, this._resizeHandler);
                kendo.destroy(that.element);
                that.element = that.list = null;
            },
            events: [CHANGE],
            options: {
                name: 'Pager',
                selectTemplate: '<li><span class="k-state-selected">#=text#</span></li>',
                currentPageTemplate: '<li class="k-current-page"><span class="k-link k-pager-nav">#=text#</span></li>',
                linkTemplate: '<li><a tabindex="-1" href="\\#" class="k-link" data-#=ns#page="#=idx#" #if (title !== "") {# title="#=title#" #}#>#=text#</a></li>',
                buttonCount: 10,
                autoBind: true,
                numeric: true,
                info: true,
                input: false,
                previousNext: true,
                pageSizes: false,
                refresh: false,
                responsive: true,
                messages: {
                    allPages: 'All',
                    display: '{0} - {1} of {2} items',
                    empty: 'No items to display',
                    page: 'Page',
                    of: 'of {0}',
                    itemsPerPage: 'items per page',
                    first: 'Go to the first page',
                    previous: 'Go to the previous page',
                    next: 'Go to the next page',
                    last: 'Go to the last page',
                    refresh: 'Refresh',
                    morePages: 'More pages'
                }
            },
            setDataSource: function (dataSource) {
                var that = this;
                that.dataSource.unbind(CHANGE, that._refreshHandler);
                that.dataSource = that.options.dataSource = dataSource;
                dataSource.bind(CHANGE, that._refreshHandler);
                if (that.options.autoBind) {
                    dataSource.fetch();
                }
            },
            _resize: function (size) {
                if (size.width) {
                    var sizeClassName = this._getWidthSizeClass(size.width);
                    var el = this.element;
                    if (!sizeClassName) {
                        el.removeClass(SIZE);
                    } else if (!el.hasClass(sizeClassName)) {
                        el.removeClass(SIZE);
                        el.addClass(sizeClassName);
                    }
                }
            },
            _createDataSource: function (options) {
                this.dataSource = kendo.data.DataSource.create(options.dataSource);
            },
            refresh: function (e) {
                var that = this, idx, end, start = 1, reminder, page = that.page(), html = '', options = that.options, pageSize = that.pageSize(), collapsedTotal = that._collapsedTotal(), total = that.dataSource.total(), totalPages = that.totalPages(), linkTemplate = that.linkTemplate, buttonCount = options.buttonCount;
                DOCUMENT_ELEMENT.unbind(that.downEvent, $.proxy(that._hideList, that));
                if (e && e.action == 'itemchange') {
                    return;
                }
                if (options.numeric) {
                    if (page > buttonCount) {
                        reminder = page % buttonCount;
                        start = reminder === 0 ? page - buttonCount + 1 : page - reminder + 1;
                    }
                    end = Math.min(start + buttonCount - 1, totalPages);
                    if (start > 1) {
                        html += button(linkTemplate, start - 1, '...', false, options.messages.morePages);
                    }
                    for (idx = start; idx <= end; idx++) {
                        html += button(idx == page ? that.selectTemplate : linkTemplate, idx, idx, true);
                    }
                    if (end < totalPages) {
                        html += button(linkTemplate, idx, '...', false, options.messages.morePages);
                    }
                    if (html === '') {
                        html = that.selectTemplate({ text: 0 });
                    }
                    html = this.currentPageTemplate({ text: page }) + html;
                    that.list.removeClass('k-state-expanded').html(html);
                }
                if (options.info) {
                    if (total > 0) {
                        html = kendo.format(options.messages.display, that.dataSource.options.endless ? 1 : Math.min((page - 1) * (that.dataSource.pageSize() || 0) + 1, collapsedTotal), Math.min(page * pageSize, collapsedTotal), total);
                    } else {
                        html = options.messages.empty;
                    }
                    that.element.find('.k-pager-info').html(html);
                }
                if (options.input) {
                    that.element.find('.k-pager-input').html(that.options.messages.page + '<input class="k-textbox" aria-label="' + page + '">' + kendo.format(options.messages.of, totalPages)).find('input').val(page).attr(DISABLED, total < 1).toggleClass('k-state-disabled', total < 1);
                }
                if (options.previousNext) {
                    first(that.element, page, totalPages);
                    prev(that.element, page, totalPages);
                    next(that.element, page, totalPages);
                    last(that.element, page, totalPages);
                }
                if (options.pageSizes) {
                    var hasAll = that.element.find('.k-pager-sizes option[value=\'all\']').length > 0;
                    var selectAll = hasAll && (pageSize === this.dataSource.total() || pageSize == MAX_VALUE);
                    var text = pageSize;
                    if (selectAll) {
                        pageSize = 'all';
                        text = options.messages.allPages;
                    }
                    that.element.find('.k-pager-sizes select').val(pageSize).attr('aria-label', pageSize).filter('[' + kendo.attr('role') + '=dropdownlist]').kendoDropDownList('value', pageSize).kendoDropDownList('text', text);
                }
            },
            _collapsedTotal: function () {
                return this.dataSource.total();
            },
            _keydown: function (e) {
                if (e.keyCode === kendo.keys.ENTER) {
                    var input = this.element.find('.k-pager-input').find('input'), page = parseInt(input.val(), 10);
                    if (isNaN(page) || page < 1 || page > this.totalPages()) {
                        page = this.page();
                    }
                    input.val(page);
                    this.page(page);
                }
            },
            _refreshClick: function (e) {
                e.preventDefault();
                this.dataSource.read();
            },
            _change: function (e) {
                var value = e.currentTarget.value;
                var pageSize = parseInt(value, 10);
                var dataSource = this.dataSource;
                if (!isNaN(pageSize)) {
                    dataSource.pageSize(pageSize);
                } else if ((value + '').toLowerCase() == 'all') {
                    dataSource._pageSize = undefined;
                    dataSource._take = undefined;
                    dataSource._skip = 0;
                    dataSource.fetch();
                }
            },
            _toggleActive: function () {
                var that = this;
                if (that.list.hasClass('k-state-expanded')) {
                    DOCUMENT_ELEMENT.unbind(that.downEvent, $.proxy(that._hideList, that));
                } else {
                    DOCUMENT_ELEMENT.bind(that.downEvent, $.proxy(that._hideList, that));
                }
                that.list.toggleClass('k-state-expanded');
            },
            _hideList: function (e) {
                var that = this, target = kendo.eventTarget(e);
                if (!$.contains(that.list[0], target)) {
                    DOCUMENT_ELEMENT.unbind(that.downEvent, $.proxy(that._hideList, that));
                    that.list.removeClass('k-state-expanded');
                }
            },
            _click: function (e) {
                var target = $(e.currentTarget);
                e.preventDefault();
                if (!target.is('.k-state-disabled')) {
                    this.page(target.attr(kendo.attr('page')));
                }
            },
            totalPages: function () {
                return Math.ceil((this.dataSource.total() || 0) / (this.pageSize() || 1));
            },
            pageSize: function () {
                return this.dataSource.pageSize() || this.dataSource.total();
            },
            page: function (page) {
                if (page !== undefined) {
                    if (this.trigger('pageChange', { index: page })) {
                        return;
                    }
                    this.dataSource.page(page);
                    this.trigger(CHANGE, { index: page });
                } else {
                    if (this.dataSource.total() > 0) {
                        return this.dataSource.page();
                    } else {
                        return 0;
                    }
                }
            },
            _getWidthSizeClass: function (width) {
                var that = this, sizes = SIZE.split(' ');
                if (!that.options.responsive) {
                    return null;
                } else if (width <= 480) {
                    return sizes[2];
                } else if (width <= 640) {
                    return sizes[1];
                } else if (width <= 1024) {
                    return sizes[0];
                }
                return null;
            }
        });
        ui.plugin(Pager);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.notification', [
        'kendo.core',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'notification',
        name: 'Notification',
        category: 'web',
        description: 'The Notification widget displays user alerts.',
        depends: [
            'core',
            'popup'
        ],
        features: [{
                id: 'notification-fx',
                name: 'Animation',
                description: 'Support for animation',
                depends: ['fx']
            }]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, proxy = $.proxy, extend = $.extend, setTimeout = window.setTimeout, CLICK = 'click', SHOW = 'show', HIDE = 'hide', KNOTIFICATION = 'k-notification', KICLOSE = '.k-notification-wrap .k-i-close', KHIDING = 'k-hiding', INFO = 'info', SUCCESS = 'success', WARNING = 'warning', ERROR = 'error', TOP = 'top', LEFT = 'left', BOTTOM = 'bottom', RIGHT = 'right', UP = 'up', NS = '.kendoNotification', WRAPPER = '<div class="k-widget k-popup k-notification"></div>', TEMPLATE = '<div class="k-notification-wrap">' + '<span class="k-icon k-i-#=typeIcon#" title="#=typeIcon#"></span>' + '<div class="k-notification-content">#=content#</div>' + '<span class="k-icon k-i-close" title="Hide"></span>' + '</div>', SAFE_TEMPLATE = TEMPLATE.replace('#=content#', '#:content#');
        var Notification = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                if (!options.appendTo || !$(options.appendTo).is(element)) {
                    that.element.hide();
                }
                that._compileTemplates(options.templates);
                that._guid = '_' + kendo.guid();
                that._isRtl = kendo.support.isRtl(element);
                that._compileStacking(options.stacking, options.position.top, options.position.left);
                kendo.notify(that);
            },
            events: [
                SHOW,
                HIDE
            ],
            options: {
                name: 'Notification',
                position: {
                    pinned: true,
                    top: null,
                    left: null,
                    bottom: 20,
                    right: 20
                },
                stacking: 'default',
                hideOnClick: true,
                button: false,
                allowHideAfter: 0,
                autoHideAfter: 5000,
                appendTo: null,
                width: null,
                height: null,
                templates: [],
                animation: {
                    open: {
                        effects: 'fade:in',
                        duration: 300
                    },
                    close: {
                        effects: 'fade:out',
                        duration: 600,
                        hide: true
                    }
                }
            },
            _compileTemplates: function (templates) {
                var that = this;
                var kendoTemplate = kendo.template;
                that._compiled = {};
                $.each(templates, function (key, value) {
                    that._compiled[value.type] = kendoTemplate(value.template || $('#' + value.templateId).html());
                });
                that._defaultCompiled = kendoTemplate(TEMPLATE);
                that._safeCompiled = kendoTemplate(SAFE_TEMPLATE);
            },
            _getCompiled: function (type, safe) {
                var defaultCompiled = safe ? this._safeCompiled : this._defaultCompiled;
                return type ? this._compiled[type] || defaultCompiled : defaultCompiled;
            },
            _compileStacking: function (stacking, top, left) {
                var that = this, paddings = {
                        paddingTop: 0,
                        paddingRight: 0,
                        paddingBottom: 0,
                        paddingLeft: 0
                    }, horizontalAlignment = left !== null ? LEFT : RIGHT, origin, position;
                switch (stacking) {
                case 'down':
                    origin = BOTTOM + ' ' + horizontalAlignment;
                    position = TOP + ' ' + horizontalAlignment;
                    delete paddings.paddingBottom;
                    break;
                case RIGHT:
                    origin = TOP + ' ' + RIGHT;
                    position = TOP + ' ' + LEFT;
                    delete paddings.paddingRight;
                    break;
                case LEFT:
                    origin = TOP + ' ' + LEFT;
                    position = TOP + ' ' + RIGHT;
                    delete paddings.paddingLeft;
                    break;
                case UP:
                    origin = TOP + ' ' + horizontalAlignment;
                    position = BOTTOM + ' ' + horizontalAlignment;
                    delete paddings.paddingTop;
                    break;
                default:
                    if (top !== null) {
                        origin = BOTTOM + ' ' + horizontalAlignment;
                        position = TOP + ' ' + horizontalAlignment;
                        delete paddings.paddingBottom;
                    } else {
                        origin = TOP + ' ' + horizontalAlignment;
                        position = BOTTOM + ' ' + horizontalAlignment;
                        delete paddings.paddingTop;
                    }
                    break;
                }
                that._popupOrigin = origin;
                that._popupPosition = position;
                that._popupPaddings = paddings;
            },
            _attachPopupEvents: function (options, popup) {
                var that = this, allowHideAfter = options.allowHideAfter, attachDelay = !isNaN(allowHideAfter) && allowHideAfter > 0, closeIcon;
                function attachClick(target) {
                    target.on(CLICK + NS, function () {
                        that._hidePopup(popup);
                    });
                }
                if (options.hideOnClick) {
                    popup.bind('activate', function () {
                        if (attachDelay) {
                            setTimeout(function () {
                                attachClick(popup.element);
                            }, allowHideAfter);
                        } else {
                            attachClick(popup.element);
                        }
                    });
                } else if (options.button) {
                    closeIcon = popup.element.find(KICLOSE);
                    if (attachDelay) {
                        setTimeout(function () {
                            attachClick(closeIcon);
                        }, allowHideAfter);
                    } else {
                        attachClick(closeIcon);
                    }
                }
            },
            _showPopup: function (wrapper, options) {
                var that = this, autoHideAfter = options.autoHideAfter, x = options.position.left, y = options.position.top, popup, openPopup;
                openPopup = $('.' + that._guid + ':not(.' + KHIDING + ')').last();
                popup = new kendo.ui.Popup(wrapper, {
                    anchor: openPopup[0] ? openPopup : document.body,
                    origin: that._popupOrigin,
                    position: that._popupPosition,
                    animation: options.animation,
                    copyAnchorStyles: false,
                    modal: true,
                    collision: '',
                    isRtl: that._isRtl,
                    close: function () {
                        that._triggerHide(this.element);
                    },
                    deactivate: function (e) {
                        e.sender.element.off(NS);
                        e.sender.element.find(KICLOSE).off(NS);
                        e.sender.destroy();
                    }
                });
                that._attachPopupEvents(options, popup);
                wrapper.removeClass('k-group k-reset');
                if (openPopup[0]) {
                    popup.open();
                } else {
                    if (x === null) {
                        x = $(window).width() - wrapper.outerWidth() - options.position.right;
                    }
                    if (y === null) {
                        y = $(window).height() - wrapper.outerHeight() - options.position.bottom;
                    }
                    popup.open(x, y);
                }
                popup.wrapper.addClass(that._guid).css(extend({
                    margin: 0,
                    zIndex: 10050
                }, that._popupPaddings));
                if (options.position.pinned) {
                    popup.wrapper.css('position', 'fixed');
                    if (openPopup[0]) {
                        that._togglePin(popup.wrapper, true);
                    }
                } else if (!openPopup[0]) {
                    that._togglePin(popup.wrapper, false);
                }
                if (autoHideAfter > 0) {
                    setTimeout(function () {
                        that._hidePopup(popup);
                    }, autoHideAfter);
                }
            },
            _hidePopup: function (popup) {
                popup.wrapper.addClass(KHIDING);
                popup.close();
            },
            _togglePin: function (wrapper, pin) {
                var win = $(window), sign = pin ? -1 : 1;
                wrapper.css({
                    top: parseInt(wrapper.css(TOP), 10) + sign * win.scrollTop(),
                    left: parseInt(wrapper.css(LEFT), 10) + sign * win.scrollLeft()
                });
            },
            _attachStaticEvents: function (options, wrapper) {
                var that = this, allowHideAfter = options.allowHideAfter, attachDelay = !isNaN(allowHideAfter) && allowHideAfter > 0;
                function attachClick(target) {
                    target.on(CLICK + NS, proxy(that._hideStatic, that, wrapper));
                }
                if (options.hideOnClick) {
                    if (attachDelay) {
                        setTimeout(function () {
                            attachClick(wrapper);
                        }, allowHideAfter);
                    } else {
                        attachClick(wrapper);
                    }
                } else if (options.button) {
                    if (attachDelay) {
                        setTimeout(function () {
                            attachClick(wrapper.find(KICLOSE));
                        }, allowHideAfter);
                    } else {
                        attachClick(wrapper.find(KICLOSE));
                    }
                }
            },
            _showStatic: function (wrapper, options) {
                var that = this, autoHideAfter = options.autoHideAfter, animation = options.animation, insertionMethod = options.stacking == UP || options.stacking == LEFT ? 'prependTo' : 'appendTo', initializedNotifications;
                wrapper.removeClass('k-popup').addClass(that._guid)[insertionMethod](options.appendTo).hide().kendoAnimate(animation.open || false);
                initializedNotifications = that.getNotifications();
                initializedNotifications.each(function (idx, element) {
                    that._attachStaticEvents(options, $(element));
                    if (autoHideAfter > 0) {
                        setTimeout(function () {
                            that._hideStatic($(element));
                        }, autoHideAfter);
                    }
                });
            },
            _hideStatic: function (wrapper) {
                wrapper.kendoAnimate(extend(this.options.animation.close || false, {
                    complete: function () {
                        wrapper.off(NS).find(KICLOSE).off(NS);
                        wrapper.remove();
                    }
                }));
                this._triggerHide(wrapper);
            },
            _triggerHide: function (element) {
                this.trigger(HIDE, { element: element });
                this.angular('cleanup', function () {
                    return { elements: element };
                });
            },
            show: function (content, type, safe) {
                var that = this, options = that.options, wrapper = $(WRAPPER), args, defaultArgs;
                if (!type) {
                    type = INFO;
                }
                if (content !== null && content !== undefined && content !== '') {
                    if (kendo.isFunction(content)) {
                        content = content();
                    }
                    defaultArgs = {
                        typeIcon: type,
                        content: ''
                    };
                    if ($.isPlainObject(content)) {
                        args = extend(defaultArgs, content);
                    } else {
                        args = extend(defaultArgs, { content: content });
                    }
                    wrapper.addClass(KNOTIFICATION + '-' + type).toggleClass(KNOTIFICATION + '-button', options.button).toggleClass(KNOTIFICATION + '-closable', options.button).attr('data-role', 'alert').css({
                        width: options.width,
                        height: options.height
                    }).append(that._getCompiled(type, safe)(args));
                    that.angular('compile', function () {
                        return {
                            elements: wrapper,
                            data: [{ dataItem: args }]
                        };
                    });
                    if ($(options.appendTo)[0]) {
                        that._showStatic(wrapper, options);
                    } else {
                        that._showPopup(wrapper, options);
                    }
                    that.trigger(SHOW, { element: wrapper });
                }
                return that;
            },
            showText: function (content, type) {
                this.show(content, type, true);
            },
            info: function (content) {
                return this.show(content, INFO);
            },
            success: function (content) {
                return this.show(content, SUCCESS);
            },
            warning: function (content) {
                return this.show(content, WARNING);
            },
            error: function (content) {
                return this.show(content, ERROR);
            },
            hide: function () {
                var that = this, openedNotifications = that.getNotifications();
                if (that.options.appendTo) {
                    openedNotifications.each(function (idx, element) {
                        that._hideStatic($(element));
                    });
                } else {
                    openedNotifications.each(function (idx, element) {
                        var popup = $(element).data('kendoPopup');
                        if (popup) {
                            that._hidePopup(popup);
                        }
                    });
                }
                return that;
            },
            getNotifications: function () {
                var that = this, guidElements = $('.' + that._guid + ':not(.' + KHIDING + ')');
                if (that.options.appendTo) {
                    return guidElements;
                } else {
                    return guidElements.children('.' + KNOTIFICATION);
                }
            },
            setOptions: function (newOptions) {
                var that = this, options;
                Widget.fn.setOptions.call(that, newOptions);
                options = that.options;
                if (newOptions.templates !== undefined) {
                    that._compileTemplates(options.templates);
                }
                if (newOptions.stacking !== undefined || newOptions.position !== undefined) {
                    that._compileStacking(options.stacking, options.position.top, options.position.left);
                }
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.getNotifications().off(NS).find(KICLOSE).off(NS);
            }
        });
        kendo.ui.plugin(Notification);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.tooltip', [
        'kendo.core',
        'kendo.popup',
        'kendo.fx'
    ], f);
}(function () {
    var __meta__ = {
        id: 'tooltip',
        name: 'Tooltip',
        category: 'web',
        description: 'The Tooltip widget displays a popup hint for a given html element.',
        depends: [
            'core',
            'popup'
        ],
        features: [{
                id: 'tooltip-fx',
                name: 'Animation',
                description: 'Support for animation',
                depends: ['fx']
            }]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, Popup = kendo.ui.Popup, isFunction = kendo.isFunction, isPlainObject = $.isPlainObject, extend = $.extend, proxy = $.proxy, DOCUMENT = $(document), isLocalUrl = kendo.isLocalUrl, ARIAIDSUFFIX = '_tt_active', DESCRIBEDBY = 'aria-describedby', SHOW = 'show', HIDE = 'hide', ERROR = 'error', CONTENTLOAD = 'contentLoad', REQUESTSTART = 'requestStart', KCONTENTFRAME = 'k-content-frame', TEMPLATE = '<div role="tooltip" class="k-widget k-tooltip#if (!autoHide) {# k-tooltip-closable#}#">#if (!autoHide) {# <div class="k-tooltip-button"><a href="\\#" class="k-icon k-i-close" title="Close"></a></div> #}#' + '<div class="k-tooltip-content"></div>' + '#if (callout){ #<div class="k-callout k-callout-#=dir#"></div>#}#' + '</div>', IFRAMETEMPLATE = kendo.template('<iframe frameborder=\'0\' class=\'' + KCONTENTFRAME + '\' ' + 'src=\'#= content.url #\'>' + 'This page requires frames in order to show content' + '</iframe>'), NS = '.kendoTooltip', POSITIONS = {
                bottom: {
                    origin: 'bottom center',
                    position: 'top center'
                },
                top: {
                    origin: 'top center',
                    position: 'bottom center'
                },
                left: {
                    origin: 'center left',
                    position: 'center right',
                    collision: 'fit flip'
                },
                right: {
                    origin: 'center right',
                    position: 'center left',
                    collision: 'fit flip'
                },
                center: {
                    position: 'center center',
                    origin: 'center center'
                }
            }, REVERSE = {
                'top': 'bottom',
                'bottom': 'top',
                'left': 'right',
                'right': 'left',
                'center': 'center'
            }, DIRCLASSES = {
                bottom: 'n',
                top: 's',
                left: 'e',
                right: 'w',
                center: 'n'
            }, DIMENSIONS = {
                'horizontal': {
                    offset: 'top',
                    size: 'outerHeight'
                },
                'vertical': {
                    offset: 'left',
                    size: 'outerWidth'
                }
            }, DEFAULTCONTENT = function (e) {
                return e.target.data(kendo.ns + 'title');
            };
        function restoreTitle(element) {
            while (element.length) {
                if (restoreTitleAttributeForElement(element)) {
                    break;
                }
                element = element.parent();
            }
        }
        function restoreTitleAttributeForElement(element) {
            var title = element.data(kendo.ns + 'title');
            if (title) {
                element.attr('title', title);
                element.removeData(kendo.ns + 'title');
                return true;
            }
        }
        function saveTitleAttributeForElement(element) {
            var title = element.attr('title');
            if (title) {
                element.data(kendo.ns + 'title', title);
                element.attr('title', '');
                return true;
            }
        }
        function saveTitleAttributes(element) {
            while (element.length && !element.is('body')) {
                if (saveTitleAttributeForElement(element)) {
                    break;
                }
                element = element.parent();
            }
        }
        var Tooltip = Widget.extend({
            init: function (element, options) {
                var that = this, axis;
                Widget.fn.init.call(that, element, options);
                axis = that.options.position.match(/left|right/) ? 'horizontal' : 'vertical';
                that.dimensions = DIMENSIONS[axis];
                that._documentKeyDownHandler = proxy(that._documentKeyDown, that);
                that.element.on(that.options.showOn + NS, that.options.filter, proxy(that._showOn, that));
                if (this._isShownOnMouseEnter() || this._isShownOnClick()) {
                    that.element.on('mouseenter' + NS, that.options.filter, proxy(that._mouseenter, that));
                }
                if (this.options.autoHide && this._isShownOnMouseEnter()) {
                    that.element.on('mouseleave' + NS, that.options.filter, proxy(that._mouseleave, that));
                }
                if (this.options.autoHide && this._isShownOnFocus()) {
                    that.element.on('blur' + NS, that.options.filter, proxy(that._blur, that));
                }
            },
            options: {
                name: 'Tooltip',
                filter: '',
                content: DEFAULTCONTENT,
                showAfter: 100,
                hideAfter: 100,
                callout: true,
                offset: 0,
                position: 'bottom',
                showOn: 'mouseenter',
                autoHide: true,
                width: null,
                height: null,
                animation: {
                    open: {
                        effects: 'fade:in',
                        duration: 0
                    },
                    close: {
                        duration: 40,
                        hide: true
                    }
                }
            },
            events: [
                SHOW,
                HIDE,
                CONTENTLOAD,
                ERROR,
                REQUESTSTART
            ],
            _isShownOnFocus: function () {
                return this.options.showOn && this.options.showOn.match(/focus/);
            },
            _isShownOnMouseEnter: function () {
                return this.options.showOn && this.options.showOn.match(/mouseenter/);
            },
            _isShownOnClick: function () {
                return this.options.showOn && this.options.showOn.match(/click/);
            },
            _mouseenter: function (e) {
                saveTitleAttributes($(e.currentTarget));
            },
            _showOn: function (e) {
                var that = this;
                var currentTarget = $(e.currentTarget);
                if (that._isShownOnClick() && !that._isShownOnMouseEnter()) {
                    that._show(currentTarget);
                } else if (that._isShownOnFocus()) {
                    saveTitleAttributes(currentTarget);
                    that._show(currentTarget);
                } else {
                    clearTimeout(that.timeout);
                    that.timeout = setTimeout(function () {
                        that._show(currentTarget);
                    }, that.options.showAfter);
                }
            },
            _appendContent: function (target) {
                var that = this, contentOptions = that.options.content, element = that.content, showIframe = that.options.iframe, iframe;
                if (isPlainObject(contentOptions) && contentOptions.url) {
                    if (!('iframe' in that.options)) {
                        showIframe = !isLocalUrl(contentOptions.url);
                    }
                    that.trigger(REQUESTSTART, {
                        options: contentOptions,
                        target: target
                    });
                    if (!showIframe) {
                        element.empty();
                        kendo.ui.progress(element, true);
                        that._ajaxRequest(contentOptions);
                    } else {
                        element.hide();
                        iframe = element.find('.' + KCONTENTFRAME)[0];
                        if (iframe) {
                            iframe.src = contentOptions.url || iframe.src;
                        } else {
                            element.html(IFRAMETEMPLATE({ content: contentOptions }));
                        }
                        element.find('.' + KCONTENTFRAME).off('load' + NS).on('load' + NS, function () {
                            that.trigger(CONTENTLOAD);
                            element.show();
                        });
                    }
                } else if (contentOptions && isFunction(contentOptions)) {
                    contentOptions = contentOptions({
                        sender: this,
                        target: target
                    });
                    element.html(contentOptions || '');
                } else {
                    element.html(contentOptions);
                }
                that.angular('compile', function () {
                    return { elements: element };
                });
            },
            _ajaxRequest: function (options) {
                var that = this;
                jQuery.ajax(extend({
                    type: 'GET',
                    dataType: 'html',
                    cache: false,
                    error: function (xhr, status) {
                        kendo.ui.progress(that.content, false);
                        that.trigger(ERROR, {
                            status: status,
                            xhr: xhr
                        });
                    },
                    success: proxy(function (data) {
                        kendo.ui.progress(that.content, false);
                        that.content.html(data);
                        that.trigger(CONTENTLOAD);
                    }, that)
                }, options));
            },
            _documentKeyDown: function (e) {
                if (e.keyCode === kendo.keys.ESC) {
                    this.hide();
                }
            },
            refresh: function () {
                var that = this, popup = that.popup;
                if (popup && popup.options.anchor) {
                    that._appendContent(popup.options.anchor);
                }
            },
            hide: function () {
                if (this.popup) {
                    this.popup.close();
                }
            },
            show: function (target) {
                target = target || this.element;
                saveTitleAttributes(target);
                this._show(target);
            },
            _show: function (target) {
                var that = this, current = that.target();
                if (!that.popup) {
                    that._initPopup();
                }
                if (current && current[0] != target[0]) {
                    that.popup.close();
                    that.popup.element.kendoStop(true, true);
                }
                if (!current || current[0] != target[0]) {
                    that._appendContent(target);
                    that.popup.options.anchor = target;
                }
                that.popup.one('deactivate', function () {
                    restoreTitle(target);
                    target.removeAttr(DESCRIBEDBY);
                    this.element.removeAttr('id').attr('aria-hidden', true);
                    DOCUMENT.off('keydown' + NS, that._documentKeyDownHandler);
                });
                that.popup._hovered = true;
                that.popup.open();
            },
            _initPopup: function () {
                var that = this, options = that.options, wrapper = $(kendo.template(TEMPLATE)({
                        callout: options.callout && options.position !== 'center',
                        dir: DIRCLASSES[options.position],
                        autoHide: options.autoHide
                    }));
                that.popup = new Popup(wrapper, extend({
                    autosize: true,
                    activate: function () {
                        var anchor = this.options.anchor, ariaId = anchor[0].id || that.element[0].id;
                        if (ariaId) {
                            anchor.attr(DESCRIBEDBY, ariaId + ARIAIDSUFFIX);
                            this.element.attr('id', ariaId + ARIAIDSUFFIX);
                        }
                        if (options.callout) {
                            that._positionCallout();
                        } else {
                            that._offset(that.options.position, that.options.offset);
                        }
                        this.element.removeAttr('aria-hidden');
                        DOCUMENT.on('keydown' + NS, that._documentKeyDownHandler);
                        that.trigger(SHOW);
                        that.popup._hovered = undefined;
                    },
                    close: function () {
                        that.trigger(HIDE);
                    },
                    copyAnchorStyles: false,
                    animation: options.animation
                }, POSITIONS[options.position]));
                wrapper.css({
                    width: options.width,
                    height: options.height
                });
                that.content = wrapper.find('.k-tooltip-content');
                that.arrow = wrapper.find('.k-callout');
                if (options.autoHide && this._isShownOnMouseEnter()) {
                    wrapper.on('mouseleave' + NS, proxy(that._mouseleave, that));
                } else {
                    wrapper.on('click' + NS, '.k-tooltip-button', proxy(that._closeButtonClick, that));
                }
            },
            _closeButtonClick: function (e) {
                e.preventDefault();
                this.hide();
            },
            _mouseleave: function (e) {
                var that = this;
                clearTimeout(that.timeout);
                that.timeout = setTimeout(function () {
                    that._closePopup(e.currentTarget);
                }, that.options.hideAfter);
            },
            _blur: function (e) {
                this._closePopup(e.currentTarget);
            },
            _closePopup: function (target) {
                if (this.popup && !this.popup._hovered) {
                    this.popup.close();
                } else {
                    restoreTitle($(target));
                }
            },
            target: function () {
                if (this.popup) {
                    return this.popup.options.anchor;
                }
                return null;
            },
            _positionCallout: function () {
                var that = this, position = that.options.position, dimensions = that.dimensions, offset = dimensions.offset, popup = that.popup, anchor = popup.options.anchor, anchorOffset = $(anchor).offset(), elementOffset = $(popup.element).offset(), cssClass = DIRCLASSES[popup.flipped ? REVERSE[position] : position], offsetAmount = anchorOffset[offset] - elementOffset[offset] + $(anchor)[dimensions.size]() / 2;
                that._offset(position, that.options.offset);
                that.arrow.removeClass('k-callout-n k-callout-s k-callout-w k-callout-e').addClass('k-callout-' + cssClass).css(offset, offsetAmount);
            },
            destroy: function () {
                var popup = this.popup;
                if (popup) {
                    popup.element.off(NS);
                    popup.destroy();
                }
                clearTimeout(this.timeout);
                this.element.off(NS);
                DOCUMENT.off('keydown' + NS, this._documentKeyDownHandler);
                Widget.fn.destroy.call(this);
            },
            _offset: function (position, offsetAmount) {
                var that = this, isTopLeft = position == 'top' || position == 'left', isFlipped = that.popup.flipped, direction = isTopLeft && isFlipped || !isTopLeft && !isFlipped ? 1 : -1, marginRule = isTopLeft ? 'margin-' + position : 'margin-' + REVERSE[position], offset = kendo._outerWidth(that.arrow) / 2 + offsetAmount;
                that.popup.wrapper.css(marginRule, offset * direction + 'px');
            }
        });
        kendo.ui.plugin(Tooltip);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.list', [
        'kendo.data',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'list',
        name: 'List',
        category: 'framework',
        depends: [
            'data',
            'popup'
        ],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, outerHeight = kendo._outerHeight, percentageUnitsRegex = /^\d+(\.\d+)?%$/i, Widget = ui.Widget, keys = kendo.keys, support = kendo.support, htmlEncode = kendo.htmlEncode, activeElement = kendo._activeElement, outerWidth = kendo._outerWidth, ObservableArray = kendo.data.ObservableArray, ID = 'id', CHANGE = 'change', FOCUSED = 'k-state-focused', HOVER = 'k-state-hover', LOADING = 'k-i-loading', GROUPHEADER = '.k-group-header', ITEMSELECTOR = '.k-item', LABELIDPART = '_label', OPEN = 'open', CLOSE = 'close', CASCADE = 'cascade', SELECT = 'select', SELECTED = 'selected', REQUESTSTART = 'requestStart', REQUESTEND = 'requestEnd', extend = $.extend, proxy = $.proxy, isArray = $.isArray, browser = support.browser, HIDDENCLASS = 'k-hidden', WIDTH = 'width', isIE = browser.msie, isIE8 = isIE && browser.version < 9, quotRegExp = /"/g, alternativeNames = {
                'ComboBox': 'DropDownList',
                'DropDownList': 'ComboBox'
            };
        var List = kendo.ui.DataBoundWidget.extend({
            init: function (element, options) {
                var that = this, ns = that.ns, id;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                that._isSelect = element.is(SELECT);
                if (that._isSelect && that.element[0].length) {
                    if (!options.dataSource) {
                        options.dataTextField = options.dataTextField || 'text';
                        options.dataValueField = options.dataValueField || 'value';
                    }
                }
                that.ul = $('<ul unselectable="on" class="k-list k-reset"/>').attr({
                    tabIndex: -1,
                    'aria-hidden': true
                });
                that.list = $('<div class=\'k-list-container\'/>').append(that.ul).on('mousedown' + ns, proxy(that._listMousedown, that));
                id = element.attr(ID);
                if (!id) {
                    id = kendo.guid();
                }
                that.list.attr(ID, id + '-list');
                that.ul.attr(ID, id + '_listbox');
                if (options.columns && options.columns.length) {
                    that.ul.removeClass('k-list').addClass('k-grid-list');
                    that._columnsHeader();
                }
                that._header();
                that._noData();
                that._footer();
                that._accessors();
                that._initValue();
            },
            options: {
                valuePrimitive: false,
                footerTemplate: '',
                headerTemplate: '',
                noDataTemplate: 'No data found.'
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                if (options && options.enable !== undefined) {
                    options.enabled = options.enable;
                }
                if (options.columns && options.columns.length) {
                    this._columnsHeader();
                }
                this._header();
                this._noData();
                this._footer();
                this._renderFooter();
                this._renderNoData();
            },
            focus: function () {
                this._focused.focus();
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            _header: function () {
                var list = this;
                var header = $(list.header);
                var template = list.options.headerTemplate;
                this._angularElement(header, 'cleanup');
                kendo.destroy(header);
                header.remove();
                if (!template) {
                    list.header = null;
                    return;
                }
                var headerTemplate = typeof template !== 'function' ? kendo.template(template) : template;
                header = $(headerTemplate({}));
                list.header = header[0] ? header : null;
                list.list.prepend(header);
                this._angularElement(list.header, 'compile');
            },
            _columnsHeader: function () {
                var list = this;
                var columnsHeader = $(list.columnsHeader);
                this._angularElement(columnsHeader, 'cleanup');
                kendo.destroy(columnsHeader);
                columnsHeader.remove();
                var header = '<div class=\'k-grid-header\'><div class=\'k-grid-header-wrap\'><table>';
                var colGroup = '<colgroup>';
                var row = '<tr>';
                for (var idx = 0; idx < this.options.columns.length; idx++) {
                    var currentColumn = this.options.columns[idx];
                    var title = currentColumn.title || currentColumn.field || '';
                    var template = currentColumn.headerTemplate || title;
                    var columnsHeaderTemplate = typeof template !== 'function' ? kendo.template(template) : template;
                    var currentWidth = currentColumn.width;
                    var currentWidthInt = parseInt(currentWidth, 10);
                    var widthStyle = '';
                    if (currentWidth && !isNaN(currentWidthInt)) {
                        widthStyle += 'style=\'width:';
                        widthStyle += currentWidthInt;
                        widthStyle += percentageUnitsRegex.test(currentWidth) ? '%' : 'px';
                        widthStyle += ';\'';
                    }
                    colGroup += '<col ' + widthStyle + '/>';
                    row += '<th class=\'k-header\'>';
                    row += columnsHeaderTemplate(currentColumn);
                    row += '</th>';
                }
                colGroup += '</colgroup>';
                row += '</tr>';
                header += colGroup;
                header += row;
                header += '</table></div></div>';
                list.columnsHeader = columnsHeader = $(header);
                list.list.prepend(columnsHeader);
                this._angularElement(list.columnsHeader, 'compile');
            },
            _noData: function () {
                var list = this;
                var noData = $(list.noData);
                var template = list.options.noDataTemplate;
                list.angular('cleanup', function () {
                    return { elements: noData };
                });
                kendo.destroy(noData);
                noData.remove();
                if (!template) {
                    list.noData = null;
                    return;
                }
                list.noData = $('<div class="k-nodata" style="display:none"><div></div></div>').appendTo(list.list);
                list.noDataTemplate = typeof template !== 'function' ? kendo.template(template) : template;
            },
            _footer: function () {
                var list = this;
                var footer = $(list.footer);
                var template = list.options.footerTemplate;
                this._angularElement(footer, 'cleanup');
                kendo.destroy(footer);
                footer.remove();
                if (!template) {
                    list.footer = null;
                    return;
                }
                list.footer = $('<div class="k-footer"></div>').appendTo(list.list);
                list.footerTemplate = typeof template !== 'function' ? kendo.template(template) : template;
            },
            _listOptions: function (options) {
                var that = this;
                var currentOptions = that.options;
                var virtual = currentOptions.virtual;
                var changeEventOption = { change: proxy(that._listChange, that) };
                var listBoundHandler = proxy(that._listBound, that);
                virtual = typeof virtual === 'object' ? virtual : {};
                options = $.extend({
                    autoBind: false,
                    selectable: true,
                    dataSource: that.dataSource,
                    click: proxy(that._click, that),
                    activate: proxy(that._activateItem, that),
                    columns: currentOptions.columns,
                    deactivate: proxy(that._deactivateItem, that),
                    dataBinding: function () {
                        that.trigger('dataBinding');
                    },
                    dataBound: listBoundHandler,
                    height: currentOptions.height,
                    dataValueField: currentOptions.dataValueField,
                    dataTextField: currentOptions.dataTextField,
                    groupTemplate: currentOptions.groupTemplate,
                    fixedGroupTemplate: currentOptions.fixedGroupTemplate,
                    template: currentOptions.template
                }, options, virtual, changeEventOption);
                if (!options.template) {
                    options.template = '#:' + kendo.expr(options.dataTextField, 'data') + '#';
                }
                if (currentOptions.$angular) {
                    options.$angular = currentOptions.$angular;
                }
                return options;
            },
            _initList: function () {
                var that = this;
                var listOptions = that._listOptions({ selectedItemChange: proxy(that._listChange, that) });
                if (!that.options.virtual) {
                    that.listView = new kendo.ui.StaticList(that.ul, listOptions);
                } else {
                    that.listView = new kendo.ui.VirtualList(that.ul, listOptions);
                }
                that.listView.bind('listBound', proxy(that._listBound, that));
                that._setListValue();
            },
            _setListValue: function (value) {
                value = value || this.options.value;
                if (value !== undefined) {
                    this.listView.value(value).done(proxy(this._updateSelectionState, this));
                }
            },
            _updateSelectionState: $.noop,
            _listMousedown: function (e) {
                if (!this.filterInput || this.filterInput[0] !== e.target) {
                    e.preventDefault();
                }
            },
            _isFilterEnabled: function () {
                var filter = this.options.filter;
                return filter && filter !== 'none';
            },
            _hideClear: function () {
                var list = this;
                if (list._clear) {
                    list._clear.addClass(HIDDENCLASS);
                }
            },
            _showClear: function () {
                if (this._clear) {
                    this._clear.removeClass(HIDDENCLASS);
                }
            },
            _clearValue: function () {
                this._clearText();
                this._accessor('');
                this.listView.value([]);
                if (this._isSelect) {
                    this._customOption = undefined;
                }
                if (this._isFilterEnabled() && !this.options.enforceMinLength) {
                    this._filter({
                        word: '',
                        open: false
                    });
                    if (this.options.highlightFirst) {
                        this.listView.focus(0);
                    }
                }
                this._change();
            },
            _clearText: function () {
                this.text('');
            },
            _clearFilter: function () {
                if (!this.options.virtual) {
                    this.listView.bound(false);
                }
                this._filterSource();
            },
            _filterSource: function (filter, force) {
                var that = this;
                var options = that.options;
                var isMultiColumnFiltering = options.filterFields && filter && filter.logic && filter.filters && filter.filters.length;
                var dataSource = that.dataSource;
                var expression = extend({}, dataSource.filter() || {});
                var resetPageSettings = filter || expression.filters && expression.filters.length && !filter;
                var removed = removeFiltersForField(expression, options.dataTextField);
                this._clearFilterExpressions(expression);
                if ((filter || removed) && that.trigger('filtering', { filter: filter })) {
                    return;
                }
                var newExpression = {
                    filters: [],
                    logic: 'and'    // logic: expression.logic || 'and'    //Custom Change// // don't keep //  (-- LIST --)
                };
                if (isMultiColumnFiltering) {
                    newExpression.filters.push(filter);
                } else {
                    this._pushFilterExpression(newExpression, filter);
                }
                if (isValidFilterExpr(expression)) {
                    if (newExpression.logic === expression.logic) {
                        newExpression.filters = newExpression.filters.concat(expression.filters);
                    } else {
                        newExpression.filters.push(expression);
                    }
                }
                if (that._cascading) {
                    this.listView.setDSFilter(newExpression);
                }
                var dataSourceState = extend({}, {
                    page: resetPageSettings ? 1 : dataSource.page(),
                    pageSize: resetPageSettings ? dataSource.options.pageSize : dataSource.pageSize(),
                    sort: dataSource.sort(),
                    filter: dataSource.filter(),
                    group: dataSource.group(),
                    aggregate: dataSource.aggregate()
                }, { filter: newExpression });
                return dataSource[force ? 'read' : 'query'](dataSource._mergeState(dataSourceState));
            },
            _pushFilterExpression: function (newExpression, filter) {
                if (isValidFilterExpr(filter) && filter.value !== '') {
                    newExpression.filters.push(filter);
                }
            },
            _clearFilterExpressions: function (expression) {
                if (!expression.filters) {
                    return;
                }
                var filtersToRemove;
                for (var i = 0; i < expression.filters.length; i++) {
                    if ('fromFilter' in expression.filters[i]) {
                        filtersToRemove = i;
                    }
                }
                if (!isNaN(filtersToRemove)) {
                    expression.filters.splice(filtersToRemove, 1);
                }
            },
            _angularElement: function (element, action) {
                if (!element) {
                    return;
                }
                this.angular(action, function () {
                    return { elements: element };
                });
            },
            _renderNoData: function () {
                var list = this;
                var noData = list.noData;
                if (!noData) {
                    return;
                }
                this._angularElement(noData, 'cleanup');
                noData.children(':first').html(list.noDataTemplate({ instance: list }));
                this._angularElement(noData, 'compile');
            },
            _toggleNoData: function (show) {
                $(this.noData).toggle(show);
            },
            _toggleHeader: function (show) {
                var groupHeader = this.listView.content.prev(GROUPHEADER);
                groupHeader.toggle(show);
            },
            _renderFooter: function () {
                var list = this;
                var footer = list.footer;
                if (!footer) {
                    return;
                }
                this._angularElement(footer, 'cleanup');
                footer.html(list.footerTemplate({ instance: list }));
                this._angularElement(footer, 'compile');
            },
            _allowOpening: function () {
                return this.options.noDataTemplate || this.dataSource.flatView().length;
            },
            _initValue: function () {
                var that = this, value = that.options.value;
                if (value !== null) {
                    that.element.val(value);
                } else {
                    value = that._accessor();
                    that.options.value = value;
                }
                that._old = value;
            },
            _ignoreCase: function () {
                var that = this, model = that.dataSource.reader.model, field;
                if (model && model.fields) {
                    field = model.fields[that.options.dataTextField];
                    if (field && field.type && field.type !== 'string') {
                        that.options.ignoreCase = false;
                    }
                }
            },
            _focus: function (candidate) {
                return this.listView.focus(candidate);
            },
            _filter: function (options) {
                var that = this;
                var widgetOptions = that.options;
                var word = options.word;
                var filterFields = widgetOptions.filterFields;
                var field = widgetOptions.dataTextField;
                var expression;
                if (filterFields && filterFields.length) {
                    expression = {
                        logic: 'or',
                        filters: [],
                        fromFilter: true
                    };
                    for (var i = 0; i < filterFields.length; i++) {
                        this._pushFilterExpression(expression, that._buildExpression(word, filterFields[i]));
                    }
                } else {
                    expression = that._buildExpression(word, field);
                }
                that._open = options.open;
                that._filterSource(expression);
            },
            _buildExpression: function (value, field) {
                var that = this;
                var widgetOptions = that.options;
                var ignoreCase = widgetOptions.ignoreCase;
                var accentFoldingFiltering = that.dataSource.options.accentFoldingFiltering;
                return {
                    value: ignoreCase ? accentFoldingFiltering ? value.toLocaleLowerCase(accentFoldingFiltering) : value.toLowerCase() : value,
                    field: field,
                    operator: widgetOptions.filter,
                    ignoreCase: ignoreCase
                };
            },
            _clearButton: function () {
                var list = this;
                var clearTitle = list.options.messages && list.options.messages.clear ? list.options.messages.clear : 'clear';
                if (!list._clear) {
                    list._clear = $('<span unselectable="on" class="k-icon k-clear-value k-i-close" title="' + clearTitle + '"></span>').attr({
                        'role': 'button',
                        'tabIndex': -1
                    });
                }
                if (!list.options.clearButton) {
                    list._clear.remove();
                }
                this._hideClear();
            },
            search: function (word) {
                var options = this.options;
                word = typeof word === 'string' ? word : this._inputValue();
                clearTimeout(this._typingTimeout);
                if (!options.enforceMinLength && !word.length || word.length >= options.minLength) {
                    this._state = 'filter';
                    if (this.listView) {
                        this.listView._emptySearch = !$.trim(word).length;
                    }
                    if (!this._isFilterEnabled()) {
                        this._searchByWord(word);
                    } else {
                        this._filter({
                            word: word,
                            open: true
                        });
                    }
                }
            },
            current: function (candidate) {
                return this._focus(candidate);
            },
            items: function () {
                return this.ul[0].children;
            },
            destroy: function () {
                var that = this;
                var ns = that.ns;
                Widget.fn.destroy.call(that);
                that._unbindDataSource();
                that.listView.destroy();
                that.list.off(ns);
                that.popup.destroy();
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
            },
            dataItem: function (index) {
                var that = this;
                if (index === undefined) {
                    return that.listView.selectedDataItems()[0];
                }
                if (typeof index !== 'number') {
                    if (that.options.virtual) {
                        return that.dataSource.getByUid($(index).data('uid'));
                    }
                    index = $(that.items()).index(index);
                }
                return that.dataSource.flatView()[index];
            },
            _activateItem: function () {
                var current = this.listView.focus();
                if (current) {
                    this._focused.add(this.filterInput).attr('aria-activedescendant', current.attr('id'));
                }
            },
            _deactivateItem: function () {
                this._focused.add(this.filterInput).removeAttr('aria-activedescendant');
            },
            _accessors: function () {
                var that = this;
                var element = that.element;
                var options = that.options;
                var getter = kendo.getter;
                var textField = element.attr(kendo.attr('text-field'));
                var valueField = element.attr(kendo.attr('value-field'));
                if (!options.dataTextField && textField) {
                    options.dataTextField = textField;
                }
                if (!options.dataValueField && valueField) {
                    options.dataValueField = valueField;
                }
                that._text = getter(options.dataTextField);
                that._value = getter(options.dataValueField);
            },
            _aria: function (id) {
                var that = this, options = that.options, element = that._focused.add(that.filterInput);
                if (options.suggest !== undefined) {
                    element.attr('aria-autocomplete', options.suggest ? 'both' : 'list');
                }
                id = id ? id + ' ' + that.ul[0].id : that.ul[0].id;
                element.attr('aria-owns', id);
                that.ul.attr('aria-live', !that._isFilterEnabled() ? 'off' : 'polite');
                that._ariaLabel();
            },
            _ariaLabel: function () {
                var that = this;
                var focusedElm = that._focused;
                var inputElm = that.element;
                var inputId = inputElm.attr('id');
                var labelElm = $('label[for="' + inputId + '"]');
                var ariaLabel = inputElm.attr('aria-label');
                var ariaLabelledBy = inputElm.attr('aria-labelledby');
                if (focusedElm === inputElm) {
                    return;
                }
                if (ariaLabel) {
                    focusedElm.attr('aria-label', ariaLabel);
                } else if (ariaLabelledBy) {
                    focusedElm.attr('aria-labelledby', ariaLabelledBy);
                } else if (labelElm.length) {
                    var labelId = labelElm.attr('id') || that._generateLabelId(labelElm, inputId || kendo.guid());
                    focusedElm.attr('aria-labelledby', labelId);
                }
            },
            _generateLabelId: function (label, inputId) {
                var labelId = inputId + LABELIDPART;
                label.attr('id', labelId);
                return labelId;
            },
            _blur: function () {
                var that = this;
                that._change();
                that.close();
            },
            _change: function () {
                var that = this;
                var index = that.selectedIndex;
                var optionValue = that.options.value;
                var value = that.value();
                var trigger;
                if (that._isSelect && !that.listView.bound() && optionValue) {
                    value = optionValue;
                }
                if (value !== unifyType(that._old, typeof value) && value !== unifyType(that._oldText, typeof value)) {
                    trigger = true;
                } else if (that._valueBeforeCascade !== undefined && that._valueBeforeCascade !== unifyType(that._old, typeof that._valueBeforeCascade) && that._userTriggered) {
                    trigger = true;
                } else if (index !== undefined && index !== that._oldIndex && !that.listView.isFiltered()) {
                    trigger = true;
                }
                if (trigger) {
                    if (that._old === null || that._old === '' || value === '') {
                        that._valueBeforeCascade = that._old = value;
                    } else {
                        if (that.dataItem()) {
                            that._valueBeforeCascade = that._old = that.options.dataValueField ? that.dataItem()[that.options.dataValueField] : that.dataItem();
                        } else {
                            that._valueBeforeCascade = that._old = null;
                        }
                    }
                    that._oldIndex = index;
                    that._oldText = that.text && that.text();
                    if (!that._typing) {
                        that.element.trigger(CHANGE);
                    }
                    that.trigger(CHANGE);
                }
                that.typing = false;
            },
            _data: function () {
                return this.dataSource.view();
            },
            _enable: function () {
                var that = this, options = that.options, disabled = that.element.is('[disabled]');
                if (options.enable !== undefined) {
                    options.enabled = options.enable;
                }
                if (!options.enabled || disabled) {
                    that.enable(false);
                } else {
                    that.readonly(that.element.is('[readonly]'));
                }
            },
            _dataValue: function (dataItem) {
                var value = this._value(dataItem);
                if (value === undefined) {
                    value = this._text(dataItem);
                }
                return value;
            },
            _offsetHeight: function () {
                var offsetHeight = 0;
                var siblings = this.listView.content.prevAll(':visible');
                siblings.each(function () {
                    var element = $(this);
                    offsetHeight += outerHeight(element, true);
                });
                return offsetHeight;
            },
            _height: function (length) {
                var that = this;
                var list = that.list;
                var height = that.options.height;
                var visible = that.popup.visible();
                var offsetTop;
                var popups;
                var footerHeight;
                if (length || that.options.noDataTemplate) {
                    popups = list.add(list.parent('.k-animation-container')).show();
                    if (!list.is(':visible')) {
                        popups.hide();
                        return;
                    }
                    height = that.listView.content[0].scrollHeight > height ? height : 'auto';
                    popups.height(height);
                    if (height !== 'auto') {
                        offsetTop = that._offsetHeight();
                        footerHeight = outerHeight($(that.footer)) || 0;
                        height = height - offsetTop - footerHeight;
                    }
                    that.listView.content.height(height);
                    if (!visible) {
                        popups.hide();
                    }
                }
                return height;
            },
            _openHandler: function (e) {
                this._adjustListWidth();
                if (this.trigger(OPEN)) {
                    e.preventDefault();
                } else {
                    this._focused.attr('aria-expanded', true);
                    this.ul.attr('aria-hidden', false);
                }
            },
            _adjustListWidth: function () {
                var that = this, list = that.list, width = list[0].style.width, wrapper = that.wrapper, computedStyle, computedWidth;
                if (!list.data(WIDTH) && width) {
                    return;
                }
                computedStyle = window.getComputedStyle ? window.getComputedStyle(wrapper[0], null) : 0;
                computedWidth = parseFloat(computedStyle && computedStyle.width) || outerWidth(wrapper);
                if (computedStyle && browser.msie) {
                    computedWidth += parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) + parseFloat(computedStyle.borderLeftWidth) + parseFloat(computedStyle.borderRightWidth);
                }
                if (list.css('box-sizing') !== 'border-box') {
                    width = computedWidth - (outerWidth(list) - list.width());
                } else {
                    width = computedWidth;
                }
                list.css({
                    fontFamily: wrapper.css('font-family'),
                    width: that.options.autoWidth ? 'auto' : width,
                    minWidth: width,
                    whiteSpace: that.options.autoWidth ? 'nowrap' : 'normal'
                }).data(WIDTH, width);
                return true;
            },
            _closeHandler: function (e) {
                if (this.trigger(CLOSE)) {
                    e.preventDefault();
                } else {
                    this._focused.attr('aria-expanded', false);
                    this.ul.attr('aria-hidden', true);
                }
            },
            _focusItem: function () {
                var listView = this.listView;
                var noFocusedItem = !listView.focus();
                var index = last(listView.select());
                if (index === undefined && this.options.highlightFirst && noFocusedItem) {
                    index = 0;
                }
                if (index !== undefined) {
                    listView.focus(index);
                } else if (noFocusedItem) {
                    listView.scrollToIndex(0);
                }
            },
            _calculateGroupPadding: function (height) {
                var li = this.ul.children('.k-first:first');
                var groupHeader = this.listView.content.prev(GROUPHEADER);
                var padding = 0;
                var direction = 'right';
                if (groupHeader[0] && groupHeader[0].style.display !== 'none') {
                    if (height !== 'auto') {
                        padding = kendo.support.scrollbar();
                    }
                    if (this.element.parents('.k-rtl').length) {
                        direction = 'left';
                    }
                    padding += parseFloat(li.css('border-' + direction + '-width'), 10) + parseFloat(li.children('.k-group').css('padding-' + direction), 10);
                    groupHeader.css('padding-' + direction, padding);
                }
            },
            _calculatePopupHeight: function (force) {
                var height = this._height(this.dataSource.flatView().length || force);
                this._calculateGroupPadding(height);
                this._calculateColumnsHeaderPadding(height);
            },
            _calculateColumnsHeaderPadding: function (height) {
                if (this.options.columns && this.options.columns.length) {
                    var list = this;
                    var isRtl = support.isRtl(list.wrapper);
                    var scrollbar = kendo.support.scrollbar();
                    list.columnsHeader.css(isRtl ? 'padding-left' : 'padding-right', height !== 'auto' ? scrollbar : 0);
                }
            },
            _refreshScroll: function () {
                var listView = this.listView;
                var enableYScroll = listView.element.height() > listView.content.height();
                if (this.options.autoWidth) {
                    listView.content.css({
                        overflowX: 'hidden',
                        overflowY: enableYScroll ? 'scroll' : 'auto'
                    });
                }
            },
            _resizePopup: function (force) {
                if (this.options.virtual) {
                    return;
                }
                if (!this.popup.element.is(':visible')) {
                    this.popup.one('open', function (force) {
                        return proxy(function () {
                            this._calculatePopupHeight(force);
                        }, this);
                    }.call(this, force));
                    this.popup.one('activate', proxy(this._refreshScroll, this));
                } else {
                    this._calculatePopupHeight(force);
                }
            },
            _popup: function () {
                var list = this;
                list.popup = new ui.Popup(list.list, extend({}, list.options.popup, {
                    anchor: list.wrapper,
                    open: proxy(list._openHandler, list),
                    close: proxy(list._closeHandler, list),
                    animation: list.options.animation,
                    isRtl: support.isRtl(list.wrapper),
                    autosize: list.options.autoWidth
                }));
            },
            _makeUnselectable: function () {
                if (isIE8) {
                    this.list.find('*').not('.k-textbox').attr('unselectable', 'on');
                }
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _toggle: function (open, preventFocus) {
                var that = this;
                var touchEnabled = support.mobileOS && (support.touch || support.MSPointers || support.pointers);
                open = open !== undefined ? open : !that.popup.visible();
                if (!preventFocus && !touchEnabled && that._focused[0] !== activeElement()) {
                    that._prevent = true;
                    that._focused.focus();
                    that._prevent = false;
                }
                that[open ? OPEN : CLOSE]();
            },
            _triggerCascade: function () {
                var that = this;
                if (!that._cascadeTriggered || that.value() !== unifyType(that._cascadedValue, typeof that.value())) {
                    that._cascadedValue = that.value();
                    that._cascadeTriggered = true;
                    that.trigger(CASCADE, { userTriggered: that._userTriggered });
                }
            },
            _triggerChange: function () {
                if (this._valueBeforeCascade !== this.value()) {
                    this.trigger(CHANGE);
                }
            },
            _unbindDataSource: function () {
                var that = this;
                that.dataSource.unbind(REQUESTSTART, that._requestStartHandler).unbind(REQUESTEND, that._requestEndHandler).unbind('error', that._errorHandler);
            },
            requireValueMapper: function (options, value) {
                var hasValue = (options.value instanceof Array ? options.value.length : options.value) || (value instanceof Array ? value.length : value);
                if (hasValue && options.virtual && typeof options.virtual.valueMapper !== 'function') {
                    throw new Error('ValueMapper is not provided while the value is being set. See http://docs.telerik.com/kendo-ui/controls/editors/combobox/virtualization#the-valuemapper-function');
                }
            }
        });
        function unifyType(value, type) {
            if (value !== undefined && value !== '' && value !== null) {
                if (type === 'boolean') {
                    value = Boolean(value);
                } else if (type === 'number') {
                    value = Number(value);
                } else if (type === 'string') {
                    value = value.toString();
                }
            }
            return value;
        }
        extend(List, {
            inArray: function (node, parentNode) {
                var idx, length, siblings = parentNode.children;
                if (!node || node.parentNode !== parentNode) {
                    return -1;
                }
                for (idx = 0, length = siblings.length; idx < length; idx++) {
                    if (node === siblings[idx]) {
                        return idx;
                    }
                }
                return -1;
            },
            unifyType: unifyType
        });
        kendo.ui.List = List;
        ui.Select = List.extend({
            init: function (element, options) {
                List.fn.init.call(this, element, options);
                this._initial = this.element.val();
            },
            setDataSource: function (dataSource) {
                var that = this;
                var parent;
                that.options.dataSource = dataSource;
                that._dataSource();
                if (that.listView.bound()) {
                    that._initialIndex = null;
                    that.listView._current = null;
                }
                that.listView.setDataSource(that.dataSource);
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                }
                parent = that._parentWidget();
                if (parent) {
                    that._cascadeSelect(parent);
                }
            },
            close: function () {
                this.popup.close();
            },
            select: function (candidate) {
                var that = this;
                if (candidate === undefined) {
                    return that.selectedIndex;
                } else {
                    return that._select(candidate).done(function () {
                        that._cascadeValue = that._old = that._accessor();
                        that._oldIndex = that.selectedIndex;
                    });
                }
            },
            _accessor: function (value, idx) {
                return this[this._isSelect ? '_accessorSelect' : '_accessorInput'](value, idx);
            },
            _accessorInput: function (value) {
                var element = this.element[0];
                if (value === undefined) {
                    return element.value;
                } else {
                    if (value === null) {
                        value = '';
                    }
                    element.value = value;
                }
            },
            _accessorSelect: function (value, idx) {
                var element = this.element[0];
                var hasValue;
                if (value === undefined) {
                    return getSelectedOption(element).value || '';
                }
                getSelectedOption(element).selected = false;
                if (idx === undefined) {
                    idx = -1;
                }
                hasValue = value !== null && value !== '';
                if (hasValue && idx == -1) {
                    this._custom(value);
                } else {
                    if (value) {
                        element.value = value;
                    } else {
                        element.selectedIndex = idx;
                    }
                }
            },
            _syncValueAndText: function () {
                return true;
            },
            _custom: function (value) {
                var that = this;
                var element = that.element;
                var custom = that._customOption;
                if (!custom) {
                    custom = $('<option/>');
                    that._customOption = custom;
                    element.append(custom);
                }
                custom.text(value);
                custom[0].selected = true;
            },
            _hideBusy: function () {
                var that = this;
                clearTimeout(that._busy);
                that._arrowIcon.removeClass(LOADING);
                that._focused.attr('aria-busy', false);
                that._busy = null;
                that._showClear();
            },
            _showBusy: function (e) {
                var that = this;
                if (e.isDefaultPrevented()) {
                    return;
                }
                that._request = true;
                if (that._busy) {
                    return;
                }
                that._busy = setTimeout(function () {
                    if (that._arrowIcon) {
                        that._focused.attr('aria-busy', true);
                        that._arrowIcon.addClass(LOADING);
                        that._hideClear();
                    }
                }, 100);
            },
            _requestEnd: function () {
                this._request = false;
                this._hideBusy();
            },
            _dataSource: function () {
                var that = this, element = that.element, options = that.options, dataSource = options.dataSource || {}, idx;
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                if (that._isSelect) {
                    idx = element[0].selectedIndex;
                    if (idx > -1) {
                        options.index = idx;
                    }
                    dataSource.select = element;
                    dataSource.fields = [
                        { field: options.dataTextField },
                        { field: options.dataValueField }
                    ];
                }
                if (that.dataSource) {
                    that._unbindDataSource();
                } else {
                    that._requestStartHandler = proxy(that._showBusy, that);
                    that._requestEndHandler = proxy(that._requestEnd, that);
                    that._errorHandler = proxy(that._hideBusy, that);
                }
                that.dataSource = kendo.data.DataSource.create(dataSource).bind(REQUESTSTART, that._requestStartHandler).bind(REQUESTEND, that._requestEndHandler).bind('error', that._errorHandler);
            },
            _firstItem: function () {
                this.listView.focusFirst();
            },
            _lastItem: function () {
                this.listView.focusLast();
            },
            _nextItem: function () {
                this.listView.focusNext();
            },
            _prevItem: function () {
                this.listView.focusPrev();
            },
            _move: function (e) {
                var that = this;
                var listView = that.listView;
                var key = e.keyCode;
                var down = key === keys.DOWN;
                var dataItem;
                var pressed;
                var current;
                if (key === keys.UP || down) {
                    if (e.altKey) {
                        that.toggle(down);
                    } else {
                        if (!listView.bound() && !that.ul[0].firstChild) {
                            if (!that._fetch) {
                                that.dataSource.one(CHANGE, function () {
                                    that._fetch = false;
                                    that._move(e);
                                });
                                that._fetch = true;
                                that._filterSource();
                            }
                            e.preventDefault();
                            return true;
                        }
                        current = that._focus();
                        if (!that._fetch && (!current || current.hasClass('k-state-selected'))) {
                            if (down) {
                                that._nextItem();
                                if (!that._focus()) {
                                    that._lastItem();
                                }
                            } else {
                                that._prevItem();
                                if (!that._focus()) {
                                    that._firstItem();
                                }
                            }
                        }
                        dataItem = listView.dataItemByIndex(listView.getElementIndex(that._focus()));
                        if (that.trigger(SELECT, {
                                dataItem: dataItem,
                                item: that._focus()
                            })) {
                            that._focus(current);
                            return;
                        }
                        that._select(that._focus(), true).done(function () {
                            if (!that.popup.visible()) {
                                that._blur();
                            }
                            if (that._cascadedValue === null) {
                                that._cascadedValue = that.value();
                            } else {
                                that._cascadedValue = that.dataItem() ? that.dataItem()[that.options.dataValueField] || that.dataItem() : null;
                            }
                        });
                    }
                    e.preventDefault();
                    pressed = true;
                } else if (key === keys.ENTER || key === keys.TAB) {
                    if (that.popup.visible()) {
                        e.preventDefault();
                    }
                    current = that._focus();
                    dataItem = that.dataItem();
                    if (!that.popup.visible() && (!dataItem || that.text() !== that._text(dataItem))) {
                        current = null;
                    }
                    var activeFilter = that.filterInput && that.filterInput[0] === activeElement();
                    var selection;
                    if (current) {
                        dataItem = listView.dataItemByIndex(listView.getElementIndex(current));
                        var shouldTrigger = true;
                        if (dataItem) {
                            shouldTrigger = that._value(dataItem) !== List.unifyType(that.value(), typeof that._value(dataItem));
                        }
                        if (shouldTrigger && that.trigger(SELECT, {
                                dataItem: dataItem,
                                item: current
                            })) {
                            return;
                        }
                        selection = that._select(current);
                    } else if (that.input) {
                        if (that._syncValueAndText() || that._isSelect) {
                            that._accessor(that.input.val());
                        }
                        that.listView.value(that.input.val());
                    }
                    if (that._focusElement) {
                        that._focusElement(that.wrapper);
                    }
                    if (activeFilter && key === keys.TAB) {
                        that.wrapper.focusout();
                    } else {
                        if (selection && typeof selection.done === 'function') {
                            selection.done(function () {
                                that._blur();
                            });
                        } else {
                            that._blur();
                        }
                    }
                    that.close();
                    pressed = true;
                } else if (key === keys.ESC) {
                    if (that.popup.visible()) {
                        e.preventDefault();
                    }
                    that.close();
                    pressed = true;
                } else if (that.popup.visible() && (key === keys.PAGEDOWN || key === keys.PAGEUP)) {
                    e.preventDefault();
                    var direction = key === keys.PAGEDOWN ? 1 : -1;
                    listView.scrollWith(direction * listView.screenHeight());
                    pressed = true;
                }
                return pressed;
            },
            _fetchData: function () {
                var that = this;
                var hasItems = !!that.dataSource.view().length;
                if (that._request || that.options.cascadeFrom) {
                    return;
                }
                if (!that.listView.bound() && !that._fetch && !hasItems) {
                    that._fetch = true;
                    that.dataSource.fetch().done(function () {
                        that._fetch = false;
                    });
                }
            },
            _options: function (data, optionLabel, value) {
                var that = this, element = that.element, htmlElement = element[0], length = data.length, options = '', option, dataItem, dataText, dataValue, idx = 0;
                if (optionLabel) {
                    options = optionLabel;
                }
                for (; idx < length; idx++) {
                    option = '<option';
                    dataItem = data[idx];
                    dataText = that._text(dataItem);
                    dataValue = that._value(dataItem);
                    if (dataValue !== undefined) {
                        dataValue += '';
                        if (dataValue.indexOf('"') !== -1) {
                            dataValue = dataValue.replace(quotRegExp, '&quot;');
                        }
                        option += ' value="' + dataValue + '"';
                    }
                    option += '>';
                    if (dataText !== undefined) {
                        option += htmlEncode(dataText);
                    }
                    option += '</option>';
                    options += option;
                }
                element.html(options);
                if (value !== undefined) {
                    htmlElement.value = value;
                    if (htmlElement.value && !value) {
                        htmlElement.selectedIndex = -1;
                    }
                }
                if (htmlElement.selectedIndex !== -1) {
                    option = getSelectedOption(htmlElement);
                    if (option) {
                        option.setAttribute(SELECTED, SELECTED);
                    }
                }
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(that._initial);
                        });
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            },
            _parentWidget: function () {
                var name = this.options.name;
                if (!this.options.cascadeFrom) {
                    return;
                }
                var parentElement = $('#' + this.options.cascadeFrom);
                var parent = parentElement.data('kendo' + name);
                if (!parent) {
                    parent = parentElement.data('kendo' + alternativeNames[name]);
                }
                return parent;
            },
            _cascade: function () {
                var that = this;
                var options = that.options;
                var cascade = options.cascadeFrom;
                var parent;
                if (cascade) {
                    parent = that._parentWidget();
                    if (!parent) {
                        return;
                    }
                    that._cascadeHandlerProxy = proxy(that._cascadeHandler, that);
                    that._cascadeFilterRequests = [];
                    options.autoBind = false;
                    parent.bind('set', function () {
                        that.one('set', function (e) {
                            that._selectedValue = e.value || that._accessor();
                        });
                    });
                    parent.first(CASCADE, that._cascadeHandlerProxy);
                    if (parent.listView.bound()) {
                        that._toggleCascadeOnFocus();
                        that._cascadeSelect(parent);
                    } else {
                        parent.one('dataBound', function () {
                            that._toggleCascadeOnFocus();
                            if (parent.popup.visible()) {
                                parent._focused.focus();
                            }
                        });
                        if (!parent.value()) {
                            that.enable(false);
                        }
                    }
                }
            },
            _toggleCascadeOnFocus: function () {
                var that = this;
                var parent = that._parentWidget();
                var focusout = isIE ? 'blur' : 'focusout';
                parent._focused.add(parent.filterInput).bind('focus', function () {
                    parent.unbind(CASCADE, that._cascadeHandlerProxy);
                    parent.first(CHANGE, that._cascadeHandlerProxy);
                });
                parent._focused.add(parent.filterInput).bind(focusout, function () {
                    parent.unbind(CHANGE, that._cascadeHandlerProxy);
                    parent.first(CASCADE, that._cascadeHandlerProxy);
                });
            },
            _cascadeHandler: function (e) {
                var parent = this._parentWidget();
                var valueBeforeCascade = this.value();
                this._userTriggered = e.userTriggered;
                if (this.listView.bound()) {
                    this._clearSelection(parent, true);
                }
                this._cascadeSelect(parent, valueBeforeCascade);
            },
            _cascadeChange: function (parent) {
                var that = this;
                var value = that._accessor() || that._selectedValue;
                if (!that._cascadeFilterRequests.length) {
                    that._selectedValue = null;
                }
                if (that._userTriggered) {
                    that._clearSelection(parent, true);
                } else if (value) {
                    if (value !== unifyType(that.listView.value()[0], typeof value)) {
                        that.value(value);
                    }
                    if (!that.dataSource.view()[0] || that.selectedIndex === -1) {
                        that._clearSelection(parent, true);
                    }
                } else if (that.dataSource.flatView().length) {
                    that.select(that.options.index);
                }
                that.enable();
                that._triggerCascade();
                that._triggerChange();
                that._userTriggered = false;
            },
            _cascadeSelect: function (parent, valueBeforeCascade) {
                var that = this;
                var dataItem = parent.dataItem();
                var filterValue = dataItem ? dataItem[that.options.cascadeFromParentField] || parent._value(dataItem) : null;
                var valueField = that.options.cascadeFromField || parent.options.dataValueField;
                var expressions;
                that._valueBeforeCascade = valueBeforeCascade !== undefined ? valueBeforeCascade : that.value();
                if (filterValue || filterValue === 0) {
                    expressions = that.dataSource.filter() || {};
                    removeFiltersForField(expressions, valueField);
                    var handler = function () {
                        var currentHandler = that._cascadeFilterRequests.shift();
                        if (currentHandler) {
                            that.unbind('dataBound', currentHandler);
                        }
                        currentHandler = that._cascadeFilterRequests[0];
                        if (currentHandler) {
                            that.first('dataBound', currentHandler);
                        }
                        that._cascadeChange(parent);
                    };
                    that._cascadeFilterRequests.push(handler);
                    if (that._cascadeFilterRequests.length === 1) {
                        that.first('dataBound', handler);
                    }
                    that._cascading = true;
                    that._filterSource({
                        field: valueField,
                        operator: 'eq',
                        value: filterValue
                    });
                    that._cascading = false;
                } else {
                    that.enable(false);
                    that._clearSelection(parent);
                    that._triggerCascade();
                    that._triggerChange();
                    that._userTriggered = false;
                }
            }
        });
        var STATIC_LIST_NS = '.StaticList';
        var StaticList = kendo.ui.DataBoundWidget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.element.attr('role', 'listbox').on('click' + STATIC_LIST_NS, 'li', proxy(this._click, this)).on('mouseenter' + STATIC_LIST_NS, 'li', function () {
                    $(this).addClass(HOVER);
                }).on('mouseleave' + STATIC_LIST_NS, 'li', function () {
                    $(this).removeClass(HOVER);
                });
                if (support.touch) {
                    this._touchHandlers();
                }
                if (this.options.selectable === 'multiple') {
                    this.element.attr('aria-multiselectable', true);
                }
                this.content = this.element.wrap('<div class=\'k-list-scroller\' unselectable=\'on\'></div>').parent();
                this.header = this.content.before('<div class="k-group-header" style="display:none"></div>').prev();
                this.bound(false);
                this._optionID = kendo.guid();
                this._selectedIndices = [];
                this._view = [];
                this._dataItems = [];
                this._values = [];
                var value = this.options.value;
                if (value) {
                    this._values = $.isArray(value) ? value.slice(0) : [value];
                }
                this._getter();
                this._templates();
                this.setDataSource(this.options.dataSource);
                this._onScroll = proxy(function () {
                    var that = this;
                    clearTimeout(that._scrollId);
                    that._scrollId = setTimeout(function () {
                        that._renderHeader();
                    }, 50);
                }, this);
            },
            options: {
                name: 'StaticList',
                dataValueField: null,
                valuePrimitive: false,
                selectable: true,
                template: null,
                groupTemplate: null,
                fixedGroupTemplate: null
            },
            events: [
                'click',
                CHANGE,
                'activate',
                'deactivate',
                'dataBinding',
                'dataBound',
                'selectedItemChange'
            ],
            setDataSource: function (source) {
                var that = this;
                var dataSource = source || {};
                var value;
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                dataSource = kendo.data.DataSource.create(dataSource);
                if (that.dataSource) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                    value = that.value();
                    that.value([]);
                    that.bound(false);
                    that.value(value);
                } else {
                    that._refreshHandler = proxy(that.refresh, that);
                }
                that.setDSFilter(dataSource.filter());
                that.dataSource = dataSource.bind(CHANGE, that._refreshHandler);
                that._fixedHeader();
            },
            _touchHandlers: function () {
                var that = this;
                var startY;
                var endY;
                var tapPosition = function (event) {
                    return (event.originalEvent || event).changedTouches[0].pageY;
                };
                that.element.on('touchstart' + STATIC_LIST_NS, function (e) {
                    startY = tapPosition(e);
                });
                that.element.on('touchend' + STATIC_LIST_NS, function (e) {
                    if (e.isDefaultPrevented()) {
                        return;
                    }
                    endY = tapPosition(e);
                    if (Math.abs(endY - startY) < 10) {
                        that._touchTriggered = true;
                        that._triggerClick($(e.target).closest(ITEMSELECTOR).get(0));
                    }
                });
            },
            skip: function () {
                return this.dataSource.skip();
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._getter();
                this._templates();
                this._render();
            },
            destroy: function () {
                this.element.off(STATIC_LIST_NS);
                if (this._refreshHandler) {
                    this.dataSource.unbind(CHANGE, this._refreshHandler);
                }
                clearTimeout(this._scrollId);
                Widget.fn.destroy.call(this);
            },
            dataItemByIndex: function (index) {
                return this.dataSource.flatView()[index];
            },
            screenHeight: function () {
                return this.content[0].clientHeight;
            },
            scrollToIndex: function (index) {
                var item = this.element[0].children[index];
                if (item) {
                    this.scroll(item);
                }
            },
            scrollWith: function (value) {
                this.content.scrollTop(this.content.scrollTop() + value);
            },
            scroll: function (item) {
                if (!item) {
                    return;
                }
                if (item[0]) {
                    item = item[0];
                }
                var content = this.content[0], itemOffsetTop = item.offsetTop, itemOffsetHeight = item.offsetHeight, contentScrollTop = content.scrollTop, contentOffsetHeight = content.clientHeight, bottomDistance = itemOffsetTop + itemOffsetHeight;
                if (contentScrollTop > itemOffsetTop) {
                    contentScrollTop = itemOffsetTop;
                } else if (bottomDistance > contentScrollTop + contentOffsetHeight) {
                    contentScrollTop = bottomDistance - contentOffsetHeight;
                }
                content.scrollTop = contentScrollTop;
            },
            selectedDataItems: function (dataItems) {
                if (dataItems === undefined) {
                    return this._dataItems.slice();
                }
                this._dataItems = dataItems;
                this._values = this._getValues(dataItems);
            },
            _getValues: function (dataItems) {
                var getter = this._valueGetter;
                return $.map(dataItems, function (dataItem) {
                    return getter(dataItem);
                });
            },
            focusNext: function () {
                var current = this.focus();
                if (!current) {
                    current = 0;
                } else {
                    current = current.next();
                }
                this.focus(current);
            },
            focusPrev: function () {
                var current = this.focus();
                if (!current) {
                    current = this.element[0].children.length - 1;
                } else {
                    current = current.prev();
                }
                this.focus(current);
            },
            focusFirst: function () {
                this.focus(this.element[0].children[0]);
            },
            focusLast: function () {
                this.focus(last(this.element[0].children));
            },
            focus: function (candidate) {
                var that = this;
                var id = that._optionID;
                var hasCandidate;
                if (candidate === undefined) {
                    return that._current;
                }
                candidate = last(that._get(candidate));
                candidate = $(this.element[0].children[candidate]);
                if (that._current) {
                    that._current.removeClass(FOCUSED).removeAttr(ID);
                    that.trigger('deactivate');
                }
                hasCandidate = !!candidate[0];
                if (hasCandidate) {
                    candidate.addClass(FOCUSED);
                    that.scroll(candidate);
                    candidate.attr('id', id);
                }
                that._current = hasCandidate ? candidate : null;
                that.trigger('activate');
            },
            focusIndex: function () {
                return this.focus() ? this.focus().index() : undefined;
            },
            skipUpdate: function (skipUpdate) {
                this._skipUpdate = skipUpdate;
            },
            select: function (indices) {
                var that = this;
                var selectable = that.options.selectable;
                var singleSelection = selectable !== 'multiple' && selectable !== false;
                var selectedIndices = that._selectedIndices;
                var uiSelectedIndices = [this.element.find('.k-state-selected').index()];
                var added = [];
                var removed = [];
                var result;
                if (indices === undefined) {
                    return selectedIndices.slice();
                }
                indices = that._get(indices);
                if (indices.length === 1 && indices[0] === -1) {
                    indices = [];
                }
                var deferred = $.Deferred().resolve();
                var filtered = that.isFiltered();
                if (filtered && !singleSelection && that._deselectFiltered(indices)) {
                    return deferred;
                }
                if (singleSelection && !filtered && $.inArray(last(indices), selectedIndices) !== -1 && $.inArray(last(indices), uiSelectedIndices) !== -1) {
                    if (that._dataItems.length && that._view.length) {
                        that._dataItems = [that._view[selectedIndices[0]].item];
                    }
                    return deferred;
                }
                result = that._deselect(indices);
                removed = result.removed;
                indices = result.indices;
                if (indices.length) {
                    if (singleSelection) {
                        indices = [last(indices)];
                    }
                    added = that._select(indices);
                }
                if (added.length || removed.length) {
                    that._valueComparer = null;
                    that.trigger(CHANGE, {
                        added: added,
                        removed: removed
                    });
                }
                return deferred;
            },
            removeAt: function (position) {
                this._selectedIndices.splice(position, 1);
                this._values.splice(position, 1);
                this._valueComparer = null;
                return {
                    position: position,
                    dataItem: this._dataItems.splice(position, 1)[0]
                };
            },
            setValue: function (value) {
                value = $.isArray(value) || value instanceof ObservableArray ? value.slice(0) : [value];
                this._values = value;
                this._valueComparer = null;
            },
            value: function (value) {
                var that = this;
                var deferred = that._valueDeferred;
                var indices;
                if (value === undefined) {
                    return that._values.slice();
                }
                that.setValue(value);
                if (!deferred || deferred.state() === 'resolved') {
                    that._valueDeferred = deferred = $.Deferred();
                }
                if (that.bound()) {
                    indices = that._valueIndices(that._values);
                    if (that.options.selectable === 'multiple') {
                        that.select(-1);
                    }
                    that.select(indices);
                    deferred.resolve();
                }
                that._skipUpdate = false;
                return deferred;
            },
            items: function () {
                return this.element.children(ITEMSELECTOR);
            },
            _click: function (e) {
                if (this._touchTriggered) {
                    this._touchTriggered = false;
                    return;
                }
                if (!e.isDefaultPrevented()) {
                    this._triggerClick(e.currentTarget);
                }
            },
            _triggerClick: function (item) {
                if (!this.trigger('click', { item: $(item) })) {
                    this.select(item);
                }
            },
            _valueExpr: function (type, values) {
                var that = this;
                var idx = 0;
                var body;
                var comparer;
                var normalized = [];
                if (!that._valueComparer || that._valueType !== type) {
                    that._valueType = type;
                    for (; idx < values.length; idx++) {
                        normalized.push(unifyType(values[idx], type));
                    }
                    body = 'for (var idx = 0; idx < ' + normalized.length + '; idx++) {' + ' if (current === values[idx]) {' + '   return idx;' + ' }' + '} ' + 'return -1;';
                    comparer = new Function('current', 'values', body);
                    that._valueComparer = function (current) {
                        return comparer(current, normalized);
                    };
                }
                return that._valueComparer;
            },
            _dataItemPosition: function (dataItem, values) {
                var value = this._valueGetter(dataItem);
                var valueExpr = this._valueExpr(typeof value, values);
                return valueExpr(value);
            },
            _getter: function () {
                this._valueGetter = kendo.getter(this.options.dataValueField);
            },
            _deselect: function (indices) {
                var that = this;
                var children = that.element[0].children;
                var selectable = that.options.selectable;
                var selectedIndices = that._selectedIndices;
                var dataItems = that._dataItems;
                var values = that._values;
                var removed = [];
                var i = 0;
                var j;
                var index, selectedIndex;
                var removedIndices = 0;
                indices = indices.slice();
                if (selectable === true || !indices.length) {
                    for (; i < selectedIndices.length; i++) {
                        $(children[selectedIndices[i]]).removeClass('k-state-selected').attr('aria-selected', false);
                        removed.push({
                            position: i,
                            dataItem: dataItems[i]
                        });
                    }
                    that._values = [];
                    that._dataItems = [];
                    that._selectedIndices = [];
                } else if (selectable === 'multiple') {
                    for (; i < indices.length; i++) {
                        index = indices[i];
                        if (!$(children[index]).hasClass('k-state-selected')) {
                            continue;
                        }
                        for (j = 0; j < selectedIndices.length; j++) {
                            selectedIndex = selectedIndices[j];
                            if (selectedIndex === index) {
                                $(children[selectedIndex]).removeClass('k-state-selected').attr('aria-selected', false);
                                removed.push({
                                    position: j + removedIndices,
                                    dataItem: dataItems.splice(j, 1)[0]
                                });
                                selectedIndices.splice(j, 1);
                                indices.splice(i, 1);
                                values.splice(j, 1);
                                removedIndices += 1;
                                i -= 1;
                                j -= 1;
                                break;
                            }
                        }
                    }
                }
                return {
                    indices: indices,
                    removed: removed
                };
            },
            _deselectFiltered: function (indices) {
                var children = this.element[0].children;
                var dataItem, index, position;
                var removed = [];
                var idx = 0;
                for (; idx < indices.length; idx++) {
                    index = indices[idx];
                    dataItem = this._view[index].item;
                    position = this._dataItemPosition(dataItem, this._values);
                    if (position > -1) {
                        removed.push(this.removeAt(position));
                        $(children[index]).removeClass('k-state-selected');
                    }
                }
                if (removed.length) {
                    this.trigger(CHANGE, {
                        added: [],
                        removed: removed
                    });
                    return true;
                }
                return false;
            },
            _select: function (indices) {
                var that = this;
                var children = that.element[0].children;
                var data = that._view;
                var dataItem, index;
                var added = [];
                var idx = 0;
                if (last(indices) !== -1) {
                    that.focus(indices);
                }
                for (; idx < indices.length; idx++) {
                    index = indices[idx];
                    dataItem = data[index];
                    if (index === -1 || !dataItem) {
                        continue;
                    }
                    dataItem = dataItem.item;
                    that._selectedIndices.push(index);
                    that._dataItems.push(dataItem);
                    that._values.push(that._valueGetter(dataItem));
                    $(children[index]).addClass('k-state-selected').attr('aria-selected', true);
                    added.push({ dataItem: dataItem });
                }
                return added;
            },
            getElementIndex: function (element) {
                return $(element).data('offset-index');
            },
            _get: function (candidate) {
                if (typeof candidate === 'number') {
                    candidate = [candidate];
                } else if (!isArray(candidate)) {
                    candidate = this.getElementIndex(candidate);
                    candidate = [candidate !== undefined ? candidate : -1];
                }
                return candidate;
            },
            _template: function () {
                var that = this;
                var options = that.options;
                var template = options.template;
                if (!template) {
                    template = kendo.template('<li tabindex="-1" role="option" unselectable="on" class="k-item">${' + kendo.expr(options.dataTextField, 'data') + '}</li>', { useWithBlock: false });
                } else {
                    template = kendo.template(template);
                    template = function (data) {
                        return '<li tabindex="-1" role="option" unselectable="on" class="k-item">' + template(data) + '</li>';
                    };
                }
                return template;
            },
            _templates: function () {
                var template;
                var options = this.options;
                var templates = {
                    template: options.template,
                    groupTemplate: options.groupTemplate,
                    fixedGroupTemplate: options.fixedGroupTemplate
                };
                if (options.columns) {
                    for (var i = 0; i < options.columns.length; i++) {
                        var currentColumn = options.columns[i];
                        var templateText = currentColumn.field ? currentColumn.field.toString() : 'text';
                        templates['column' + i] = currentColumn.template || '#: ' + templateText + '#';
                    }
                }
                for (var key in templates) {
                    template = templates[key];
                    if (template && typeof template !== 'function') {
                        templates[key] = kendo.template(template);
                    }
                }
                this.templates = templates;
            },
            _normalizeIndices: function (indices) {
                var newIndices = [];
                var idx = 0;
                for (; idx < indices.length; idx++) {
                    if (indices[idx] !== undefined) {
                        newIndices.push(indices[idx]);
                    }
                }
                return newIndices;
            },
            _valueIndices: function (values, indices) {
                var data = this._view;
                var idx = 0;
                var index;
                indices = indices ? indices.slice() : [];
                if (!values.length) {
                    return [];
                }
                for (; idx < data.length; idx++) {
                    index = this._dataItemPosition(data[idx].item, values);
                    if (index !== -1) {
                        indices[index] = idx;
                    }
                }
                return this._normalizeIndices(indices);
            },
            _firstVisibleItem: function () {
                var element = this.element[0];
                var content = this.content[0];
                var scrollTop = content.scrollTop;
                var itemHeight = $(element.children[0]).height();
                var itemIndex = Math.floor(scrollTop / itemHeight) || 0;
                var item = element.children[itemIndex] || element.lastChild;
                var forward = item.offsetTop < scrollTop;
                while (item) {
                    if (forward) {
                        if (item.offsetTop + itemHeight > scrollTop || !item.nextSibling) {
                            break;
                        }
                        item = item.nextSibling;
                    } else {
                        if (item.offsetTop <= scrollTop || !item.previousSibling) {
                            break;
                        }
                        item = item.previousSibling;
                    }
                }
                return this._view[$(item).data('offset-index')];
            },
            _fixedHeader: function () {
                if (this.isGrouped() && this.templates.fixedGroupTemplate) {
                    this.header.show();
                    this.content.scroll(this._onScroll);
                } else {
                    this.header.hide();
                    this.content.off('scroll', this._onScroll);
                }
            },
            _renderHeader: function () {
                var template = this.templates.fixedGroupTemplate;
                if (!template) {
                    return;
                }
                var visibleItem = this._firstVisibleItem();
                if (visibleItem && visibleItem.group.toString().length) {
                    this.header.html(template(visibleItem.group));
                }
            },
            _renderItem: function (context) {
                var item = '<li tabindex="-1" role="option" unselectable="on" class="k-item';
                var dataItem = context.item;
                var notFirstItem = context.index !== 0;
                var selected = context.selected;
                var isGrouped = this.isGrouped();
                var hasColumns = this.options.columns && this.options.columns.length;
                if (notFirstItem && context.newGroup) {
                    item += ' k-first';
                }
                if (context.isLastGroupedItem && hasColumns) {
                    item += ' k-last';
                }
                if (selected) {
                    item += ' k-state-selected';
                }
                item += '" aria-selected="' + (selected ? 'true' : 'false') + '" data-offset-index="' + context.index + '">';
                if (hasColumns) {
                    item += this._renderColumns(dataItem);
                } else {
                    item += this.templates.template(dataItem);
                }
                if (notFirstItem && context.newGroup) {
                    if (hasColumns) {
                        item += '<div class="k-cell k-group-cell"><span>' + this.templates.groupTemplate(context.group) + '</span></div>';
                    } else {
                        item += '<div class="k-group">' + this.templates.groupTemplate(context.group) + '</div>';
                    }
                } else if (isGrouped && hasColumns) {
                    item += '<div class=\'k-cell k-spacer-cell\'></div>';
                }
                return item + '</li>';
            },
            _renderColumns: function (dataItem) {
                var item = '';
                for (var i = 0; i < this.options.columns.length; i++) {
                    var currentWidth = this.options.columns[i].width;
                    var currentWidthInt = parseInt(currentWidth, 10);
                    var widthStyle = '';
                    if (currentWidth && !isNaN(currentWidthInt)) {
                        widthStyle += 'style=\'width:';
                        widthStyle += currentWidthInt;
                        widthStyle += percentageUnitsRegex.test(currentWidth) ? '%' : 'px';
                        widthStyle += ';\'';
                    }
                    item += '<span class=\'k-cell\' ' + widthStyle + '>';
                    item += this.templates['column' + i](dataItem);
                    item += '</span>';
                }
                return item;
            },
            _render: function () {
                var html = '';
                var i = 0;
                var idx = 0;
                var context;
                var dataContext = [];
                var view = this.dataSource.view();
                var values = this.value();
                var group, newGroup, j;
                var isGrouped = this.isGrouped();
                if (isGrouped) {
                    for (i = 0; i < view.length; i++) {
                        group = view[i];
                        newGroup = true;
                        for (j = 0; j < group.items.length; j++) {
                            context = {
                                selected: this._selected(group.items[j], values),
                                item: group.items[j],
                                group: group.value,
                                newGroup: newGroup,
                                isLastGroupedItem: j === group.items.length - 1,
                                index: idx
                            };
                            dataContext[idx] = context;
                            idx += 1;
                            html += this._renderItem(context);
                            newGroup = false;
                        }
                    }
                } else {
                    for (i = 0; i < view.length; i++) {
                        context = {
                            selected: this._selected(view[i], values),
                            item: view[i],
                            index: i
                        };
                        dataContext[i] = context;
                        html += this._renderItem(context);
                    }
                }
                this._view = dataContext;
                this.element[0].innerHTML = html;
                if (isGrouped && dataContext.length) {
                    this._renderHeader();
                }
            },
            _selected: function (dataItem, values) {
                var select = !this.isFiltered() || this.options.selectable === 'multiple';
                return select && this._dataItemPosition(dataItem, values) !== -1;
            },
            setDSFilter: function (filter) {
                this._lastDSFilter = extend({}, filter);
            },
            isFiltered: function () {
                if (!this._lastDSFilter) {
                    this.setDSFilter(this.dataSource.filter());
                }
                return !kendo.data.Query.compareFilters(this.dataSource.filter(), this._lastDSFilter);
            },
            refresh: function (e) {
                var that = this;
                var action = e && e.action;
                var skipUpdateOnBind = that.options.skipUpdateOnBind;
                var isItemChange = action === 'itemchange';
                var result;
                that.trigger('dataBinding');
                that._angularItems('cleanup');
                that._fixedHeader();
                that._render();
                that.bound(true);
                if (isItemChange || action === 'remove') {
                    result = mapChangedItems(that._dataItems, e.items);
                    if (result.changed.length) {
                        if (isItemChange) {
                            that.trigger('selectedItemChange', { items: result.changed });
                        } else {
                            that.value(that._getValues(result.unchanged));
                        }
                    }
                } else if (that.isFiltered() || that._skipUpdate || that._emptySearch) {
                    that.focus(0);
                    if (that._skipUpdate) {
                        that._skipUpdate = false;
                        that._selectedIndices = that._valueIndices(that._values, that._selectedIndices);
                    }
                } else if (!skipUpdateOnBind && (!action || action === 'add')) {
                    that.value(that._values);
                }
                if (that._valueDeferred) {
                    that._valueDeferred.resolve();
                }
                that._angularItems('compile');
                that.trigger('dataBound');
            },
            bound: function (bound) {
                if (bound === undefined) {
                    return this._bound;
                }
                this._bound = bound;
            },
            isGrouped: function () {
                return (this.dataSource.group() || []).length;
            }
        });
        ui.plugin(StaticList);
        function last(list) {
            return list[list.length - 1];
        }
        function getSelectedOption(select) {
            var index = select.selectedIndex;
            return index > -1 ? select.options[index] : {};
        }
        function mapChangedItems(selected, itemsToMatch) {
            var itemsLength = itemsToMatch.length;
            var selectedLength = selected.length;
            var dataItem;
            var found;
            var i, j;
            var changed = [];
            var unchanged = [];
            if (selectedLength) {
                for (i = 0; i < selectedLength; i++) {
                    dataItem = selected[i];
                    found = false;
                    for (j = 0; j < itemsLength; j++) {
                        if (dataItem === itemsToMatch[j]) {
                            found = true;
                            changed.push({
                                index: i,
                                item: dataItem
                            });
                            break;
                        }
                    }
                    if (!found) {
                        unchanged.push(dataItem);
                    }
                }
            }
            return {
                changed: changed,
                unchanged: unchanged
            };
        }
        function isValidFilterExpr(expression) {
            if (!expression || $.isEmptyObject(expression)) {
                return false;
            }
            if (expression.filters && !expression.filters.length) {
                return false;
            }
            return true;
        }
        function removeFiltersForField(expression, field) {
            var filters;
            var found = false;
            if (expression.filters) {
                filters = $.grep(expression.filters, function (filter) {
                    found = removeFiltersForField(filter, field);
                    if (filter.filters) {
                        return filter.filters.length;
                    } else {
                        return filter.field != field;
                    }
                });
                if (!found && expression.filters.length !== filters.length) {
                    found = true;
                }
                expression.filters = filters;
            }
            return found;
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.calendar', [
        'kendo.core',
        'kendo.selectable'
    ], f);
}(function () {
    var __meta__ = {
        id: 'calendar',
        name: 'Calendar',
        category: 'web',
        description: 'The Calendar widget renders a graphical calendar that supports navigation and selection.',
        depends: [
            'core',
            'selectable'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, support = kendo.support, ui = kendo.ui, Widget = ui.Widget, keys = kendo.keys, parse = kendo.parseDate, adjustDST = kendo.date.adjustDST, weekInYear = kendo.date.weekInYear, Selectable = kendo.ui.Selectable, extractFormat = kendo._extractFormat, template = kendo.template, getCulture = kendo.getCulture, transitions = kendo.support.transitions, transitionOrigin = transitions ? transitions.css + 'transform-origin' : '', cellTemplate = template('<td#=data.cssClass# role="gridcell"><a tabindex="-1" class="k-link" href="\\#" data-#=data.ns#value="#=data.dateString#">#=data.value#</a></td>', { useWithBlock: false }), emptyCellTemplate = template('<td role="gridcell" class="k-out-of-range"><a class="k-link"></a></td>', { useWithBlock: false }), otherMonthCellTemplate = template('<td role="gridcell" class="k-out-of-range">&nbsp;</td>', { useWithBlock: false }), weekNumberTemplate = template('<td class="k-alt">#= data.weekNumber #</td>', { useWithBlock: false }), browser = kendo.support.browser, isIE8 = browser.msie && browser.version < 9, outerWidth = kendo._outerWidth, ns = '.kendoCalendar', CLICK = 'click' + ns, KEYDOWN_NS = 'keydown' + ns, ID = 'id', MIN = 'min', LEFT = 'left', SLIDE = 'slideIn', MONTH = 'month', CENTURY = 'century', CHANGE = 'change', NAVIGATE = 'navigate', VALUE = 'value', HOVER = 'k-state-hover', DISABLED = 'k-state-disabled', FOCUSED = 'k-state-focused', OTHERMONTH = 'k-other-month', OTHERMONTHCLASS = ' class="' + OTHERMONTH + '"', OUTOFRANGE = 'k-out-of-range', TODAY = 'k-nav-today', CELLSELECTOR = 'td:has(.k-link)', CELLSELECTORVALID = 'td:has(.k-link):not(.' + DISABLED + '):not(.' + OUTOFRANGE + ')', WEEKCOLUMNSELECTOR = 'td:not(:has(.k-link))', SELECTED = 'k-state-selected', BLUR = 'blur' + ns, FOCUS = 'focus', FOCUS_WITH_NS = FOCUS + ns, MOUSEENTER = support.touch ? 'touchstart' : 'mouseenter', MOUSEENTER_WITH_NS = support.touch ? 'touchstart' + ns : 'mouseenter' + ns, MOUSELEAVE = support.touch ? 'touchend' + ns + ' touchmove' + ns : 'mouseleave' + ns, MS_PER_MINUTE = 60000, MS_PER_DAY = 86400000, PREVARROW = '_prevArrow', NEXTARROW = '_nextArrow', ARIA_DISABLED = 'aria-disabled', ARIA_SELECTED = 'aria-selected', ARIA_LABEL = 'aria-label', proxy = $.proxy, extend = $.extend, DATE = Date, views = {
                month: 0,
                year: 1,
                decade: 2,
                century: 3
            };
        var Calendar = Widget.extend({
            init: function (element, options) {
                var that = this, value, id;
                Widget.fn.init.call(that, element, options);
                element = that.wrapper = that.element;
                options = that.options;
                options.url = window.unescape(options.url);
                that.options.disableDates = getDisabledExpr(that.options.disableDates);
                that._templates();
                that._selectable();
                that._header();
                that._viewWrapper();
                that._footer(that.footer);
                id = element.addClass('k-widget k-calendar ' + (options.weekNumber ? ' k-week-number' : '')).on(MOUSEENTER_WITH_NS + ' ' + MOUSELEAVE, CELLSELECTOR, mousetoggle).on(KEYDOWN_NS, 'table.k-content', proxy(that._move, that)).on(CLICK, CELLSELECTOR, function (e) {
                    var link = e.currentTarget.firstChild, value = toDateObject(link);
                    if (link.href.indexOf('#') != -1) {
                        e.preventDefault();
                    }
                    if (that._view.name == 'month' && that.options.disableDates(value)) {
                        return;
                    }
                    if (that._view.name != 'month' || options.selectable == 'single') {
                        that._click($(link));
                    }
                }).on('mouseup' + ns, 'table.k-content, .k-footer', function () {
                    that._focusView(that.options.focusOnNav !== false);
                }).attr(ID);
                if (id) {
                    that._cellID = id + '_cell_selected';
                }
                if (that._isMultipleSelection() && that.options.weekNumber) {
                    element.on(CLICK, WEEKCOLUMNSELECTOR, function (e) {
                        var first = $(e.currentTarget).closest('tr').find(CELLSELECTORVALID).first(), last = that.selectable._lastActive = $(e.currentTarget).closest('tr').find(CELLSELECTORVALID).last();
                        that.selectable.selectRange(first, last, { event: e });
                        that._current = that._value = toDateObject(last.find('a'));
                        that._class(FOCUSED, that._current);
                    });
                }
                normalize(options);
                value = parse(options.value, options.format, options.culture);
                that._selectDates = [];
                that._index = views[options.start];
                that._current = new DATE(+restrictValue(value, options.min, options.max));
                that._addClassProxy = function () {
                    that._active = true;
                    if (that._cell.hasClass(DISABLED)) {
                        var todayString = that._view.toDateString(getToday());
                        that._cell = that._cellByDate(todayString);
                    }
                    that._cell.addClass(FOCUSED);
                };
                that._removeClassProxy = function () {
                    that._active = false;
                    that._cell.removeClass(FOCUSED);
                };
                that.value(value);
                if (that._isMultipleSelection() && options.selectDates.length > 0) {
                    that.selectDates(options.selectDates);
                }
                kendo.notify(that);
            },
            options: {
                name: 'Calendar',
                value: null,
                min: new DATE(1900, 0, 1),
                max: new DATE(2099, 11, 31),
                dates: [],
                disableDates: null,
                url: '',
                culture: '',
                footer: '',
                format: '',
                month: {},
                weekNumber: false,
                selectable: 'single',
                selectDates: [],
                start: MONTH,
                depth: MONTH,
                animation: {
                    horizontal: {
                        effects: SLIDE,
                        reverse: true,
                        duration: 500,
                        divisor: 2
                    },
                    vertical: {
                        effects: 'zoomIn',
                        duration: 400
                    }
                },
                messages: { weekColumnHeader: '' }
            },
            events: [
                CHANGE,
                NAVIGATE
            ],
            setOptions: function (options) {
                var that = this;
                normalize(options);
                options.disableDates = getDisabledExpr(options.disableDates);
                Widget.fn.setOptions.call(that, options);
                that._templates();
                that._selectable();
                that._viewWrapper();
                that._footer(that.footer);
                that._index = views[that.options.start];
                that.navigate();
                if (options.weekNumber) {
                    that.element.addClass('k-week-number');
                }
            },
            destroy: function () {
                var that = this, today = that._today;
                that.element.off(ns);
                that._title.off(ns);
                that[PREVARROW].off(ns);
                that[NEXTARROW].off(ns);
                that._destroySelectable();
                kendo.destroy(that._table);
                if (today) {
                    kendo.destroy(today.off(ns));
                }
                Widget.fn.destroy.call(that);
            },
            current: function () {
                return this._current;
            },
            view: function () {
                return this._view;
            },
            focus: function (table) {
                table = table || this._table;
                this._bindTable(table);
                table.trigger('focus');
            },
            min: function (value) {
                return this._option(MIN, value);
            },
            max: function (value) {
                return this._option('max', value);
            },
            navigateToPast: function () {
                this._navigate(PREVARROW, -1);
            },
            navigateToFuture: function () {
                this._navigate(NEXTARROW, 1);
            },
            navigateUp: function () {
                var that = this, index = that._index;
                if (that._title.hasClass(DISABLED)) {
                    return;
                }
                that.navigate(that._current, ++index);
            },
            navigateDown: function (value) {
                var that = this, index = that._index, depth = that.options.depth;
                if (!value) {
                    return;
                }
                if (index === views[depth]) {
                    if (!isEqualDate(that._value, that._current) || !isEqualDate(that._value, value)) {
                        that.value(value);
                        that.trigger(CHANGE);
                    }
                    return;
                }
                that.navigate(value, --index);
            },
            navigate: function (value, view) {
                view = isNaN(view) ? views[view] : view;
                var that = this, options = that.options, culture = options.culture, min = options.min, max = options.max, title = that._title, from = that._table, old = that._oldTable, currentValue = that._current, future = value && +value > +currentValue, vertical = view !== undefined && view !== that._index, to, currentView, compare, disabled;
                if (!value) {
                    value = currentValue;
                }
                that._current = value = new DATE(+restrictValue(value, min, max));
                if (view === undefined) {
                    view = that._index;
                } else {
                    that._index = view;
                }
                that._view = currentView = calendar.views[view];
                compare = currentView.compare;
                disabled = view === views[CENTURY];
                title.toggleClass(DISABLED, disabled).attr(ARIA_DISABLED, disabled);
                disabled = compare(value, min) < 1;
                that[PREVARROW].toggleClass(DISABLED, disabled).attr(ARIA_DISABLED, disabled);
                if (that[PREVARROW].hasClass(DISABLED)) {
                    that[PREVARROW].removeClass(HOVER);
                }
                disabled = compare(value, max) > -1;
                that[NEXTARROW].toggleClass(DISABLED, disabled).attr(ARIA_DISABLED, disabled);
                if (that[NEXTARROW].hasClass(DISABLED)) {
                    that[NEXTARROW].removeClass(HOVER);
                }
                if (from && old && old.data('animating')) {
                    old.kendoStop(true, true);
                    from.kendoStop(true, true);
                }
                that._oldTable = from;
                if (!from || that._changeView) {
                    title.html(currentView.title(value, min, max, culture));
                    that._table = to = $(currentView.content(extend({
                        min: min,
                        max: max,
                        date: value,
                        url: options.url,
                        dates: options.dates,
                        format: options.format,
                        otherMonth: true,
                        culture: culture,
                        disableDates: options.disableDates,
                        isWeekColumnVisible: options.weekNumber,
                        messages: options.messages
                    }, that[currentView.name])));
                    addClassToViewContainer(to, currentView.name);
                    makeUnselectable(to);
                    var replace = from && from.data('start') === to.data('start');
                    that._animate({
                        from: from,
                        to: to,
                        vertical: vertical,
                        future: future,
                        replace: replace
                    });
                    that.trigger(NAVIGATE);
                    that._focus(value);
                }
                if (view === views[options.depth] && that._selectDates.length > 0) {
                    that._visualizeSelectedDatesInView();
                }
                if (that.options.selectable === 'single') {
                    if (view === views[options.depth] && that._value && !that.options.disableDates(that._value)) {
                        that._class('k-state-selected', that._value);
                    }
                }
                that._class(FOCUSED, value);
                if (!from && that._cell) {
                    that._cell.removeClass(FOCUSED);
                }
                that._changeView = true;
            },
            selectDates: function (dates) {
                var that = this, validSelectedDates, datesUnique;
                if (dates === undefined) {
                    return that._selectDates;
                }
                datesUnique = dates.map(function (date) {
                    return date.getTime();
                }).filter(function (date, position, array) {
                    return array.indexOf(date) === position;
                }).map(function (time) {
                    return new Date(time);
                });
                validSelectedDates = $.grep(datesUnique, function (value) {
                    if (value) {
                        return +that._validateValue(new Date(value.setHours(0, 0, 0, 0))) === +value;
                    }
                });
                that._selectDates = validSelectedDates.length > 0 ? validSelectedDates : datesUnique.length === 0 ? datesUnique : that._selectDates;
                that._visualizeSelectedDatesInView();
            },
            value: function (value) {
                var that = this, old = that._view, view = that._view;
                if (value === undefined) {
                    return that._value;
                }
                value = that._validateValue(value);
                if (value && that._isMultipleSelection()) {
                    var date = new Date(+value);
                    date.setHours(0, 0, 0, 0);
                    that._selectDates = [date];
                    that.selectable._lastActive = null;
                }
                if (old && value === null && that._cell) {
                    that._cell.removeClass(SELECTED);
                } else {
                    that._changeView = !value || view && view.compare(value, that._current) !== 0;
                    that.navigate(value);
                }
            },
            _validateValue: function (value) {
                var that = this, options = that.options, min = options.min, max = options.max;
                if (value === null) {
                    that._current = createDate(that._current.getFullYear(), that._current.getMonth(), that._current.getDate());
                }
                value = parse(value, options.format, options.culture);
                if (value !== null) {
                    value = new DATE(+value);
                    if (!isInRange(value, min, max)) {
                        value = null;
                    }
                }
                if (value === null || !that.options.disableDates(new Date(+value))) {
                    that._value = value;
                } else if (that._value === undefined) {
                    that._value = null;
                }
                return that._value;
            },
            _visualizeSelectedDatesInView: function () {
                var that = this;
                var selectedDates = {};
                $.each(that._selectDates, function (index, value) {
                    selectedDates[kendo.calendar.views[0].toDateString(value)] = value;
                });
                that.selectable.clear();
                var cells = that._table.find(CELLSELECTOR).filter(function (index, element) {
                    return selectedDates[$(element.firstChild).attr(kendo.attr(VALUE))];
                });
                if (cells.length > 0) {
                    that.selectable._selectElement(cells, true);
                }
            },
            _isMultipleSelection: function () {
                var that = this;
                return that.options.selectable === 'multiple';
            },
            _selectable: function () {
                var that = this;
                if (!that._isMultipleSelection()) {
                    return;
                }
                var selectable = that.options.selectable, selectableOptions = Selectable.parseOptions(selectable);
                if (selectableOptions.multiple) {
                    that.element.attr('aria-multiselectable', 'true');
                }
                that.selectable = new Selectable(that.wrapper, {
                    aria: true,
                    inputSelectors: 'input,textarea,.k-multiselect-wrap,select,button,.k-button>span,.k-button>img,span.k-icon.k-i-arrow-60-down,span.k-icon.k-i-arrow-60-up',
                    multiple: selectableOptions.multiple,
                    filter: 'table.k-month:eq(0) ' + CELLSELECTORVALID,
                    change: proxy(that._onSelect, that),
                    relatedTarget: proxy(that._onRelatedTarget, that)
                });
            },
            _onRelatedTarget: function (target) {
                var that = this;
                if (that.selectable.options.multiple && target.is(CELLSELECTORVALID)) {
                    that._current = toDateObject(target.find('a'));
                    that._class(FOCUSED, toDateObject(target.find('a')));
                }
            },
            _onSelect: function (e) {
                var that = this, eventArgs = e, selectableOptions = Selectable.parseOptions(that.options.selectable);
                if (!selectableOptions.multiple) {
                    if ($(eventArgs.event.currentTarget).is('td') && !$(eventArgs.event.currentTarget).hasClass('k-state-selected')) {
                        $(eventArgs.event.currentTarget).addClass('k-state-selected');
                    } else {
                        that._click($(eventArgs.event.currentTarget).find('a'));
                    }
                    return;
                }
                if (eventArgs.event.ctrlKey || eventArgs.event.metaKey) {
                    if ($(eventArgs.event.currentTarget).is(CELLSELECTORVALID)) {
                        that._toggleSelection($(eventArgs.event.currentTarget));
                    } else {
                        that._cellsBySelector(CELLSELECTORVALID).each(function (index, element) {
                            var value = toDateObject($(element).find('a'));
                            that._deselect(value);
                        });
                        that._addSelectedCellsToArray();
                    }
                } else if (eventArgs.event.shiftKey) {
                    that._rangeSelection(that._cell);
                } else if ($(eventArgs.event.currentTarget).is(CELLSELECTOR)) {
                    that.value(toDateObject($(eventArgs.event.currentTarget).find('a')));
                } else {
                    that._selectDates = [];
                    that._addSelectedCellsToArray();
                }
                that.trigger(CHANGE);
            },
            _destroySelectable: function () {
                var that = this;
                if (that.selectable) {
                    that.selectable.destroy();
                    that.selectable = null;
                }
            },
            _toggleSelection: function (currentCell) {
                var that = this, date = toDateObject(currentCell.find('a'));
                if (currentCell.hasClass('k-state-selected')) {
                    that._selectDates.push(date);
                } else {
                    that._deselect(date);
                }
            },
            _rangeSelection: function (toDateCell, startDate) {
                var that = this, fromDate = startDate || toDateObject(that.selectable.value().first().find('a')), toDate = toDateObject(toDateCell.find('a')), daysDifference;
                if (that.selectable._lastActive || that._value) {
                    fromDate = that.selectable._lastActive ? toDateObject(that.selectable._lastActive.find('a')) : new Date(+that._value);
                } else {
                    that.selectable._lastActive = startDate ? that._cellByDate(that._view.toDateString(startDate), CELLSELECTORVALID) : that.selectable.value().first();
                }
                that._selectDates = [];
                daysDifference = daysBetweenTwoDates(fromDate, toDate);
                addDaysToArray(that._selectDates, daysDifference, fromDate, that.options.disableDates);
                that._visualizeSelectedDatesInView();
            },
            _cellsBySelector: function (selector) {
                var that = this;
                return that._table.find(selector);
            },
            _addSelectedCellsToArray: function () {
                var that = this;
                that.selectable.value().each(function (index, item) {
                    var date = toDateObject($(item.firstChild));
                    if (!that.options.disableDates(date)) {
                        that._selectDates.push(date);
                    }
                });
            },
            _deselect: function (date) {
                var that = this;
                var currentDateIndex = that._selectDates.map(Number).indexOf(+date);
                if (currentDateIndex != -1) {
                    that._selectDates.splice(currentDateIndex, 1);
                }
            },
            _dateInView: function (date) {
                var that = this, firstDateInView = toDateObject(that._cellsBySelector(CELLSELECTORVALID + ':first').find('a')), lastDateInView = toDateObject(that._cellsBySelector(CELLSELECTORVALID + ':last').find('a'));
                return +date <= +lastDateInView && +date >= +firstDateInView;
            },
            _isNavigatable: function (currentValue, cellIndex) {
                var that = this;
                var isDisabled = that.options.disableDates;
                var cell;
                var index;
                if (that._view.name == 'month') {
                    return !isDisabled(currentValue);
                } else {
                    index = that.wrapper.find('.' + FOCUSED).index();
                    cell = that.wrapper.find('.k-content td:eq(' + (index + cellIndex) + ')');
                    return cell.is(CELLSELECTORVALID) || !isDisabled(currentValue);
                }
            },
            _move: function (e) {
                var that = this, options = that.options, key = e.keyCode, view = that._view, index = that._index, min = that.options.min, max = that.options.max, currentValue = new DATE(+that._current), isRtl = kendo.support.isRtl(that.wrapper), isDisabled = that.options.disableDates, value, prevent, method, temp;
                if (e.target === that._table[0]) {
                    that._active = true;
                }
                if (key == keys.RIGHT && !isRtl || key == keys.LEFT && isRtl) {
                    value = 1;
                    prevent = true;
                } else if (key == keys.LEFT && !isRtl || key == keys.RIGHT && isRtl) {
                    value = -1;
                    prevent = true;
                } else if (key == keys.UP) {
                    value = index === 0 ? -7 : -4;
                    prevent = true;
                } else if (key == keys.DOWN) {
                    value = index === 0 ? 7 : 4;
                    prevent = true;
                } else if (key == keys.SPACEBAR) {
                    value = 0;
                    prevent = true;
                } else if (key == keys.HOME || key == keys.END) {
                    method = key == keys.HOME ? 'first' : 'last';
                    temp = view[method](currentValue);
                    currentValue = new DATE(temp.getFullYear(), temp.getMonth(), temp.getDate(), currentValue.getHours(), currentValue.getMinutes(), currentValue.getSeconds(), currentValue.getMilliseconds());
                    currentValue.setFullYear(temp.getFullYear());
                    prevent = true;
                }
                if (e.ctrlKey || e.metaKey) {
                    if (key == keys.RIGHT && !isRtl || key == keys.LEFT && isRtl) {
                        that.navigateToFuture();
                        prevent = true;
                    } else if (key == keys.LEFT && !isRtl || key == keys.RIGHT && isRtl) {
                        that.navigateToPast();
                        prevent = true;
                    } else if (key == keys.UP) {
                        that.navigateUp();
                        prevent = true;
                    } else if (key == keys.DOWN) {
                        that._click($(that._cell[0].firstChild));
                        prevent = true;
                    } else if ((key == keys.ENTER || key == keys.SPACEBAR) && that._isMultipleSelection()) {
                        that._keyboardToggleSelection(e);
                        var focusedDate = toDateObject($(that._cell[0]).find('a'));
                        that._class(FOCUSED, focusedDate);
                    }
                } else if (e.shiftKey) {
                    if (value !== undefined || method) {
                        if (!method) {
                            view.setDate(currentValue, value);
                        }
                        if (!isInRange(currentValue, min, max)) {
                            currentValue = restrictValue(currentValue, options.min, options.max);
                        }
                        if (isDisabled(currentValue)) {
                            currentValue = that._nextNavigatable(currentValue, value);
                        }
                        min = createDate(min.getFullYear(), min.getMonth(), min.getDate());
                        if (that._isMultipleSelection()) {
                            that._keyboardRangeSelection(e, currentValue);
                        } else {
                            that._focus(currentValue);
                        }
                    }
                } else {
                    if (key == keys.ENTER || key == keys.SPACEBAR) {
                        if (view.name == 'month' && that._isMultipleSelection()) {
                            that.value(toDateObject($(that._cell.find('a'))));
                            that.selectable._lastActive = $(that._cell[0]);
                            that.trigger(CHANGE);
                        } else {
                            that._click($(that._cell[0].firstChild));
                        }
                        prevent = true;
                    } else if (key == keys.PAGEUP) {
                        prevent = true;
                        that.navigateToPast();
                    } else if (key == keys.PAGEDOWN) {
                        prevent = true;
                        that.navigateToFuture();
                    }
                    if (value || method) {
                        if (!method) {
                            view.setDate(currentValue, value);
                        }
                        min = createDate(min.getFullYear(), min.getMonth(), min.getDate());
                        if (!isInRange(currentValue, min, max)) {
                            currentValue = restrictValue(currentValue, options.min, options.max);
                        }
                        if (!that._isNavigatable(currentValue, value)) {
                            currentValue = that._nextNavigatable(currentValue, value);
                        }
                        if (that._isMultipleSelection()) {
                            if (!that._dateInView(currentValue)) {
                                that.navigate(currentValue);
                            } else {
                                that._current = currentValue;
                                that._class(FOCUSED, currentValue);
                            }
                        } else {
                            that._focus(currentValue);
                        }
                    }
                }
                if (prevent) {
                    e.preventDefault();
                }
                return that._current;
            },
            _keyboardRangeSelection: function (event, currentValue) {
                var that = this, fromDate, daysDifference;
                if (!that._dateInView(currentValue)) {
                    that._selectDates = [];
                    fromDate = that.selectable._lastActive ? toDateObject(that.selectable._lastActive.find('a')) : currentValue;
                    daysDifference = daysBetweenTwoDates(fromDate, new Date(+currentValue));
                    addDaysToArray(that._selectDates, daysDifference, fromDate, that.options.disableDates);
                    that.navigate(currentValue);
                    that._current = currentValue;
                    that.selectable._lastActive = that.selectable._lastActive || that._cellByDate(that._view.toDateString(currentValue), CELLSELECTORVALID);
                    that.trigger(CHANGE);
                    return;
                }
                that.selectable.options.filter = that.wrapper.find('table').length > 1 && +currentValue > +that._current ? 'table.k-month:eq(1) ' + CELLSELECTORVALID : 'table.k-month:eq(0) ' + CELLSELECTORVALID;
                that._class(FOCUSED, currentValue);
                that._current = currentValue;
                that._rangeSelection(that._cellByDate(that._view.toDateString(currentValue), CELLSELECTORVALID), currentValue);
                that.trigger(CHANGE);
                that.selectable.options.filter = 'table.k-month:eq(0) ' + CELLSELECTORVALID;
            },
            _keyboardToggleSelection: function (event) {
                var that = this;
                event.currentTarget = that._cell[0];
                that.selectable._lastActive = $(that._cell[0]);
                if ($(that._cell[0]).hasClass(SELECTED)) {
                    that.selectable._unselect($(that._cell[0]));
                    that.selectable.trigger(CHANGE, { event: event });
                } else {
                    that.selectable.value($(that._cell[0]), { event: event });
                }
            },
            _nextNavigatable: function (currentValue, value) {
                var that = this, disabled = true, view = that._view, min = that.options.min, max = that.options.max, isDisabled = that.options.disableDates, navigatableDate = new Date(currentValue.getTime());
                view.setDate(navigatableDate, -value);
                while (disabled) {
                    view.setDate(currentValue, value);
                    if (!isInRange(currentValue, min, max)) {
                        currentValue = navigatableDate;
                        break;
                    }
                    disabled = isDisabled(currentValue);
                }
                return currentValue;
            },
            _animate: function (options) {
                var that = this;
                var from = options.from;
                var to = options.to;
                var active = that._active;
                var viewWrapper = that.element.children('.k-calendar-view');
                if (!from) {
                    viewWrapper.append(to);
                    that._bindTable(to);
                } else if (from.parent().data('animating')) {
                    from.off(ns);
                    from.parent().kendoStop(true, true).remove();
                    from.remove();
                    viewWrapper.append(to);
                    that._focusView(active);
                } else if (!from.is(':visible') || that.options.animation === false || options.replace) {
                    to.insertAfter(from);
                    from.off(ns).remove();
                    that._focusView(active);
                } else {
                    that[options.vertical ? '_vertical' : '_horizontal'](from, to, options.future);
                }
            },
            _horizontal: function (from, to, future) {
                var that = this, active = that._active, horizontal = that.options.animation.horizontal, effects = horizontal.effects, viewWidth = outerWidth(from);
                if (effects && effects.indexOf(SLIDE) != -1) {
                    from.add(to).css({ width: viewWidth });
                    from.wrap('<div/>');
                    that._focusView(active, from);
                    from.parent().css({
                        position: 'relative',
                        width: viewWidth * 2,
                        'float': LEFT,
                        'margin-left': future ? 0 : -viewWidth
                    });
                    to[future ? 'insertAfter' : 'insertBefore'](from);
                    extend(horizontal, {
                        effects: SLIDE + ':' + (future ? 'right' : LEFT),
                        complete: function () {
                            from.off(ns).remove();
                            that._oldTable = null;
                            to.unwrap();
                            that._focusView(active);
                        }
                    });
                    from.parent().kendoStop(true, true).kendoAnimate(horizontal);
                }
            },
            _vertical: function (from, to) {
                var that = this, vertical = that.options.animation.vertical, effects = vertical.effects, active = that._active, cell, position;
                if (effects && effects.indexOf('zoom') != -1) {
                    to.insertBefore(from);
                    from.css({
                        position: 'absolute',
                        width: to.width()
                    });
                    if (transitionOrigin) {
                        cell = that._cellByDate(that._view.toDateString(that._current));
                        position = cell.position();
                        position = position.left + parseInt(cell.width() / 2, 10) + 'px' + ' ' + (position.top + parseInt(cell.height() / 2, 10) + 'px');
                        to.css(transitionOrigin, position);
                    }
                    from.kendoStop(true, true).kendoAnimate({
                        effects: 'fadeOut',
                        duration: 600,
                        complete: function () {
                            from.off(ns).remove();
                            that._oldTable = null;
                            that._focusView(active);
                        }
                    });
                    to.kendoStop(true, true).kendoAnimate(vertical);
                }
            },
            _cellByDate: function (value, selector) {
                return this._table.find(selector ? selector : 'td:not(.' + OTHERMONTH + ')').filter(function () {
                    return $(this.firstChild).attr(kendo.attr(VALUE)) === value;
                });
            },
            _class: function (className, date) {
                var that = this, id = that._cellID, cell = that._cell, value = that._view.toDateString(date), disabledDate;
                if (cell && cell.length) {
                    cell[0].removeAttribute(ARIA_SELECTED);
                    cell[0].removeAttribute(ARIA_LABEL);
                    cell[0].removeAttribute(ID);
                }
                if (date && that._view.name == 'month') {
                    disabledDate = that.options.disableDates(date);
                }
                that._cellsBySelector(that._isMultipleSelection() ? CELLSELECTOR : 'td:not(.' + OTHERMONTH + ')').removeClass(className);
                cell = that._cellByDate(value, that.options.selectable == 'multiple' ? CELLSELECTOR : 'td:not(.' + OTHERMONTH + ')').attr(ARIA_SELECTED, true);
                if (className === FOCUSED && !that._active && that.options.focusOnNav !== false || disabledDate) {
                    className = '';
                }
                cell.addClass(className);
                if (cell[0]) {
                    that._cell = cell;
                }
                if (id) {
                    cell.attr(ID, id);
                    that._table[0].removeAttribute('aria-activedescendant');
                    that._table.attr('aria-activedescendant', id);
                }
            },
            _bindTable: function (table) {
                table.on(FOCUS_WITH_NS, this._addClassProxy).on(BLUR, this._removeClassProxy);
            },
            _click: function (link) {
                var that = this, options = that.options, currentValue = new Date(+that._current), value = toDateObject(link);
                adjustDST(value, 0);
                if (that._view.name == 'month' && that.options.disableDates(value)) {
                    value = that._value;
                }
                that._view.setDate(currentValue, value);
                that.navigateDown(restrictValue(currentValue, options.min, options.max));
            },
            _focus: function (value) {
                var that = this, view = that._view;
                if (view.compare(value, that._current) !== 0) {
                    that.navigate(value);
                } else {
                    that._current = value;
                    that._class(FOCUSED, value);
                }
            },
            _focusView: function (active, table) {
                if (active) {
                    this.focus(table);
                }
            },
            _viewWrapper: function () {
                var that = this;
                var element = that.element;
                var viewWrapper = element.children('.k-calendar-view');
                if (!viewWrapper[0]) {
                    viewWrapper = $('<div class=\'k-calendar-view\' />').insertAfter(element.find('.k-header'));
                }
            },
            _footer: function (template) {
                var that = this, today = getToday(), element = that.element, footer = element.find('.k-footer');
                if (!template) {
                    that._toggle(false);
                    footer.hide();
                    return;
                }
                if (!footer[0]) {
                    footer = $('<div class="k-footer"><a href="#" class="k-link k-nav-today"></a></div>').appendTo(element);
                }
                that._today = footer.show().find('.k-link').html(template(today)).attr('title', kendo.toString(today, 'D', that.options.culture));
                that._toggle();
            },
            _header: function () {
                var that = this, element = that.element, links;
                if (!element.find('.k-header')[0]) {
                    element.html('<div class="k-header">' + '<a href="#" role="button" class="k-link k-nav-prev" ' + ARIA_LABEL + '="Previous"><span class="k-icon k-i-arrow-60-left"></span></a>' + '<a href="#" role="button" aria-live="assertive" aria-atomic="true" class="k-link k-nav-fast"></a>' + '<a href="#" role="button" class="k-link k-nav-next" ' + ARIA_LABEL + '="Next"><span class="k-icon k-i-arrow-60-right"></span></a>' + '</div>');
                }
                links = element.find('.k-link').on(MOUSEENTER_WITH_NS + ' ' + MOUSELEAVE + ' ' + FOCUS_WITH_NS + ' ' + BLUR, mousetoggle).on('click', function () {
                    return false;
                });
                that._title = links.eq(1).on(CLICK, function () {
                    that._active = that.options.focusOnNav !== false;
                    that.navigateUp();
                });
                that[PREVARROW] = links.eq(0).on(CLICK, function () {
                    that._active = that.options.focusOnNav !== false;
                    that.navigateToPast();
                });
                that[NEXTARROW] = links.eq(2).on(CLICK, function () {
                    that._active = that.options.focusOnNav !== false;
                    that.navigateToFuture();
                });
            },
            _navigate: function (arrow, modifier) {
                var that = this, index = that._index + 1, currentValue = new DATE(+that._current);
                if (that._isMultipleSelection()) {
                    var firstDayCurrentMonth = that._table.find('td:not(.k-other-month):not(.k-out-of-range)').has('.k-link').first();
                    currentValue = toDateObject(firstDayCurrentMonth.find('a'));
                    that._current = new Date(+currentValue);
                }
                arrow = that[arrow];
                if (!arrow.hasClass(DISABLED)) {
                    if (index > 3) {
                        currentValue.setFullYear(currentValue.getFullYear() + 100 * modifier);
                    } else {
                        calendar.views[index].setDate(currentValue, modifier);
                    }
                    that.navigate(currentValue);
                }
            },
            _option: function (option, value) {
                var that = this, options = that.options, currentValue = that._value || that._current, isBigger;
                if (value === undefined) {
                    return options[option];
                }
                value = parse(value, options.format, options.culture);
                if (!value) {
                    return;
                }
                options[option] = new DATE(+value);
                if (option === MIN) {
                    isBigger = value > currentValue;
                } else {
                    isBigger = currentValue > value;
                }
                if (isBigger || isEqualMonth(currentValue, value)) {
                    if (isBigger) {
                        that._value = null;
                    }
                    that._changeView = true;
                }
                if (!that._changeView) {
                    that._changeView = !!(options.month.content || options.month.empty);
                }
                that.navigate(that._value);
                that._toggle();
            },
            _toggle: function (toggle) {
                var that = this, options = that.options, isTodayDisabled = that.options.disableDates(getToday()), link = that._today;
                if (toggle === undefined) {
                    toggle = isInRange(getToday(), options.min, options.max);
                }
                if (link) {
                    link.off(CLICK);
                    if (toggle && !isTodayDisabled) {
                        link.addClass(TODAY).removeClass(DISABLED).on(CLICK, proxy(that._todayClick, that));
                    } else {
                        link.removeClass(TODAY).addClass(DISABLED).on(CLICK, prevent);
                    }
                }
            },
            _todayClick: function (e) {
                var that = this, depth = views[that.options.depth], disabled = that.options.disableDates, today = getToday();
                e.preventDefault();
                if (disabled(today)) {
                    return;
                }
                if (that._view.compare(that._current, today) === 0 && that._index == depth) {
                    that._changeView = false;
                }
                if (that._isMultipleSelection()) {
                    that._selectDates = [today];
                    that.selectable._lastActive = null;
                }
                that._value = today;
                that.navigate(today, depth);
                that.trigger(CHANGE);
            },
            _templates: function () {
                var that = this, options = that.options, footer = options.footer, month = options.month, content = month.content, weekNumber = month.weekNumber, empty = month.empty, footerTemplate = '#= kendo.toString(data,"D","' + options.culture + '") #';
                that.month = {
                    content: template('<td#=data.cssClass# role="gridcell"><a tabindex="-1" class="k-link#=data.linkClass#" href="#=data.url#" ' + kendo.attr(VALUE) + '="#=data.dateString#" title="#=data.title#">' + (content || '#=data.value#') + '</a></td>', { useWithBlock: !!content }),
                    empty: template('<td role="gridcell">' + (empty || '&nbsp;') + '</td>', { useWithBlock: !!empty }),
                    weekNumber: template('<td class="k-alt">' + (weekNumber || '#= data.weekNumber #') + '</td>', { useWithBlock: !!weekNumber })
                };
                if (footer && footer !== true) {
                    footerTemplate = footer;
                }
                that.footer = footer !== false ? template(footerTemplate, { useWithBlock: false }) : null;
            }
        });
        ui.plugin(Calendar);
        var calendar = {
            firstDayOfMonth: function (date) {
                return createDate(date.getFullYear(), date.getMonth(), 1);
            },
            firstVisibleDay: function (date, calendarInfo) {
                calendarInfo = calendarInfo || kendo.culture().calendar;
                var firstDay = calendarInfo.firstDay, firstVisibleDay = new DATE(date.getFullYear(), date.getMonth(), 1, date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
                firstVisibleDay.setFullYear(date.getFullYear());
                while (firstVisibleDay.getDay() != firstDay) {
                    calendar.setTime(firstVisibleDay, -1 * MS_PER_DAY);
                }
                return firstVisibleDay;
            },
            setTime: function (date, time) {
                var tzOffsetBefore = date.getTimezoneOffset(), resultDATE = new DATE(date.getTime() + time), tzOffsetDiff = resultDATE.getTimezoneOffset() - tzOffsetBefore;
                date.setTime(resultDATE.getTime() + tzOffsetDiff * MS_PER_MINUTE);
            },
            views: [
                {
                    name: MONTH,
                    title: function (date, min, max, culture) {
                        return getCalendarInfo(culture).months.names[date.getMonth()] + ' ' + date.getFullYear();
                    },
                    content: function (options) {
                        var that = this, idx = 0, min = options.min, max = options.max, date = options.date, dates = options.dates, format = options.format, culture = options.culture, navigateUrl = options.url, showHeader = options.showHeader, otherMonth = options.otherMonth, isWeekColumnVisible = options.isWeekColumnVisible, hasUrl = navigateUrl && dates[0], currentCalendar = getCalendarInfo(culture), firstDayIdx = currentCalendar.firstDay, days = currentCalendar.days, names = shiftArray(days.names, firstDayIdx), shortNames = shiftArray(days.namesShort, firstDayIdx), start = calendar.firstVisibleDay(date, currentCalendar), firstDayOfMonth = that.first(date), lastDayOfMonth = that.last(date), toDateString = that.toDateString, today = getToday(), html = '<table tabindex="0" role="grid" class="k-content" cellspacing="0" data-start="' + toDateString(start) + '">';
                        if (showHeader) {
                            html += '<caption class="k-month-header">' + this.title(date, min, max, culture) + '</caption><thead><tr role="row">';
                        } else {
                            html += '<thead><tr role="row">';
                        }
                        if (isWeekColumnVisible) {
                            html += '<th scope="col" class="k-alt">' + options.messages.weekColumnHeader + '</th>';
                        }
                        for (; idx < 7; idx++) {
                            html += '<th scope="col" title="' + names[idx] + '">' + shortNames[idx] + '</th>';
                        }
                        adjustDST(today, 0);
                        today = +today;
                        return view({
                            cells: 42,
                            perRow: 7,
                            html: html += '</tr></thead><tbody><tr role="row">',
                            start: start,
                            isWeekColumnVisible: isWeekColumnVisible,
                            weekNumber: options.weekNumber,
                            min: createDate(min.getFullYear(), min.getMonth(), min.getDate()),
                            max: createDate(max.getFullYear(), max.getMonth(), max.getDate()),
                            otherMonth: otherMonth,
                            content: options.content,
                            lastDayOfMonth: lastDayOfMonth,
                            empty: options.empty,
                            setter: that.setDate,
                            disableDates: options.disableDates,
                            build: function (date, idx, disableDates) {
                                var cssClass = [], day = date.getDay(), linkClass = '', url = '#';
                                if (date < firstDayOfMonth || date > lastDayOfMonth) {
                                    cssClass.push(OTHERMONTH);
                                }
                                if (disableDates(date)) {
                                    cssClass.push(DISABLED);
                                }
                                if (+date === today) {
                                    cssClass.push('k-today');
                                }
                                if (day === 0 || day === 6) {
                                    cssClass.push('k-weekend');
                                }
                                if (hasUrl && inArray(+date, dates)) {
                                    url = navigateUrl.replace('{0}', kendo.toString(date, format, culture));
                                    linkClass = ' k-action-link';
                                }
                                return {
                                    date: date,
                                    dates: dates,
                                    ns: kendo.ns,
                                    title: kendo.toString(date, 'D', culture),
                                    value: date.getDate(),
                                    dateString: toDateString(date),
                                    cssClass: cssClass[0] ? ' class="' + cssClass.join(' ') + '"' : '',
                                    linkClass: linkClass,
                                    url: url
                                };
                            },
                            weekNumberBuild: function (date) {
                                return {
                                    weekNumber: weekInYear(date, kendo.culture().calendar.firstDay),
                                    currentDate: date
                                };
                            }
                        });
                    },
                    first: function (date) {
                        return calendar.firstDayOfMonth(date);
                    },
                    last: function (date) {
                        var last = createDate(date.getFullYear(), date.getMonth() + 1, 0), first = calendar.firstDayOfMonth(date), timeOffset = Math.abs(last.getTimezoneOffset() - first.getTimezoneOffset());
                        if (timeOffset) {
                            last.setHours(first.getHours() + timeOffset / 60);
                        }
                        return last;
                    },
                    compare: function (date1, date2) {
                        var result, month1 = date1.getMonth(), year1 = date1.getFullYear(), month2 = date2.getMonth(), year2 = date2.getFullYear();
                        if (year1 > year2) {
                            result = 1;
                        } else if (year1 < year2) {
                            result = -1;
                        } else {
                            result = month1 == month2 ? 0 : month1 > month2 ? 1 : -1;
                        }
                        return result;
                    },
                    setDate: function (date, value) {
                        var hours = date.getHours();
                        if (value instanceof DATE) {
                            date.setFullYear(value.getFullYear(), value.getMonth(), value.getDate());
                        } else {
                            calendar.setTime(date, value * MS_PER_DAY);
                        }
                        adjustDST(date, hours);
                    },
                    toDateString: function (date) {
                        return date.getFullYear() + '/' + date.getMonth() + '/' + date.getDate();
                    }
                },
                {
                    name: 'year',
                    title: function (date) {
                        return date.getFullYear();
                    },
                    content: function (options) {
                        var namesAbbr = getCalendarInfo(options.culture).months.namesAbbr, toDateString = this.toDateString, min = options.min, max = options.max, html = '';
                        if (options.showHeader) {
                            html += '<table tabindex="0" role="grid" class="k-content k-meta-view" cellspacing="0"><caption class="k-meta-header">';
                            html += this.title(options.date);
                            html += '</caption><tbody><tr role="row">';
                        }
                        return view({
                            min: createDate(min.getFullYear(), min.getMonth(), 1),
                            max: createDate(max.getFullYear(), max.getMonth(), 1),
                            start: createDate(options.date.getFullYear(), 0, 1),
                            html: html,
                            setter: this.setDate,
                            build: function (date) {
                                return {
                                    value: namesAbbr[date.getMonth()],
                                    ns: kendo.ns,
                                    dateString: toDateString(date),
                                    cssClass: ''
                                };
                            }
                        });
                    },
                    first: function (date) {
                        return createDate(date.getFullYear(), 0, date.getDate());
                    },
                    last: function (date) {
                        return createDate(date.getFullYear(), 11, date.getDate());
                    },
                    compare: function (date1, date2) {
                        return compare(date1, date2);
                    },
                    setDate: function (date, value) {
                        var month, hours = date.getHours();
                        if (value instanceof DATE) {
                            month = value.getMonth();
                            date.setFullYear(value.getFullYear(), month, date.getDate());
                            if (month !== date.getMonth()) {
                                date.setDate(0);
                            }
                        } else {
                            month = date.getMonth() + value;
                            date.setMonth(month);
                            if (month > 11) {
                                month -= 12;
                            }
                            if (month > 0 && date.getMonth() != month) {
                                date.setDate(0);
                            }
                        }
                        adjustDST(date, hours);
                    },
                    toDateString: function (date) {
                        return date.getFullYear() + '/' + date.getMonth() + '/1';
                    }
                },
                {
                    name: 'decade',
                    title: function (date, min, max) {
                        return title(date, min, max, 10);
                    },
                    content: function (options) {
                        var year = options.date.getFullYear(), toDateString = this.toDateString, html = '';
                        if (options.showHeader) {
                            html += '<table tabindex="0" role="grid" class="k-content k-meta-view" cellspacing="0"><caption class="k-meta-header">';
                            html += this.title(options.date, options.min, options.max);
                            html += '</caption><tbody><tr role="row">';
                        }
                        return view({
                            start: createDate(year - year % 10 - 1, 0, 1),
                            min: createDate(options.min.getFullYear(), 0, 1),
                            max: createDate(options.max.getFullYear(), 0, 1),
                            otherMonth: options.otherMonth,
                            html: html,
                            setter: this.setDate,
                            build: function (date, idx) {
                                return {
                                    value: date.getFullYear(),
                                    ns: kendo.ns,
                                    dateString: toDateString(date),
                                    cssClass: idx === 0 || idx == 11 ? OTHERMONTHCLASS : ''
                                };
                            }
                        });
                    },
                    first: function (date) {
                        var year = date.getFullYear();
                        return createDate(year - year % 10, date.getMonth(), date.getDate());
                    },
                    last: function (date) {
                        var year = date.getFullYear();
                        return createDate(year - year % 10 + 9, date.getMonth(), date.getDate());
                    },
                    compare: function (date1, date2) {
                        return compare(date1, date2, 10);
                    },
                    setDate: function (date, value) {
                        setDate(date, value, 1);
                    },
                    toDateString: function (date) {
                        return date.getFullYear() + '/0/1';
                    }
                },
                {
                    name: CENTURY,
                    title: function (date, min, max) {
                        return title(date, min, max, 100);
                    },
                    content: function (options) {
                        var year = options.date.getFullYear(), min = options.min.getFullYear(), max = options.max.getFullYear(), toDateString = this.toDateString, minYear = min, maxYear = max, html = '';
                        minYear = minYear - minYear % 10;
                        maxYear = maxYear - maxYear % 10;
                        if (maxYear - minYear < 10) {
                            maxYear = minYear + 9;
                        }
                        if (options.showHeader) {
                            html += '<table tabindex="0" role="grid" class="k-content k-meta-view" cellspacing="0"><caption class="k-meta-header">';
                            html += this.title(options.date, options.min, options.max);
                            html += '</caption><tbody><tr role="row">';
                        }
                        return view({
                            start: createDate(year - year % 100 - 10, 0, 1),
                            min: createDate(minYear, 0, 1),
                            max: createDate(maxYear, 0, 1),
                            otherMonth: options.otherMonth,
                            html: html,
                            setter: this.setDate,
                            build: function (date, idx) {
                                var start = date.getFullYear(), end = start + 9;
                                if (start < min) {
                                    start = min;
                                }
                                if (end > max) {
                                    end = max;
                                }
                                return {
                                    ns: kendo.ns,
                                    value: start + ' - ' + end,
                                    dateString: toDateString(date),
                                    cssClass: idx === 0 || idx == 11 ? OTHERMONTHCLASS : ''
                                };
                            }
                        });
                    },
                    first: function (date) {
                        var year = date.getFullYear();
                        return createDate(year - year % 100, date.getMonth(), date.getDate());
                    },
                    last: function (date) {
                        var year = date.getFullYear();
                        return createDate(year - year % 100 + 99, date.getMonth(), date.getDate());
                    },
                    compare: function (date1, date2) {
                        return compare(date1, date2, 100);
                    },
                    setDate: function (date, value) {
                        setDate(date, value, 10);
                    },
                    toDateString: function (date) {
                        var year = date.getFullYear();
                        return year - year % 10 + '/0/1';
                    }
                }
            ]
        };
        function title(date, min, max, modular) {
            var start = date.getFullYear(), minYear = min.getFullYear(), maxYear = max.getFullYear(), end;
            start = start - start % modular;
            end = start + (modular - 1);
            if (start < minYear) {
                start = minYear;
            }
            if (end > maxYear) {
                end = maxYear;
            }
            return start + '-' + end;
        }
        function view(options) {
            var idx = 0, data, min = options.min, max = options.max, start = options.start, setter = options.setter, build = options.build, weekNumberBuild = options.weekNumberBuild, length = options.cells || 12, isWeekColumnVisible = options.isWeekColumnVisible, cellsPerRow = options.perRow || 4, otherMonth = options.otherMonth, lastDayOfMonth = options.lastDayOfMonth, weekNumber = options.weekNumber || weekNumberTemplate, content = options.content || cellTemplate, empty = options.empty || emptyCellTemplate, otherMonthTemplate = options.otherMonthCellTemplate || otherMonthCellTemplate, html = options.html || '<table tabindex="0" role="grid" class="k-content k-meta-view" cellspacing="0"><tbody><tr role="row">';
            if (isWeekColumnVisible) {
                html += weekNumber(weekNumberBuild(start));
            }
            for (; idx < length; idx++) {
                if (idx > 0 && idx % cellsPerRow === 0) {
                    html += '</tr><tr role="row">';
                    if (isWeekColumnVisible) {
                        html += otherMonth || +start <= +lastDayOfMonth ? weekNumber(weekNumberBuild(start)) : weekNumber({ weekNumber: '&nbsp;' });
                    }
                }
                start = createDate(start.getFullYear(), start.getMonth(), start.getDate());
                adjustDST(start, 0);
                data = build(start, idx, options.disableDates);
                html += data.cssClass.indexOf(OTHERMONTH) !== -1 && !otherMonth ? otherMonthTemplate(data) : isInRange(start, min, max) ? content(data) : empty(data);
                setter(start, 1);
            }
            return html + '</tr></tbody></table>';
        }
        function compare(date1, date2, modifier) {
            var year1 = date1.getFullYear(), start = date2.getFullYear(), end = start, result = 0;
            if (modifier) {
                start = start - start % modifier;
                end = start - start % modifier + modifier - 1;
            }
            if (year1 > end) {
                result = 1;
            } else if (year1 < start) {
                result = -1;
            }
            return result;
        }
        function getToday() {
            var today = new DATE();
            return new DATE(today.getFullYear(), today.getMonth(), today.getDate());
        }
        function restrictValue(value, min, max) {
            var today = getToday();
            if (value) {
                today = new DATE(+value);
            }
            if (min > today) {
                today = new DATE(+min);
            } else if (max < today) {
                today = new DATE(+max);
            }
            return today;
        }
        function isInRange(date, min, max) {
            return +date >= +min && +date <= +max;
        }
        function shiftArray(array, idx) {
            return array.slice(idx).concat(array.slice(0, idx));
        }
        function setDate(date, value, multiplier) {
            value = value instanceof DATE ? value.getFullYear() : date.getFullYear() + multiplier * value;
            date.setFullYear(value);
        }
        function daysBetweenTwoDates(startDate, endDate) {
            if (+endDate < +startDate) {
                var temp = +startDate;
                calendar.views[0].setDate(startDate, endDate);
                calendar.views[0].setDate(endDate, new Date(temp));
            }
            var fromDateUTC = Date.UTC(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
            var endDateUTC = Date.UTC(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
            return Math.ceil((+endDateUTC - +fromDateUTC) / kendo.date.MS_PER_DAY);
        }
        function addDaysToArray(array, numberOfDays, fromDate, disableDates) {
            for (var i = 0; i <= numberOfDays; i++) {
                var nextDay = new Date(fromDate.getTime());
                nextDay = new Date(nextDay.setDate(nextDay.getDate() + i));
                if (!disableDates(nextDay)) {
                    array.push(nextDay);
                }
            }
        }
        function mousetoggle(e) {
            var disabled = $(this).hasClass('k-state-disabled');
            if (!disabled) {
                $(this).toggleClass(HOVER, MOUSEENTER.indexOf(e.type) > -1 || e.type == FOCUS);
            }
        }
        function prevent(e) {
            e.preventDefault();
        }
        function createDate(year, month, date) {
            var dateObject = new DATE(year, month, date);
            dateObject.setFullYear(year, month, date);
            return dateObject;
        }
        function getCalendarInfo(culture) {
            return getCulture(culture).calendars.standard;
        }
        function normalize(options) {
            var start = views[options.start], depth = views[options.depth], culture = getCulture(options.culture);
            options.format = extractFormat(options.format || culture.calendars.standard.patterns.d);
            if (isNaN(start)) {
                start = 0;
                options.start = MONTH;
            }
            if (depth === undefined || depth > start) {
                options.depth = MONTH;
            }
            if (options.dates === null) {
                options.dates = [];
            }
        }
        function makeUnselectable(element) {
            if (isIE8) {
                element.find('*').attr('unselectable', 'on');
            }
        }
        function addClassToViewContainer(element, currentView) {
            element.addClass('k-' + currentView);
        }
        function inArray(date, dates) {
            for (var i = 0, length = dates.length; i < length; i++) {
                if (date === +dates[i]) {
                    return true;
                }
            }
            return false;
        }
        function isEqualDatePart(value1, value2) {
            if (value1) {
                return value1.getFullYear() === value2.getFullYear() && value1.getMonth() === value2.getMonth() && value1.getDate() === value2.getDate();
            }
            return false;
        }
        function isEqualMonth(value1, value2) {
            if (value1) {
                return value1.getFullYear() === value2.getFullYear() && value1.getMonth() === value2.getMonth();
            }
            return false;
        }
        function getDisabledExpr(option) {
            if (kendo.isFunction(option)) {
                return option;
            }
            if ($.isArray(option)) {
                return createDisabledExpr(option);
            }
            return $.noop;
        }
        function convertDatesArray(dates) {
            var result = [];
            for (var i = 0; i < dates.length; i++) {
                result.push(dates[i].setHours(0, 0, 0, 0));
            }
            return result;
        }
        function createDisabledExpr(dates) {
            var body, callback, disabledDates = [], days = [
                    'su',
                    'mo',
                    'tu',
                    'we',
                    'th',
                    'fr',
                    'sa'
                ], searchExpression = 'if (found) {' + ' return true ' + '} else {' + 'return false' + '}';
            if (dates[0] instanceof DATE) {
                disabledDates = convertDatesArray(dates);
                body = 'var found = date && window.kendo.jQuery.inArray(date.setHours(0, 0, 0, 0),[' + disabledDates + ']) > -1;' + searchExpression;
            } else {
                for (var i = 0; i < dates.length; i++) {
                    var day = dates[i].slice(0, 2).toLowerCase();
                    var index = $.inArray(day, days);
                    if (index > -1) {
                        disabledDates.push(index);
                    }
                }
                body = 'var found = date && window.kendo.jQuery.inArray(date.getDay(),[' + disabledDates + ']) > -1;' + searchExpression;
            }
            callback = new Function('date', body);
            return callback;
        }
        function isEqualDate(oldValue, newValue) {
            if (oldValue instanceof Date && newValue instanceof Date) {
                oldValue = oldValue.getTime();
                newValue = newValue.getTime();
            }
            return oldValue === newValue;
        }
        function toDateObject(link) {
            var value = $(link).attr(kendo.attr(VALUE)).split('/');
            value = createDate(value[0], value[1], value[2]);
            return value;
        }
        calendar.isEqualDatePart = isEqualDatePart;
        calendar.isEqualDate = isEqualDate;
        calendar.makeUnselectable = makeUnselectable;
        calendar.restrictValue = restrictValue;
        calendar.isInRange = isInRange;
        calendar.addClassToViewContainer = addClassToViewContainer;
        calendar.normalize = normalize;
        calendar.viewsEnum = views;
        calendar.disabled = getDisabledExpr;
        calendar.toDateObject = toDateObject;
        calendar.getToday = getToday;
        calendar.createDate = createDate;
        kendo.calendar = calendar;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dateinput', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'dateinput',
        name: 'DateInput',
        category: 'web',
        description: 'The DateInput widget allows to edit date by typing.',
        depends: ['core']
    };
    (function ($, undefined) {
        var global = window;
        var kendo = global.kendo;
        var caret = kendo.caret;
        var ui = kendo.ui;
        var Widget = ui.Widget;
        var keys = kendo.keys;
        var ns = '.kendoDateInput';
        var proxy = $.proxy;
        var objectToString = {}.toString;
        var INPUT_EVENT_NAME = (kendo.support.propertyChangeEvent ? 'propertychange.kendoDateInput input' : 'input') + ns;
        var STATEDISABLED = 'k-state-disabled';
        var STATEDEFAULT = 'k-state-default';
        var STATEINVALID = 'k-state-invalid';
        var DISABLED = 'disabled';
        var READONLY = 'readonly';
        var CHANGE = 'change';
        var knownSymbols = 'dMyHhmftsz';
        var DateInput = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.format = kendo._extractFormat(options.format || kendo.getCulture(options.culture).calendars.standard.patterns.d);
                options.min = kendo.parseDate(element.attr('min')) || kendo.parseDate(options.min);
                options.max = kendo.parseDate(element.attr('max')) || kendo.parseDate(options.max);
                var insidePicker = (element.parent().attr('class') || '').indexOf('k-picker-wrap') >= 0;
                if (insidePicker) {
                    that.wrapper = element.parent();
                } else {
                    that.wrapper = element.wrap('<span class=\'k-widget k-dateinput\'></span>').parent();
                    that.wrapper.addClass(element[0].className);
                    that.wrapper[0].style.cssText = element[0].style.cssText;
                    element.css({
                        width: '100%',
                        height: element[0].style.height
                    });
                }
                that._inputWrapper = $(that.wrapper[0]);
                $('<span class=\'k-icon k-i-warning\'></span>').insertAfter(element);
                that._form();
                that.element.addClass(insidePicker ? ' ' : 'k-textbox').attr('autocomplete', 'off').on('focusout' + ns, function () {
                    that._change();
                });
                try {
                    element[0].setAttribute('type', 'text');
                } catch (e) {
                    element[0].type = 'text';
                }
                var disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                that.value(that.options.value || element.val());
                kendo.notify(that);
            },
            options: {
                name: 'DateInput',
                culture: '',
                value: '',
                format: '',
                min: new Date(1900, 0, 1),
                max: new Date(2099, 11, 31),
                messages: {
                    'year': 'year',
                    'month': 'month',
                    'day': 'day',
                    'weekday': 'day of the week',
                    'hour': 'hours',
                    'minute': 'minutes',
                    'second': 'seconds',
                    'dayperiod': 'AM/PM'
                }
            },
            events: [CHANGE],
            min: function (value) {
                if (value !== undefined) {
                    this.options.min = value;
                } else {
                    return this.options.min;
                }
            },
            max: function (value) {
                if (value !== undefined) {
                    this.options.max = value;
                } else {
                    return this.options.max;
                }
            },
            setOptions: function (options) {
                var that = this;
                Widget.fn.setOptions.call(that, options);
                this._unbindInput();
                this._bindInput();
                this._updateElementValue();
            },
            destroy: function () {
                var that = this;
                that.element.off(ns);
                if (that._formElement) {
                    that._formElement.off('reset', that._resetHandler);
                }
                Widget.fn.destroy.call(that);
            },
            value: function (value) {
                if (value === undefined) {
                    return this._dateTime.getDateObject();
                }
                if (value === null) {
                    value = '';
                }
                if (objectToString.call(value) !== '[object Date]') {
                    value = kendo.parseDate(value, this.options.format, this.options.culture);
                }
                if (value && !value.getTime()) {
                    value = null;
                }
                this._dateTime = new customDateTime(value, this.options.format, this.options.culture, this.options.messages);
                this._updateElementValue();
                this._oldValue = value;
            },
            _updateElementValue: function () {
                var stringAndFromat = this._dateTime.toPair(this.options.format, this.options.culture, this.options.messages);
                this.element.val(stringAndFromat[0]);
                this._oldText = stringAndFromat[0];
                this._format = stringAndFromat[1];
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            _bindInput: function () {
                var that = this;
                that.element.on('focusout' + ns, function () {
                    that._change();
                }).on('paste' + ns, proxy(that._paste, that)).on('keydown' + ns, proxy(that._keydown, that)).on(INPUT_EVENT_NAME, proxy(that._input, that)).on('mouseup' + ns, proxy(that._mouseUp, that)).on('DOMMouseScroll' + ns + ' mousewheel' + ns, proxy(that._scroll, that));
            },
            _unbindInput: function () {
                this.element.off('keydown' + ns).off('paste' + ns).off('focusout' + ns).off(INPUT_EVENT_NAME).off('mouseup' + ns).off('DOMMouseScroll' + ns + ' mousewheel' + ns);
            },
            _editable: function (options) {
                var that = this;
                var element = that.element;
                var disable = options.disable;
                var readonly = options.readonly;
                var wrapper = that.wrapper;
                that._unbindInput();
                if (!readonly && !disable) {
                    wrapper.addClass(STATEDEFAULT).removeClass(STATEDISABLED);
                    if (element && element.length) {
                        element[0].removeAttribute(DISABLED);
                        element[0].removeAttribute(READONLY);
                    }
                    that._bindInput();
                } else {
                    if (disable) {
                        wrapper.addClass(STATEDISABLED).removeClass(STATEDEFAULT);
                        element.attr(DISABLED, disable);
                        if (element && element.length) {
                            element[0].removeAttribute(READONLY);
                        }
                    }
                    if (readonly) {
                        element.attr(READONLY, readonly);
                    }
                }
            },
            _change: function () {
                var that = this;
                var oldValue = that._oldValue;
                var value = that.value();
                if (value && that.min() && value < that.min()) {
                    that.value(that.min());
                    value = that.value();
                }
                if (value && that.max() && value > that.max()) {
                    that.value(that.max());
                    value = that.value();
                }
                if (oldValue && value && value.getTime() !== oldValue.getTime() || oldValue && !value || !oldValue && value) {
                    that._oldValue = value;
                    that.trigger(CHANGE);
                    that.element.trigger(CHANGE);
                }
            },
            _input: function () {
                var that = this;
                var element = that.element[0];
                var blinkInvalid = false;
                if (kendo._activeElement() !== element) {
                    return;
                }
                var diff = approximateStringMatching(this._oldText, this._format, this.element[0].value, caret(this.element[0])[0]);
                var navigationOnly = diff.length === 1 && diff[0][1] === ' ';
                if (!navigationOnly) {
                    for (var i = 0; i < diff.length; i++) {
                        var valid = this._dateTime.parsePart(diff[i][0], diff[i][1]);
                        blinkInvalid = blinkInvalid || !valid;
                    }
                }
                this._updateElementValue();
                if (diff.length && diff[0][0] !== ' ') {
                    this._selectSegment(diff[0][0]);
                    if (!navigationOnly) {
                        var difSym = diff[0][0];
                        setTimeout(function () {
                            that._selectSegment(difSym);
                        });
                    }
                }
                if (navigationOnly) {
                    var newEvent = {
                        keyCode: 39,
                        preventDefault: function () {
                        }
                    };
                    this._keydown(newEvent);
                }
                if (blinkInvalid) {
                    clearTimeout(that._blinkInvalidTimeout);
                    var stateInvalid = STATEINVALID;
                    that.wrapper.addClass(STATEINVALID);
                    that._blinkInvalidTimeout = setTimeout(function () {
                        that.wrapper.removeClass(stateInvalid);
                    }, 100);
                }
            },
            _mouseUp: function () {
                var selection = caret(this.element[0]);
                if (selection[0] === selection[1]) {
                    this._selectNearestSegment();
                }
            },
            _scroll: function (e) {
                if (kendo._activeElement() !== this.element[0] || this.element.is('[readonly]')) {
                    return;
                }
                e = window.event || e;
                var newEvent = {
                    keyCode: 37,
                    preventDefault: function () {
                    }
                };
                if (e.shiftKey) {
                    newEvent.keyCode = (e.wheelDelta || -e.detail) > 0 ? 37 : 39;
                } else {
                    newEvent.keyCode = (e.wheelDelta || -e.detail) > 0 ? 38 : 40;
                }
                this._keydown(newEvent);
                e.returnValue = false;
                if (e.preventDefault) {
                    e.preventDefault();
                }
                if (e.stopPropagation) {
                    e.stopPropagation();
                }
            },
            _form: function () {
                var that = this;
                var element = that.element;
                var formId = element.attr('form');
                var form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(element[0].value);
                        });
                    };
                    that._formElement = form.on('reset', that._resetHandler);
                }
            },
            _paste: function (e) {
                e.preventDefault();
            },
            _keydown: function (e) {
                var key = e.keyCode;
                var selection;
                if (key == 37 || key == 39) {
                    e.preventDefault();
                    selection = caret(this.element[0]);
                    if (selection[0] != selection[1]) {
                        this._selectNearestSegment();
                    }
                    var dir = key == 37 ? -1 : 1;
                    var index = dir == -1 ? caret(this.element[0])[0] - 1 : caret(this.element[0])[1] + 1;
                    while (index >= 0 && index < this._format.length) {
                        if (knownSymbols.indexOf(this._format[index]) >= 0) {
                            this._selectSegment(this._format[index]);
                            break;
                        }
                        index += dir;
                    }
                }
                if (key == 38 || key == 40) {
                    e.preventDefault();
                    selection = caret(this.element[0]);
                    var symbol = this._format[selection[0]];
                    if (knownSymbols.indexOf(symbol) >= 0) {
                        this._dateTime.modifyPart(symbol, key == 38 ? 1 : -1);
                        this._updateElementValue();
                        this._selectSegment(symbol);
                        this.element.trigger(CHANGE);
                    }
                }
                if (kendo.support.browser.msie && kendo.support.browser.version < 10) {
                    var keycode = e.keyCode ? e.keyCode : e.which;
                    if (keycode === 8 || keycode === 46) {
                        var that = this;
                        setTimeout(function () {
                            that._input();
                        }, 0);
                    }
                }
                if (key === keys.ENTER) {
                    this._change();
                }
            },
            _selectNearestSegment: function () {
                var selection = caret(this.element[0]);
                var start = selection[0];
                for (var i = start, j = start - 1; i < this._format.length || j >= 0; i++, j--) {
                    if (i < this._format.length && knownSymbols.indexOf(this._format[i]) !== -1) {
                        this._selectSegment(this._format[i]);
                        return;
                    }
                    if (j >= 0 && knownSymbols.indexOf(this._format[j]) !== -1) {
                        this._selectSegment(this._format[j]);
                        return;
                    }
                }
            },
            _selectSegment: function (symbol) {
                var begin = -1, end = 0;
                for (var i = 0; i < this._format.length; i++) {
                    if (this._format[i] === symbol) {
                        end = i + 1;
                        if (begin === -1) {
                            begin = i;
                        }
                    }
                }
                if (begin < 0) {
                    begin = 0;
                }
                caret(this.element, begin, end);
            }
        });
        ui.plugin(DateInput);
        var customDateTime = function (initDate, initFormat, initCulture, initMessages) {
            var value = null;
            var year = true, month = true, date = true, hours = true, minutes = true, seconds = true, milliseconds = true;
            var typedMonthPart = '';
            var typedDayPeriodPart = '';
            var placeholders = {};
            var zeros = [
                '',
                '0',
                '00',
                '000',
                '0000'
            ];
            function pad(number, digits, end) {
                number = number + '';
                digits = digits || 2;
                end = digits - number.length;
                if (end) {
                    return zeros[digits].substring(0, end) + number;
                }
                return number;
            }
            var dateFormatRegExp = /dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|HH|H|hh|h|mm|m|fff|ff|f|tt|ss|s|zzz|zz|z|"[^"]*"|'[^']*'/g;
            var months = null, calendar = null, days = null, returnsFormat = false;
            var matcher = function (match) {
                var mins, sign;
                var result;
                switch (match) {
                case 'd':
                    result = date ? value.getDate() : placeholders.day;
                    break;
                case 'dd':
                    result = date ? pad(value.getDate()) : placeholders.day;
                    break;
                case 'ddd':
                    result = date && month && year ? days.namesAbbr[value.getDay()] : placeholders.weekday;
                    break;
                case 'dddd':
                    result = date && month && year ? days.names[value.getDay()] : placeholders.weekday;
                    break;
                case 'M':
                    result = month ? value.getMonth() + 1 : placeholders.month;
                    break;
                case 'MM':
                    result = month ? pad(value.getMonth() + 1) : placeholders.month;
                    break;
                case 'MMM':
                    result = month ? months.namesAbbr[value.getMonth()] : placeholders.month;
                    break;
                case 'MMMM':
                    result = month ? months.names[value.getMonth()] : placeholders.month;
                    break;
                case 'yy':
                    result = year ? pad(value.getFullYear() % 100) : placeholders.year;
                    break;
                case 'yyyy':
                    result = year ? pad(value.getFullYear(), 4) : placeholders.year;
                    break;
                case 'h':
                    result = hours ? value.getHours() % 12 || 12 : placeholders.hour;
                    break;
                case 'hh':
                    result = hours ? pad(value.getHours() % 12 || 12) : placeholders.hour;
                    break;
                case 'H':
                    result = hours ? value.getHours() : placeholders.hour;
                    break;
                case 'HH':
                    result = hours ? pad(value.getHours()) : placeholders.hour;
                    break;
                case 'm':
                    result = minutes ? value.getMinutes() : placeholders.minute;
                    break;
                case 'mm':
                    result = minutes ? pad(value.getMinutes()) : placeholders.minute;
                    break;
                case 's':
                    result = seconds ? value.getSeconds() : placeholders.second;
                    break;
                case 'ss':
                    result = seconds ? pad(value.getSeconds()) : placeholders.second;
                    break;
                case 'f':
                    result = milliseconds ? Math.floor(value.getMilliseconds() / 100) : milliseconds;
                    break;
                case 'ff':
                    result = value.getMilliseconds();
                    if (result > 99) {
                        result = Math.floor(result / 10);
                    }
                    result = milliseconds ? pad(result) : match;
                    break;
                case 'fff':
                    result = milliseconds ? pad(value.getMilliseconds(), 3) : match;
                    break;
                case 'tt':
                    result = hours ? value.getHours() < 12 ? calendar.AM[0] : calendar.PM[0] : placeholders.dayperiod;
                    break;
                case 'zzz':
                    mins = value.getTimezoneOffset();
                    sign = mins < 0;
                    result = Math.abs(mins / 60).toString().split('.')[0];
                    mins = Math.abs(mins) - result * 60;
                    result = (sign ? '+' : '-') + pad(result);
                    result += ':' + pad(mins);
                    break;
                case 'z':
                case 'zz':
                    result = value.getTimezoneOffset() / 60;
                    sign = result < 0;
                    result = Math.abs(result).toString().split('.')[0];
                    result = (sign ? '+' : '-') + (match === 'zz' ? pad(result) : result);
                    break;
                }
                result = result !== undefined ? result : match.slice(1, match.length - 1);
                if (returnsFormat) {
                    result = '' + result;
                    var formatResult = '';
                    if (match == 'ddd') {
                        match = 'EEE';
                    }
                    if (match == 'dddd') {
                        match = 'EEEE';
                    }
                    for (var i = 0; i < result.length; i++) {
                        formatResult += match[0];
                    }
                    return formatResult;
                } else {
                    return result;
                }
            };
            function generateMatcher(retFormat) {
                returnsFormat = retFormat;
                return matcher;
            }
            function setExisting(symbol, val) {
                switch (symbol) {
                case 'y':
                    year = val;
                    break;
                case 'M':
                    month = val;
                    if (!val) {
                        value.setMonth(0);
                        typedMonthPart = '';
                    }
                    break;
                case 'd':
                    date = val;
                    break;
                case 'H':
                case 'h':
                    hours = val;
                    if (!val) {
                        typedDayPeriodPart = '';
                    }
                    break;
                case 'm':
                    minutes = val;
                    break;
                case 's':
                    seconds = val;
                    break;
                default:
                    return;
                }
            }
            this.setValue = function (val) {
                date = val;
            };
            this.getValue = function () {
                return date;
            };
            this.modifyPart = function (symbol, offset) {
                var newValue = new Date(value && value.getTime ? value.getTime() : value);
                switch (symbol) {
                case 'y':
                    newValue.setFullYear(newValue.getFullYear() + offset);
                    break;
                case 'M':
                    var newMonth = newValue.getMonth() + offset;
                    newValue.setMonth(newMonth);
                    if (newValue.getMonth() % 12 !== (newMonth + 12) % 12) {
                        newValue.setDate(1);
                        newValue.setMonth(newMonth);
                    }
                    break;
                case 'd':
                case 'E':
                    newValue.setDate(newValue.getDate() + offset);
                    break;
                case 'H':
                case 'h':
                    newValue.setHours(newValue.getHours() + offset);
                    break;
                case 'm':
                    newValue.setMinutes(newValue.getMinutes() + offset);
                    break;
                case 's':
                    newValue.setSeconds(newValue.getSeconds() + offset);
                    break;
                case 't':
                    newValue.setHours((newValue.getHours() + 12) % 24);
                    break;
                default:
                    break;
                }
                if (newValue.getFullYear() > 0) {
                    setExisting(symbol, true);
                    value = newValue;
                }
            };
            this.parsePart = function (symbol, currentChar) {
                if (!currentChar) {
                    setExisting(symbol, false);
                    return true;
                }
                var newValue = new Date(value && value.getTime ? value.getTime() : value);
                var newHours;
                switch (symbol) {
                case 'd':
                    var newDate = (date ? newValue.getDate() * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newDate)) {
                        return;
                    }
                    while (newDate > 31) {
                        newDate = parseInt(newDate.toString().slice(1), 10);
                    }
                    if (newDate < 1) {
                        date = false;
                    } else {
                        newValue.setDate(newDate);
                        if (newValue.getMonth() !== value.getMonth()) {
                            return;
                        }
                        date = true;
                    }
                    break;
                case 'M':
                    var newMonth = (month ? (newValue.getMonth() + 1) * 10 : 0) + parseInt(currentChar, 10);
                    if (!isNaN(newMonth)) {
                        while (newMonth > 12) {
                            newMonth = parseInt(newMonth.toString().slice(1), 10);
                        }
                        if (newMonth < 1) {
                            month = false;
                        } else {
                            newValue.setMonth(newMonth - 1);
                            if (newValue.getMonth() !== newMonth - 1) {
                                newValue.setDate(1);
                                newValue.setMonth(newMonth - 1);
                            }
                            month = true;
                        }
                    } else {
                        var monthNames = calendar.months.names;
                        typedMonthPart += currentChar.toLowerCase();
                        while (typedMonthPart.length > 0) {
                            for (var i = 0; i < monthNames.length; i++) {
                                if (monthNames[i].toLowerCase().indexOf(typedMonthPart) === 0) {
                                    newValue.setMonth(i);
                                    month = true;
                                    value = newValue;
                                    return true;
                                }
                            }
                            typedMonthPart = typedMonthPart.substring(1, typedMonthPart.length);
                        }
                        return false;
                    }
                    break;
                case 'y':
                    var newYear = (year ? newValue.getFullYear() * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newYear)) {
                        return;
                    }
                    while (newYear > 9999) {
                        newYear = parseInt(newYear.toString().slice(1), 10);
                    }
                    if (newYear < 1) {
                        year = false;
                    } else {
                        newValue.setFullYear(newYear);
                        year = true;
                    }
                    break;
                case 'h':
                    newHours = (hours ? (newValue.getHours() % 12 || 12) * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newHours)) {
                        return;
                    }
                    while (newHours > 12) {
                        newHours = parseInt(newHours.toString().slice(1), 10);
                    }
                    newValue.setHours(Math.floor(newValue.getHours() / 12) * 12 + newHours % 12);
                    hours = true;
                    break;
                case 'H':
                    newHours = (hours ? newValue.getHours() * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newHours)) {
                        return;
                    }
                    while (newHours > 23) {
                        newHours = parseInt(newHours.toString().slice(1), 10);
                    }
                    newValue.setHours(newHours);
                    hours = true;
                    break;
                case 'm':
                    var newMinutes = (minutes ? newValue.getMinutes() * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newMinutes)) {
                        return;
                    }
                    while (newMinutes > 59) {
                        newMinutes = parseInt(newMinutes.toString().slice(1), 10);
                    }
                    newValue.setMinutes(newMinutes);
                    minutes = true;
                    break;
                case 's':
                    var newSeconds = (seconds ? newValue.getSeconds() * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newSeconds)) {
                        return;
                    }
                    while (newSeconds > 59) {
                        newSeconds = parseInt(newSeconds.toString().slice(1), 10);
                    }
                    newValue.setSeconds(newSeconds);
                    seconds = true;
                    break;
                case 't':
                    if (hours) {
                        typedDayPeriodPart += currentChar.toLowerCase();
                        while (typedDayPeriodPart.length > 0) {
                            if (calendar.AM[0].toLowerCase().indexOf(typedDayPeriodPart) === 0 && newValue.getHours() >= 12 || calendar.PM[0].toLowerCase().indexOf(typedDayPeriodPart) === 0 && newValue.getHours() < 12) {
                                newValue.setHours((newValue.getHours() + 12) % 24);
                                value = newValue;
                                return true;
                            }
                            typedDayPeriodPart = typedDayPeriodPart.substring(1, typedDayPeriodPart.length);
                        }
                        return false;
                    }
                    break;
                default:
                    break;
                }
                value = newValue;
                return true;
            };
            this.toPair = function (format, culture, messages) {
                if (!format) {
                    return [
                        '',
                        ''
                    ];
                }
                culture = kendo.getCulture(culture);
                calendar = culture.calendars.standard;
                format = calendar.patterns[format] || format;
                days = calendar.days;
                months = calendar.months;
                placeholders = messages;
                return [
                    format.replace(dateFormatRegExp, generateMatcher(false)),
                    format.replace(dateFormatRegExp, generateMatcher(true))
                ];
            };
            this.getDateObject = function () {
                return year && month && date && hours && minutes && seconds && milliseconds ? new Date(value.getTime()) : null;
            };
            if (!initDate) {
                value = new Date();
                var sampleFormat = this.toPair(initFormat, initCulture, initMessages)[1];
                for (var i = 0; i < sampleFormat.length; i++) {
                    setExisting(sampleFormat[i], false);
                }
            } else {
                value = new Date(initDate.getTime());
            }
        };
        function approximateStringMatching(oldText, oldFormat, newText, caret) {
            var oldTextSeparator = oldText[caret + oldText.length - newText.length];
            oldText = oldText.substring(0, caret + oldText.length - newText.length);
            newText = newText.substring(0, caret);
            var diff = [];
            var i;
            if (oldText === newText && caret > 0) {
                diff.push([
                    oldFormat[caret - 1],
                    newText[caret - 1]
                ]);
                return diff;
            }
            if (oldText.indexOf(newText) === 0 && (newText.length === 0 || oldFormat[newText.length - 1] !== oldFormat[newText.length])) {
                var deletedSymbol = '';
                for (i = newText.length; i < oldText.length; i++) {
                    if (oldFormat[i] !== deletedSymbol && knownSymbols.indexOf(oldFormat[i]) >= 0) {
                        deletedSymbol = oldFormat[i];
                        diff.push([
                            deletedSymbol,
                            ''
                        ]);
                    }
                }
                return diff;
            }
            if (newText[newText.length - 1] === ' ' || newText[newText.length - 1] === oldTextSeparator) {
                return [[
                        oldFormat[caret - 1],
                        ' '
                    ]];
            }
            if (newText.indexOf(oldText) === 0 || knownSymbols.indexOf(oldFormat[caret - 1]) === -1) {
                var symbol = oldFormat[0];
                for (i = Math.max(0, oldText.length - 1); i < oldFormat.length; i++) {
                    if (knownSymbols.indexOf(oldFormat[i]) >= 0) {
                        symbol = oldFormat[i];
                        break;
                    }
                }
                return [[
                        symbol,
                        newText[caret - 1]
                    ]];
            }
            return [[
                    oldFormat[caret - 1],
                    newText[caret - 1]
                ]];
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.datepicker', [
        'kendo.calendar',
        'kendo.popup',
        'kendo.dateinput'
    ], f);
}(function () {
    var __meta__ = {
        id: 'datepicker',
        name: 'DatePicker',
        category: 'web',
        description: 'The DatePicker widget allows the user to select a date from a calendar or by direct input.',
        depends: [
            'calendar',
            'popup'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, parse = kendo.parseDate, keys = kendo.keys, support = kendo.support, template = kendo.template, activeElement = kendo._activeElement, DIV = '<div />', SPAN = '<span />', ns = '.kendoDatePicker', CLICK = 'click' + ns, UP = support.mouseAndTouchPresent ? kendo.applyEventMap('up', ns.slice(1)) : CLICK, OPEN = 'open', CLOSE = 'close', CHANGE = 'change', DISABLED = 'disabled', READONLY = 'readonly', DEFAULT = 'k-state-default', FOCUSED = 'k-state-focused', SELECTED = 'k-state-selected', STATEDISABLED = 'k-state-disabled', HOVER = 'k-state-hover', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, MOUSEDOWN = 'mousedown' + ns, ID = 'id', MIN = 'min', MAX = 'max', MONTH = 'month', ARIA_DISABLED = 'aria-disabled', ARIA_EXPANDED = 'aria-expanded', ARIA_HIDDEN = 'aria-hidden', calendar = kendo.calendar, isInRange = calendar.isInRange, restrictValue = calendar.restrictValue, isEqualDatePart = calendar.isEqualDatePart, extend = $.extend, proxy = $.proxy, DATE = Date;
        function normalize(options) {
            var parseFormats = options.parseFormats, format = options.format;
            calendar.normalize(options);
            parseFormats = $.isArray(parseFormats) ? parseFormats : [parseFormats];
            if (!parseFormats.length) {
                parseFormats.push('yyyy-MM-dd');
            }
            if ($.inArray(format, parseFormats) === -1) {
                parseFormats.splice(0, 0, options.format);
            }
            options.parseFormats = parseFormats;
        }
        function preventDefault(e) {
            e.preventDefault();
        }
        var DateView = function (options) {
            var that = this, id, body = document.body, div = $(DIV).attr(ARIA_HIDDEN, 'true').addClass('k-calendar-container').appendTo(body);
            that.options = options = options || {};
            id = options.id;
            if (id) {
                id += '_dateview';
                div.attr(ID, id);
                that._dateViewID = id;
            }
            that.popup = new ui.Popup(div, extend(options.popup, options, {
                name: 'Popup',
                isRtl: kendo.support.isRtl(options.anchor)
            }));
            that.div = div;
            that.value(options.value);
        };
        DateView.prototype = {
            _calendar: function () {
                var that = this;
                var calendar = that.calendar;
                var options = that.options;
                var div;
                if (!calendar) {
                    div = $(DIV).attr(ID, kendo.guid()).appendTo(that.popup.element).on(MOUSEDOWN, preventDefault).on(CLICK, 'td:has(.k-link)', proxy(that._click, that));
                    that.calendar = calendar = new ui.Calendar(div);
                    that._setOptions(options);
                    kendo.calendar.makeUnselectable(calendar.element);
                    calendar.navigate(that._value || that._current, options.start);
                    that.value(that._value);
                }
            },
            _setOptions: function (options) {
                this.calendar.setOptions({
                    focusOnNav: false,
                    change: options.change,
                    culture: options.culture,
                    dates: options.dates,
                    depth: options.depth,
                    footer: options.footer,
                    format: options.format,
                    max: options.max,
                    min: options.min,
                    month: options.month,
                    weekNumber: options.weekNumber,
                    start: options.start,
                    disableDates: options.disableDates
                });
            },
            setOptions: function (options) {
                var old = this.options;
                var disableDates = options.disableDates;
                if (disableDates) {
                    options.disableDates = calendar.disabled(disableDates);
                }
                this.options = extend(old, options, {
                    change: old.change,
                    close: old.close,
                    open: old.open
                });
                if (this.calendar) {
                    this._setOptions(this.options);
                }
            },
            destroy: function () {
                this.popup.destroy();
            },
            open: function () {
                var that = this;
                var popupHovered;
                that._calendar();
                popupHovered = that.popup._hovered;
                that.popup._hovered = true;
                that.popup.open();
                setTimeout(function () {
                    that.popup._hovered = popupHovered;
                }, 1);
            },
            close: function () {
                this.popup.close();
            },
            min: function (value) {
                this._option(MIN, value);
            },
            max: function (value) {
                this._option(MAX, value);
            },
            toggle: function () {
                var that = this;
                that[that.popup.visible() ? CLOSE : OPEN]();
            },
            move: function (e) {
                var that = this, key = e.keyCode, calendar = that.calendar, selectIsClicked = e.ctrlKey && key == keys.DOWN || key == keys.ENTER, handled = false;
                if (e.altKey) {
                    if (key == keys.DOWN) {
                        that.open();
                        e.preventDefault();
                        handled = true;
                    } else if (key == keys.UP) {
                        that.close();
                        e.preventDefault();
                        handled = true;
                    }
                } else if (that.popup.visible()) {
                    if (key == keys.ESC || selectIsClicked && calendar._cell.hasClass(SELECTED)) {
                        that.close();
                        e.preventDefault();
                        return true;
                    }
                    if (key != keys.SPACEBAR) {
                        that._current = calendar._move(e);
                    }
                    handled = true;
                }
                return handled;
            },
            current: function (date) {
                this._current = date;
                this.calendar._focus(date);
            },
            value: function (value) {
                var that = this, calendar = that.calendar, options = that.options, disabledDate = options.disableDates;
                if (disabledDate && disabledDate(value)) {
                    value = null;
                }
                that._value = value;
                that._current = new DATE(+restrictValue(value, options.min, options.max));
                if (calendar) {
                    calendar.value(value);
                }
            },
            _click: function (e) {
                if (e.currentTarget.className.indexOf(SELECTED) !== -1) {
                    this.calendar.trigger('change');
                    this.close();
                }
            },
            _option: function (option, value) {
                var that = this;
                var calendar = that.calendar;
                that.options[option] = value;
                if (calendar) {
                    calendar[option](value);
                }
            }
        };
        DateView.normalize = normalize;
        kendo.DateView = DateView;
        var DatePicker = Widget.extend({
            init: function (element, options) {
                var that = this, disabled, div;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.disableDates = kendo.calendar.disabled(options.disableDates);
                options.min = parse(element.attr('min')) || parse(options.min);
                options.max = parse(element.attr('max')) || parse(options.max);
                normalize(options);
                that._initialOptions = extend({}, options);
                that._wrapper();
                that.dateView = new DateView(extend({}, options, {
                    id: element.attr(ID),
                    anchor: that.wrapper,
                    change: function () {
                        that._change(this.value());
                        that.close();
                    },
                    close: function (e) {
                        if (that.trigger(CLOSE)) {
                            e.preventDefault();
                        } else {
                            element.attr(ARIA_EXPANDED, false);
                            div.attr(ARIA_HIDDEN, true);
                        }
                    },
                    open: function (e) {
                        var options = that.options, date;
                        if (that.trigger(OPEN)) {
                            e.preventDefault();
                        } else {
                            if (that.element.val() !== that._oldText) {
                                date = parse(element.val(), options.parseFormats, options.culture);
                                that.dateView[date ? 'current' : 'value'](date);
                            }
                            element.attr(ARIA_EXPANDED, true);
                            div.attr(ARIA_HIDDEN, false);
                            that._updateARIA(date);
                        }
                    }
                }));
                div = that.dateView.div;
                that._icon();
                try {
                    element[0].setAttribute('type', 'text');
                } catch (e) {
                    element[0].type = 'text';
                }
                element.addClass('k-input').attr({
                    role: 'combobox',
                    'aria-expanded': false,
                    'aria-owns': that.dateView._dateViewID,
                    'autocomplete': 'off'
                });
                that._reset();
                that._template();
                disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                that._createDateInput(options);
                that._old = that._update(options.value || that.element.val());
                that._oldText = element.val();
                kendo.notify(that);
            },
            events: [
                OPEN,
                CLOSE,
                CHANGE
            ],
            options: {
                name: 'DatePicker',
                value: null,
                footer: '',
                format: '',
                culture: '',
                parseFormats: [],
                min: new Date(1900, 0, 1),
                max: new Date(2099, 11, 31),
                start: MONTH,
                depth: MONTH,
                animation: {},
                month: {},
                dates: [],
                disableDates: null,
                ARIATemplate: 'Current focused date is #=kendo.toString(data.current, "D")#',
                dateInput: false,
                weekNumber: false
            },
            setOptions: function (options) {
                var that = this;
                var value = that._value;
                Widget.fn.setOptions.call(that, options);
                options = that.options;
                options.min = parse(options.min);
                options.max = parse(options.max);
                normalize(options);
                that.dateView.setOptions(options);
                that._createDateInput(options);
                if (!that._dateInput) {
                    that.element.val(kendo.toString(value, options.format, options.culture));
                }
                if (value) {
                    that._updateARIA(value);
                }
            },
            _editable: function (options) {
                var that = this, icon = that._dateIcon.off(ns), element = that.element.off(ns), wrapper = that._inputWrapper.off(ns), readonly = options.readonly, disable = options.disable;
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    if (element && element.length) {
                        element[0].removeAttribute(DISABLED);
                        element[0].removeAttribute(READONLY);
                    }
                    element.attr(ARIA_DISABLED, false).on('keydown' + ns, proxy(that._keydown, that)).on('focusout' + ns, proxy(that._blur, that)).on('focus' + ns, function () {
                        that._inputWrapper.addClass(FOCUSED);
                    });
                    icon.on(UP, proxy(that._click, that)).on(MOUSEDOWN, preventDefault);
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    element.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
                if (this._dateInput) {
                    this._dateInput._editable({
                        readonly: readonly === undefined ? true : readonly,
                        disable: false
                    });
                }
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
                if (this._dateInput) {
                    this._dateInput._editable({
                        readonly: false,
                        disable: !(enable = enable === undefined ? true : enable)
                    });
                }
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.dateView.destroy();
                that.element.off(ns);
                that._dateIcon.off(ns);
                that._inputWrapper.off(ns);
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
            },
            open: function () {
                this.dateView.open();
            },
            close: function () {
                this.dateView.close();
            },
            min: function (value) {
                return this._option(MIN, value);
            },
            max: function (value) {
                return this._option(MAX, value);
            },
            value: function (value) {
                var that = this;
                if (value === undefined) {
                    return that._value;
                }
                that._old = that._update(value);
                if (that._old === null) {
                    that.element.val('');
                }
                that._oldText = that.element.val();
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _blur: function () {
                var that = this, value = that.element.val();
                that.close();
                if (value !== that._oldText) {
                    that._change(value);
                }
                that._inputWrapper.removeClass(FOCUSED);
            },
            _click: function (e) {
                var that = this;
                that.dateView.toggle();
                that._focusElement(e.type);
            },
            _focusElement: function (eventType) {
                var element = this.element;
                if ((!support.touch || support.mouseAndTouchPresent && !(eventType || '').match(/touch/i)) && element[0] !== activeElement()) {
                    element.trigger('focus');
                }
            },
            _change: function (value) {
                var that = this, oldValue = that.element.val(), dateChanged;
                value = that._update(value);
                dateChanged = !kendo.calendar.isEqualDate(that._old, value);
                var valueUpdated = dateChanged && !that._typing;
                var textFormatted = oldValue !== that.element.val();
                if (valueUpdated || textFormatted) {
                    that.element.trigger(CHANGE);
                }
                if (dateChanged) {
                    that._old = value;
                    that._oldText = that.element.val();
                    that.trigger(CHANGE);
                }
                that._typing = false;
            },
            _keydown: function (e) {
                var that = this, dateView = that.dateView, value = that.element.val(), handled = false;
                if (!dateView.popup.visible() && e.keyCode == keys.ENTER && value !== that._oldText) {
                    that._change(value);
                } else {
                    handled = dateView.move(e);
                    that._updateARIA(dateView._current);
                    if (!handled) {
                        that._typing = true;
                    } else if (that._dateInput && e.stopImmediatePropagation) {
                        e.stopImmediatePropagation();
                    }
                }
            },
            _icon: function () {
                var that = this, element = that.element, icon;
                icon = element.next('span.k-select');
                if (!icon[0]) {
                    icon = $('<span unselectable="on" class="k-select" aria-label="select"><span class="k-icon k-i-calendar"></span></span>').insertAfter(element);
                }
                that._dateIcon = icon.attr({
                    'role': 'button',
                    'aria-controls': that.dateView._dateViewID
                });
            },
            _option: function (option, value) {
                var that = this, options = that.options;
                if (value === undefined) {
                    return options[option];
                }
                value = parse(value, options.parseFormats, options.culture);
                if (!value) {
                    return;
                }
                options[option] = new DATE(+value);
                that.dateView[option](value);
            },
            _update: function (value) {
                var that = this, options = that.options, min = options.min, max = options.max, current = that._value, date = parse(value, options.parseFormats, options.culture), isSameType = date === null && current === null || date instanceof Date && current instanceof Date, formattedValue;
                if (options.disableDates(date)) {
                    date = null;
                    if (!that._old && !that.element.val()) {
                        value = null;
                    }
                }
                if (+date === +current && isSameType) {
                    formattedValue = kendo.toString(date, options.format, options.culture);
                    if (formattedValue !== value) {
                        that.element.val(date === null ? value : formattedValue);
                    }
                    return date;
                }
                if (date !== null && isEqualDatePart(date, min)) {
                    date = restrictValue(date, min, max);
                } else if (!isInRange(date, min, max)) {
                    date = null;
                }
                that._value = date;
                that.dateView.value(date);
                if (that._dateInput && date) {
                    that._dateInput.value(date || value);
                } else {
                    that.element.val(kendo.toString(date || value, options.format, options.culture));
                }
                that._updateARIA(date);
                return date;
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper;
                wrapper = element.parents('.k-datepicker');
                if (!wrapper[0]) {
                    wrapper = element.wrap(SPAN).parent().addClass('k-picker-wrap k-state-default');
                    wrapper = wrapper.wrap(SPAN).parent();
                }
                wrapper[0].style.cssText = element[0].style.cssText;
                element.css({
                    width: '100%',
                    height: element[0].style.height
                });
                that.wrapper = wrapper.addClass('k-widget k-datepicker').addClass(element[0].className);
                that._inputWrapper = $(wrapper[0].firstChild);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        that.value(element[0].defaultValue);
                        that.max(that._initialOptions.max);
                        that.min(that._initialOptions.min);
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            },
            _template: function () {
                this._ariaTemplate = template(this.options.ARIATemplate);
            },
            _createDateInput: function (options) {
                if (this._dateInput) {
                    this._dateInput.destroy();
                    this._dateInput = null;
                }
                if (options.dateInput) {
                    this._dateInput = new ui.DateInput(this.element, {
                        culture: options.culture,
                        format: options.format,
                        min: options.min,
                        max: options.max
                    });
                }
            },
            _updateARIA: function (date) {
                var cell;
                var that = this;
                var calendar = that.dateView.calendar;
                if (that.element && that.element.length) {
                    that.element[0].removeAttribute('aria-activedescendant');
                }
                if (calendar) {
                    cell = calendar._cell;
                    cell.attr('aria-label', that._ariaTemplate({ current: date || calendar.current() }));
                    that.element.attr('aria-activedescendant', cell.attr('id'));
                }
            }
        });
        ui.plugin(DatePicker);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.drawer', ['kendo.userevents'], f);
}(function () {
    var __meta__ = {
        id: 'drawer',
        name: 'Drawer',
        category: 'web',
        description: 'The Kendo Drawer widget provides slide to reveal sidebar',
        depends: ['userevents']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, SHOW = 'show', HIDE = 'hide', ITEMCLICK = 'itemClick', PUSH = 'push', OVERLAY = 'overlay', LEFT = 'left', RIGHT = 'right';
        var Drawer = kendo.ui.Widget.extend({
            init: function (element, options) {
                var that = this;
                var userEvents;
                Widget.fn.init.call(this, element, options);
                options = that.options;
                that._element(element);
                that._wrapper(element);
                that.position();
                that._mode();
                if (options.mini) {
                    that._miniMode();
                }
                that._initDrawerItems();
                if (options.mini && options.mode == 'overlay') {
                    that._setBodyOffset();
                }
                userEvents = this.userEvents = new kendo.UserEvents(options.mode == OVERLAY ? $(document.body) : this.outerWrapper, {
                    fastTap: true,
                    allowSelection: true
                });
                var tap = function (e) {
                    if ($.contains(that.drawerItemsWrapper[0], e.event.target)) {
                        that._itemClick(e);
                    }
                    if (that.visible && !that.trigger('hide', { sender: this })) {
                        that.hide();
                        e.preventDefault();
                    }
                };
                if (this.options.swipeToOpen) {
                    userEvents.bind('start', function (e) {
                        that._start(e);
                    });
                    userEvents.bind('move', function (e) {
                        that._update(e);
                    });
                    userEvents.bind('end', function (e) {
                        that._end(e);
                    });
                    userEvents.bind('tap', tap);
                } else {
                    userEvents.bind('press', tap);
                }
                if (options.minHeight) {
                    that.outerWrapper.css('min-height', options.minHeight);
                }
            },
            _element: function () {
                var that = this;
                var element = that.element;
                var options = that.options;
                var contentElement = that.contentElement = element.children().first();
                that.drawerElement = $(options.template);
                contentElement.addClass('k-drawer-content');
                element.addClass('k-drawer k-widget');
            },
            _wrapper: function () {
                var options = this.options;
                var drawerElement = this.drawerElement;
                var element = this.element;
                var contentElement = this.contentElement;
                var drawerItemsWrapper = this.drawerItemsWrapper = drawerElement.wrap('<div class=\'k-drawer-items\'></div>').parent();
                var drawerContainer = this.drawerContainer = drawerItemsWrapper.wrap('<div class=\'k-drawer-container\'></div>').parent();
                var outerWrapper = this.outerWrapper = drawerContainer.wrap('<div class=\'k-drawer-wrapper\'></div>').parent();
                if (options.mode == OVERLAY) {
                    $(document.body).prepend(outerWrapper);
                } else {
                    outerWrapper.append(contentElement);
                    element.prepend(outerWrapper);
                }
            },
            _setBodyOffset: function () {
                var overlayMiniOffset = this.drawerContainer.outerWidth();
                if (this.leftPositioned) {
                    $(document.body).css('padding-left', overlayMiniOffset);
                } else {
                    $(document.body).css('padding-right', overlayMiniOffset);
                }
            },
            _initDrawerItems: function () {
                var drawerItemsWrapper = this.drawerItemsWrapper;
                var drawerItems = drawerItemsWrapper.find('[data-role=\'drawer-item\']');
                var separatorItems = drawerItemsWrapper.find('[data-role=\'drawer-separator\']');
                drawerItems.addClass('k-drawer-item');
                separatorItems.addClass('k-drawer-item k-drawer-separator');
                if (this._selectedItemIndex >= 0) {
                    drawerItems.removeClass('k-state-selected');
                    drawerItems.eq(this._selectedItemIndex).addClass('k-state-selected');
                }
            },
            _mode: function () {
                var options = this.options;
                var outerWrapper = this.outerWrapper;
                var overlayContainer;
                if (options.mode == PUSH) {
                    outerWrapper.addClass('k-drawer-' + PUSH);
                } else {
                    outerWrapper.addClass('k-drawer-' + OVERLAY);
                    overlayContainer = this.overlayContainer = $('<div class="k-overlay"></div>');
                    outerWrapper.prepend(overlayContainer);
                }
            },
            _miniMode: function () {
                var options = this.options;
                var outerWrapper = this.outerWrapper;
                var miniWidth = options.mini.width;
                var miniTemplate = this._miniTemplate = options.mini.template && $(options.mini.template);
                var drawerItemsWrapper = this.drawerItemsWrapper;
                outerWrapper.addClass('k-drawer-mini-mode');
                if (miniTemplate) {
                    drawerItemsWrapper.html(miniTemplate);
                }
                if (miniWidth) {
                    drawerItemsWrapper.width(miniWidth);
                }
                this.minWidth = options.mini.width || this.drawerContainer.width();
            },
            show: function () {
                var drawerContainer = this.drawerContainer;
                var options = this.options;
                var isExpanded = drawerContainer.hasClass('k-drawer-expanded');
                var miniTemplate = this._miniTemplate;
                var drawerElement = this.drawerElement;
                var drawerItemsWrapper = this.drawerItemsWrapper;
                if (!isExpanded) {
                    drawerContainer.addClass('k-drawer-expanded');
                    this.visible = true;
                }
                if (miniTemplate) {
                    drawerItemsWrapper.html(drawerElement);
                    this._initDrawerItems();
                    this._selectItem();
                }
                if (options.mini) {
                    drawerItemsWrapper.width(options.width);
                } else {
                    drawerContainer.width(options.width);
                }
                if (options.mode == 'overlay') {
                    this.overlayContainer.show();
                    this.visible = true;
                }
            },
            hide: function () {
                var that = this;
                var drawerContainer = that.drawerContainer;
                var options = this.options;
                var drawerItemsWrapper = this.drawerItemsWrapper;
                var miniTemplate = this._miniTemplate;
                var miniWidth = options.mini && options.mini.width;
                if (this._miniTemplate) {
                    drawerItemsWrapper.html(miniTemplate);
                    that._initDrawerItems();
                    this._selectItem();
                }
                if (options.mini) {
                    if (miniWidth) {
                        drawerItemsWrapper.width(miniWidth);
                    } else {
                        drawerItemsWrapper.width('');
                    }
                } else {
                    drawerContainer.width('');
                }
                if (this.visible) {
                    drawerContainer.removeClass('k-drawer-expanded');
                    this.visible = false;
                }
                if (options.mode == 'overlay') {
                    this.overlayContainer.hide();
                }
            },
            position: function (value) {
                var options = this.options;
                var outerWrapper = this.outerWrapper;
                var position = value || options.position;
                if (position == RIGHT) {
                    outerWrapper.removeClass('k-drawer-' + LEFT);
                    outerWrapper.addClass('k-drawer-' + RIGHT);
                } else {
                    outerWrapper.removeClass('k-drawer-' + RIGHT);
                    outerWrapper.addClass('k-drawer-' + LEFT);
                }
                this.leftPositioned = position === LEFT;
            },
            _start: function (e) {
                var that = this;
                var options = this.options;
                var drawerContainer = this.drawerContainer;
                var drawerItemsWrapper = this.drawerItemsWrapper;
                var userEvents = e.sender;
                if (Math.abs(e.x.velocity) < Math.abs(e.y.velocity) || kendo.triggeredByInput(e.event)) {
                    userEvents.cancel();
                    return;
                }
                if (this.drawerMini) {
                    drawerItemsWrapper.html(that.drawerElement);
                }
                if (options.mini) {
                    drawerItemsWrapper.css('transition', 'none');
                } else {
                    drawerContainer.css('transition', 'none');
                }
                if (options.mode == 'overlay') {
                    this.overlayContainer.show();
                }
            },
            _update: function (e) {
                var options = this.options;
                var mode = options.mode;
                if (mode == 'overlay') {
                    this._overlay(e);
                } else {
                    this._push(e);
                }
            },
            _end: function (e) {
                var velocity = e.x.velocity;
                var options = this.options;
                var drawerContainer = this.drawerContainer;
                var drawerItemsWrapper = this.drawerItemsWrapper;
                var elementWidth = drawerItemsWrapper.width();
                var pastHalf = elementWidth > options.width / 2;
                var velocityThreshold = 0.8;
                var shouldShow;
                if (options.mini) {
                    drawerItemsWrapper.css('transition', 'all .3s ease-out');
                } else {
                    drawerContainer.css('transition', 'all .3s ease-out');
                }
                if (this.leftPositioned) {
                    shouldShow = velocity > -velocityThreshold && (velocity > velocityThreshold || pastHalf);
                } else {
                    shouldShow = velocity < velocityThreshold && (velocity < -velocityThreshold || pastHalf);
                }
                if (shouldShow) {
                    if (this.trigger('show', { sender: this })) {
                        e.preventDefault();
                        this.hide();
                    } else {
                        this.show();
                    }
                } else {
                    if (this.trigger('hide', { sender: this })) {
                        e.preventDefault();
                        this.show();
                    } else {
                        this.hide();
                    }
                }
            },
            _overlay: function (moveEventArgs) {
                var drawerContainer = this.drawerContainer;
                var drawerItemsWrapper = this.drawerItemsWrapper;
                var elementWidth = drawerItemsWrapper.width();
                var options = this.options;
                var minWidth = options.mini && options.mini.width || this.minWidth || 0;
                var limitedPosition;
                var updatedPosition;
                updatedPosition = elementWidth + (this.leftPositioned ? moveEventArgs.x.delta : -moveEventArgs.x.delta);
                limitedPosition = Math.min(Math.max(updatedPosition, minWidth), options.width);
                moveEventArgs.event.preventDefault();
                moveEventArgs.event.stopPropagation();
                if (options.mini) {
                    drawerItemsWrapper.width(limitedPosition);
                } else {
                    drawerContainer.width(limitedPosition);
                }
            },
            _push: function (moveEventArgs) {
                var drawerContainer = this.drawerContainer;
                var drawerItemsWrapper = this.drawerItemsWrapper;
                var elementWidth = drawerItemsWrapper.width();
                var options = this.options;
                var minWidth = options.mini && options.mini.width || this.minWidth || 0;
                var limitedPosition;
                var updatedPosition;
                updatedPosition = elementWidth + (this.leftPositioned ? moveEventArgs.x.delta : -moveEventArgs.x.delta);
                limitedPosition = Math.min(Math.max(updatedPosition, minWidth), options.width);
                moveEventArgs.event.preventDefault();
                moveEventArgs.event.stopPropagation();
                if (options.mini) {
                    drawerItemsWrapper.width(limitedPosition);
                } else {
                    drawerContainer.width(limitedPosition);
                }
            },
            _selectItem: function (item) {
                var selectedItemIndex;
                if (item) {
                    item.addClass('k-state-selected');
                    this.trigger('itemClick', {
                        item: item,
                        sender: this
                    });
                    this._selectedItemIndex = item.index();
                    return;
                }
                selectedItemIndex = this._selectedItemIndex;
                if (selectedItemIndex) {
                    this.drawerItemsWrapper.find('[data-role=\'drawer-item\']').eq(selectedItemIndex).addClass('k-state-selected');
                }
            },
            _itemClick: function (e) {
                var that = this;
                var item;
                if ($(e.event.target).find('.k-drawer-item').length > 0) {
                    item = $(e.event.target).find('.k-drawer-item');
                } else if ($(e.event.target).closest('.k-drawer-item').length > 0) {
                    item = $(e.event.target).closest('.k-drawer-item');
                } else if ($(e.event.target).hasClass('.k-drawer-item')) {
                    item = $(e.event.target);
                }
                that.drawerItemsWrapper.find('.k-drawer-item').removeClass('k-state-selected');
                that._selectItem(item);
            },
            destroy: function () {
                var options = this.options;
                if (options.mode == 'overlay') {
                    if (this.leftPositioned) {
                        $(document.body).css('padding-left', 0);
                    } else {
                        $(document.body).css('padding-right', 0);
                    }
                }
                Widget.fn.destroy.call(this);
                this.userEvents.destroy();
                kendo.destroy(this.element);
                this.element = this.drawerContainer = this.drawerElement = this.drawerItemsWrapper = this._miniTemplate = null;
            },
            options: {
                name: 'Drawer',
                position: LEFT,
                mode: 'overlay',
                swipeToOpen: true,
                width: 280,
                mini: false,
                template: ''
            },
            events: [
                HIDE,
                SHOW,
                ITEMCLICK
            ]
        });
        kendo.ui.plugin(Drawer);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.multiviewcalendar', [
        'kendo.core',
        'kendo.selectable',
        'kendo.calendar'
    ], f);
}(function () {
    var __meta__ = {
        id: 'multiviewcalendar',
        name: 'MultiViewCalendar',
        category: 'web',
        description: 'Multi-view calendar.',
        depends: [
            'core',
            'selectable',
            'calendar'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, calendar = kendo.calendar, support = kendo.support, isInRange = calendar.isInRange, toDateObject = calendar.toDateObject, createDate = calendar.createDate, isEqualDate = calendar.isEqualDate, getToday = calendar.getToday, keys = kendo.keys, ui = kendo.ui, Widget = ui.Widget, Selectable = ui.Selectable, template = kendo.template, mobileOS = support.mobileOS, ns = '.kendoMultiViewCalendar', CLICK = 'click', KEYDOWN = 'keydown', ID = 'id', MIN = 'min', MONTH = 'month', DOT = '.', CENTURY = 'century', DECADE = 'decade', CHANGE = 'change', NAVIGATE = 'navigate', VALUE = 'value', FOCUSED = 'k-state-focused', SELECTED = 'k-state-selected', MID = 'k-range-mid', SPLITEND = 'k-range-split-end', SPLITSTART = 'k-range-split-start', START = 'k-range-start', END = 'k-range-end', HOVER = 'k-state-hover', DISABLED = 'k-state-disabled', TODAY = 'k-nav-today', OTHERMONTH = 'k-other-month', OUTOFRANGE = 'k-out-of-range', CELLSELECTOR = 'td:has(.k-link):not(.' + OUTOFRANGE + ')', CELLSELECTORVALID = 'td:has(.k-link):not(.' + DISABLED + '):not(.' + OUTOFRANGE + ')', BLUR = 'blur', FOCUS = 'focus', MOUSEENTER = support.touch ? 'touchstart' : 'mouseenter', MOUSELEAVE_NS = support.touch ? 'touchend' + ns + ' touchmove' + ns : 'mouseleave' + ns, PREVARROW = '_prevArrow', NEXTARROW = '_nextArrow', ARIA_SELECTED = 'aria-selected', INPUTSELECTOR = 'input,a,textarea,.k-multiselect-wrap,select,button,.k-button>span,.k-button>img,span.k-icon.k-i-arrow-60-down,span.k-icon.k-i-arrow-60-up', ARIA_DISABLED = 'aria-disabled', ARIA_LABEL = 'aria-label', proxy = $.proxy, DATE = Date, views = {
                month: 0,
                year: 1,
                decade: 2,
                century: 3
            };
        var RangeSelectable = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.userEvents = new kendo.UserEvents(that.element, {
                    global: true,
                    allowSelection: true,
                    filter: that.options.filter,
                    tap: proxy(that._tap, that),
                    touchAction: 'none'
                });
            },
            events: [CHANGE],
            options: {
                name: 'RangeSelectable',
                filter: '>*',
                inputSelectors: INPUTSELECTOR,
                multiple: false,
                dragToSelect: true,
                relatedTarget: $.noop
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.userEvents.destroy();
                that._lastActive = that.element = that.userEvents = that._start = that._end = null;
            },
            _allowSelection: function (target) {
                if ($(target).is(this.options.inputSelectors)) {
                    this.userEvents.cancel();
                    return false;
                }
                return true;
            },
            start: function (element) {
                if (element === undefined) {
                    return this._start;
                }
                element.addClass(START + ' ' + SELECTED);
                this._start = element;
            },
            end: function (element) {
                if (element === undefined) {
                    return this._start;
                }
                element.addClass(END + ' ' + SELECTED);
                this._end = element;
            },
            mid: function (elements) {
                var tables = this.element.find('table.k-month');
                elements.addClass(MID);
                tables.each(function () {
                    var that = $(this);
                    var lastCell = that.find(CELLSELECTORVALID + ':last');
                    var firstCell = that.find(CELLSELECTORVALID + ':first');
                    if (lastCell.hasClass(MID)) {
                        lastCell.addClass(SPLITEND);
                    }
                    if (firstCell.hasClass(MID)) {
                        firstCell.addClass(SPLITSTART);
                    }
                });
            },
            clear: function (clearVariables) {
                this.element.find(CELLSELECTOR).removeClass(END + ' ' + SELECTED + ' ' + START + ' ' + MID + ' ' + SPLITEND + ' ' + SPLITSTART);
                if (clearVariables) {
                    this._start = this._end = null;
                }
            },
            selectFrom: function (start) {
                var that = this;
                var items;
                var startIdx;
                items = that.element.find(CELLSELECTOR);
                startIdx = $.inArray($(start)[0], items);
                that.clear();
                that.start(start);
                items = items.filter(function (index) {
                    return index > startIdx;
                });
                that.mid(items);
            },
            selectTo: function (end) {
                var that = this;
                var items;
                var endIdx;
                items = that.element.find(CELLSELECTOR);
                endIdx = $.inArray($(end)[0], items);
                that.clear();
                items = items.filter(function (index) {
                    return index < endIdx;
                });
                that.mid(items);
                that.end($(end));
            },
            range: function (start, end) {
                var that = this;
                var items;
                var startIdx;
                var endIdx;
                var temp;
                if (start === undefined) {
                    return {
                        start: that._start,
                        end: that._end
                    };
                }
                items = that.element.find(CELLSELECTOR);
                startIdx = $.inArray($(start)[0], items);
                endIdx = $.inArray($(end)[0], items);
                if (startIdx > endIdx) {
                    temp = end;
                    end = start;
                    start = temp;
                    temp = startIdx;
                    startIdx = endIdx;
                    endIdx = temp;
                }
                that.clear();
                start.addClass(START + ' ' + SELECTED);
                that._start = start;
                items = items.filter(function (index) {
                    return index > startIdx && index < endIdx;
                });
                that.mid(items);
                that.end($(end));
            },
            change: function () {
                this.trigger(CHANGE);
            },
            _tap: function (e) {
                var target = $(e.target), that = this, items, startIdx, endIdx;
                that._lastActive = target;
                if (!that._start) {
                    that.start(target);
                    that.trigger(CHANGE);
                    return;
                }
                if (that._start && !that._end) {
                    items = that.element.find(CELLSELECTOR);
                    startIdx = $.inArray($(that._start)[0], items);
                    endIdx = $.inArray($(target)[0], items);
                    if (+toDateObject($(that._start).find('a')) > +toDateObject($(target).find('a'))) {
                        that.clear();
                        that.start(target);
                        that.trigger(CHANGE);
                        return;
                    }
                    items = items.filter(function (index) {
                        return index > startIdx && index < endIdx;
                    });
                    that.mid(items);
                    that.end($(target));
                    that.trigger(CHANGE);
                    return;
                }
                if (that._start && that._end) {
                    if (target.hasClass(MID)) {
                        if (!that._toggling) {
                            that.range(target, that._end);
                        } else {
                            that.range(that._start, target);
                        }
                        that._toggling = !that._toggling;
                        that.trigger(CHANGE);
                        return;
                    }
                    that._toggling = false;
                    that._end = null;
                    that.clear();
                    that.start(target);
                    that.trigger(CHANGE);
                }
            }
        });
        var MultiViewCalendar = Widget.extend({
            init: function (element, options) {
                var that = this;
                var id;
                var culture;
                Widget.fn.init.call(that, element, options);
                element = that.wrapper = that.element;
                options = that.options;
                that.options.disableDates = calendar.disabled(that.options.disableDates);
                culture = kendo.getCulture(options.culture);
                options.format = kendo._extractFormat(options.format || culture.calendars.standard.patterns.d);
                that._templates();
                that._header();
                that._wrapper();
                id = element.addClass('k-widget k-calendar k-calendar-range' + (options.weekNumber ? ' k-week-number' : '')).on(KEYDOWN + ns, 'table.k-content', proxy(that._move, that)).on(BLUR + ns, 'table', proxy(that._blur, that)).on(CLICK + ns, CELLSELECTORVALID, function (e) {
                    var link = e.currentTarget.firstChild;
                    if (link.href.indexOf('#') != -1) {
                        e.preventDefault();
                    }
                    that._click($(link));
                }).on(MOUSEENTER + ns, CELLSELECTORVALID, proxy(that._mouseEnter, that)).on(MOUSELEAVE_NS, CELLSELECTORVALID, function () {
                    $(this).removeClass(HOVER);
                }).attr(ID);
                if (id) {
                    that._cellID = id + '_cell_selected';
                }
                that._calendarWidth = that.element.width();
                that._range = options.range;
                that._initViews({
                    viewName: options.start,
                    value: options.value
                });
                that._selectable();
                that._footer(that.footer);
                that._selectDates = [];
                that.value(options.value);
                if (options.selectable == 'multiple') {
                    that._selectDates = options.selectDates.length ? options.selectDates : that._selectDates;
                    that._restoreSelection();
                }
                if (options.selectable == 'range') {
                    that.selectRange(that._range);
                }
                kendo.notify(that);
            },
            options: {
                name: 'MultiViewCalendar',
                value: null,
                min: new DATE(1900, 0, 1),
                max: new DATE(2099, 11, 31),
                dates: [],
                disableDates: null,
                culture: '',
                footer: '',
                format: '',
                month: {},
                range: {
                    start: null,
                    end: null
                },
                weekNumber: false,
                views: 2,
                showViewHeader: false,
                selectable: 'single',
                selectDates: [],
                start: MONTH,
                depth: MONTH,
                messages: { weekColumnHeader: '' }
            },
            events: [
                CHANGE,
                NAVIGATE
            ],
            setOptions: function (options) {
                var that = this;
                calendar.normalize(options);
                options.disableDates = calendar.disabled(options.disableDates);
                Widget.fn.setOptions.call(that, options);
                that._selectable();
                that._templates();
                that._footer(that.footer);
                for (var i = 0; i < that._views.length; i++) {
                    that._views[i].off(ns).remove();
                }
                that._initViews({
                    viewName: options.start,
                    value: options.value
                });
                that._range = options.range || {
                    start: null,
                    end: null
                };
                that._restoreSelection();
            },
            destroy: function () {
                var that = this;
                that._cell = null;
                that._currentView = null;
                that._current = null;
                if (that._views) {
                    for (var i = 0; i < that._views.length; i++) {
                        that._views[i].off(ns).remove();
                    }
                }
                that.element.off(ns);
                if (that.header) {
                    that.header.off(ns);
                    that._title = null;
                    that.header = null;
                }
                if (that.selectable) {
                    that.selectable.destroy();
                    that.selectable = null;
                }
                if (that.rangeSelectable) {
                    that.rangeSelectable.destroy();
                    that.rangeSelectable = null;
                }
                if (that._today) {
                    kendo.destroy(that._today.off(ns));
                }
                that._views = null;
                Widget.fn.destroy.call(that);
            },
            current: function () {
                return this._current;
            },
            focus: function () {
                var table;
                if (this._cell) {
                    this._cell.closest('table').trigger('focus');
                } else if (this._current && this._dateInViews(this._current)) {
                    this._cell = this._cellByDate(this._current);
                    this._cell.closest('table').trigger('focus');
                } else {
                    table = this.element.find('table').first().trigger('focus');
                    this._cell = table.find(CELLSELECTORVALID + ':first');
                    this._current = toDateObject(this._cell.find('a'));
                }
                this._cell.addClass(FOCUSED);
            },
            min: function (value) {
                return this._option(MIN, value);
            },
            max: function (value) {
                return this._option('max', value);
            },
            view: function () {
                return this._currentView;
            },
            navigateToPast: function () {
                this._navigate(PREVARROW, -1);
            },
            navigateToFuture: function () {
                this._navigate(NEXTARROW, 1);
            },
            navigateUp: function () {
                var that = this, index = that._index;
                if (that._title.hasClass(DISABLED)) {
                    return;
                }
                that.navigate(that._current, ++index);
            },
            navigateDown: function (value) {
                var that = this, index = that._index, depth = that.options.depth;
                if (!value) {
                    return;
                }
                if (index === views[depth]) {
                    if (!isEqualDate(that._value, that._current) || !isEqualDate(that._value, value)) {
                        that.value(value);
                        that.trigger(CHANGE);
                    }
                    return;
                }
                that.navigate(value, --index);
            },
            navigate: function (value, view) {
                view = isNaN(view) ? calendar.views[calendar.viewsEnum[view]] : calendar.views[view];
                var that = this;
                var options = that.options;
                var min = options.min;
                var max = options.max;
                if (!value) {
                    that._current = value = new DATE(+calendar.restrictValue(value, min, max));
                } else {
                    that._current = value;
                }
                if (view === undefined) {
                    view = that._currentView;
                }
                that._currentView = view;
                for (var i = 0; i < that._views.length; i++) {
                    that._views[i].off(ns).remove();
                }
                that._initViews({
                    viewName: view.name,
                    value: value
                });
                that._restoreSelection();
            },
            _updateHeader: function () {
                var that = this;
                var view = that._currentView;
                var title = that._title;
                var value = that._firstViewValue;
                var options = that.options;
                var visibleRange = that._visibleRange();
                var culture = options.culture;
                var min = options.min;
                var max = options.max;
                var lastDate;
                var disabled;
                var prevDisabled;
                var nextDisabled;
                if (view.name === DECADE || view.name === CENTURY) {
                    lastDate = shiftDate(value, view.name, options.views - 1);
                    if (!isInRange(lastDate, min, max)) {
                        lastDate = max;
                    }
                    title.html(view.first(value).getFullYear() + ' - ' + view.last(lastDate).getFullYear());
                } else {
                    title.html(view.title(value, min, max, culture) + ' - ' + view.title(shiftDate(value, view.name, options.views - 1), min, max, culture));
                }
                disabled = view.name === CENTURY;
                title.toggleClass(DISABLED, disabled).attr(ARIA_DISABLED, disabled);
                prevDisabled = view.compare(visibleRange.start, that.options.min) < 1;
                nextDisabled = view.compare(visibleRange.end, that.options.max) > -1;
                if (prevDisabled && nextDisabled) {
                    if (that._navContainer) {
                        that._navContainer.remove();
                        that._navContainer = null;
                    }
                } else {
                    if (!that._navContainer) {
                        that._navContainer = $('<span class="k-calendar-nav">' + '<a href="#" role="button" class="k-button k-button-icon k-prev-view" ' + ARIA_LABEL + '="Previous"><span class="k-icon k-i-arrow-60-left"></span></a>' + '<a href="#" role="button" class="k-button k-button-icon k-next-view" ' + ARIA_LABEL + '="Next"><span class="k-icon k-i-arrow-60-right"></span></a>' + '</span>').appendTo(that.header);
                        that[PREVARROW] = that._navContainer.find('.k-prev-view');
                        that[NEXTARROW] = that._navContainer.find('.k-next-view');
                    }
                    that[PREVARROW].toggleClass(DISABLED, prevDisabled).attr(ARIA_DISABLED, prevDisabled);
                    if (that[PREVARROW].hasClass(DISABLED)) {
                        that[PREVARROW].removeClass(HOVER);
                    }
                    that[NEXTARROW].toggleClass(DISABLED, nextDisabled).attr(ARIA_DISABLED, nextDisabled);
                    if (that[NEXTARROW].hasClass(DISABLED)) {
                        that[NEXTARROW].removeClass(HOVER);
                    }
                }
            },
            _mouseEnter: function (e) {
                var that = this;
                var cell = $(e.currentTarget);
                var range;
                var items;
                var startIdx;
                var endIdx;
                cell.addClass(HOVER);
                if (that.rangeSelectable && that._currentView.name === 'month') {
                    range = that.selectRange();
                    if (range.start && !range.end) {
                        if (that._dateInViews(that.selectRange().start)) {
                            items = that.element.find(that.rangeSelectable.options.filter);
                            startIdx = $.inArray($(that.rangeSelectable._start)[0], items);
                            endIdx = $.inArray($(cell)[0], items);
                            if (startIdx > endIdx) {
                                return;
                            }
                            that.rangeSelectable.range(that.rangeSelectable._start, cell);
                        } else if (+toDateObject(that.element.find(CELLSELECTOR + ':first').find('a')) > +range.start) {
                            that.rangeSelectable.selectTo(cell);
                        }
                        that.rangeSelectable._end = null;
                    }
                }
            },
            _move: function (e, preventFocus) {
                var that = this;
                var options = that.options;
                var key = e.keyCode;
                var index = that._index;
                var min = options.min;
                var max = options.max;
                var focusedCell = that.element.find(DOT + FOCUSED);
                var table = focusedCell.closest('table');
                var currentValue = new DATE(+(that._current || toDateObject(focusedCell.find('a'))));
                var isRtl = kendo.support.isRtl(that.wrapper);
                var navigate = false;
                var value, prevent, method, cell, lastActive, cellIndex;
                if (key == keys.RIGHT && !isRtl || key == keys.LEFT && isRtl) {
                    value = 1;
                    prevent = true;
                } else if (key == keys.LEFT && !isRtl || key == keys.RIGHT && isRtl) {
                    value = -1;
                    prevent = true;
                } else if (key == keys.UP) {
                    value = index === 0 ? -7 : -4;
                    prevent = true;
                } else if (key == keys.DOWN) {
                    value = index === 0 ? 7 : 4;
                    prevent = true;
                } else if (key == keys.SPACEBAR) {
                    value = 0;
                    prevent = true;
                } else if (key == keys.HOME) {
                    prevent = true;
                    cell = table.find(CELLSELECTORVALID).eq(0);
                    if (cell.hasClass(FOCUSED)) {
                        table = table.prev();
                        if (table.length) {
                            that._focusCell(table.find(CELLSELECTORVALID).eq(0));
                        } else {
                            navigate = that[PREVARROW] && !that[PREVARROW].hasClass(DISABLED);
                            that._navigate(PREVARROW, -1, preventFocus);
                            that._focusCell(that.element.find('table:first ' + CELLSELECTORVALID + ':first'));
                        }
                    } else {
                        that._focusCell(cell);
                    }
                } else if (key == keys.END) {
                    prevent = true;
                    cell = table.find(CELLSELECTORVALID).last();
                    if (cell.hasClass(FOCUSED)) {
                        table = table.next();
                        if (table.length) {
                            that._focusCell(table.find(CELLSELECTORVALID).last());
                        } else {
                            navigate = that[NEXTARROW] && !that[NEXTARROW].hasClass(DISABLED);
                            that._navigate(NEXTARROW, 1, preventFocus);
                            that._focusCell(that.element.find('table:last ' + CELLSELECTORVALID + ':last'));
                        }
                    } else {
                        that._focusCell(cell);
                    }
                }
                if (e.ctrlKey || e.metaKey) {
                    if (key == keys.RIGHT && !isRtl || key == keys.LEFT && isRtl) {
                        navigate = that[NEXTARROW] && !that[NEXTARROW].hasClass(DISABLED);
                        that._navigate(NEXTARROW, 1, preventFocus);
                        prevent = true;
                    } else if (key == keys.LEFT && !isRtl || key == keys.RIGHT && isRtl) {
                        navigate = that[PREVARROW] && !that[PREVARROW].hasClass(DISABLED);
                        that._navigate(PREVARROW, -1, preventFocus);
                        prevent = true;
                    } else if (key == keys.UP) {
                        navigate = !that._title.hasClass(DISABLED);
                        that.navigateUp();
                        that._focusCell(that._cellByDate(that._current), !preventFocus);
                        prevent = true;
                    } else if (key == keys.DOWN) {
                        if (that._currentView.name === 'month') {
                            that.value(currentValue);
                        } else {
                            that.navigateDown(currentValue);
                            that._focusCell(that._cellByDate(that._current), !preventFocus);
                            navigate = true;
                        }
                        prevent = true;
                    } else if (key == keys.ENTER || key == keys.SPACEBAR) {
                        if (options.selectable === 'multiple') {
                            that._toggleSelection(e);
                        }
                    }
                } else if (e.shiftKey && options.selectable !== 'single') {
                    if (value !== undefined || method) {
                        if (!method) {
                            that._currentView.setDate(currentValue, value);
                        }
                        if (that._currentView.name !== 'month') {
                            return;
                        }
                        if (options.disableDates(currentValue)) {
                            currentValue = that._nextNavigatable(currentValue, value);
                        }
                        min = createDate(min.getFullYear(), min.getMonth(), min.getDate());
                        if (isInRange(currentValue, min, max)) {
                            if (!that._dateInViews(currentValue)) {
                                if (value > 0) {
                                    navigate = that[NEXTARROW] && !that[NEXTARROW].hasClass(DISABLED);
                                    that._navigate(NEXTARROW, 1, preventFocus);
                                } else {
                                    navigate = that[PREVARROW] && !that[PREVARROW].hasClass(DISABLED);
                                    that._navigate(PREVARROW, -1, preventFocus);
                                }
                            }
                            cell = that._cellByDate(currentValue);
                            that._current = currentValue;
                            if (that.selectable) {
                                that._selectRange(toDateObject((that.selectable._lastActive || focusedCell).find('a')), currentValue);
                                if (!that.selectable._lastActive) {
                                    that.selectable._lastActive = focusedCell;
                                }
                                that.trigger(CHANGE);
                                that._focusCell(cell);
                            }
                            if (that.rangeSelectable) {
                                lastActive = toDateObject((that.rangeSelectable._lastActive || focusedCell).find('a'));
                                if (!that._dateInViews(lastActive)) {
                                    if (+lastActive > +currentValue) {
                                        that.rangeSelectable._end = that.rangeSelectable._lastActive;
                                        that.rangeSelectable.selectFrom(cell);
                                    } else {
                                        that.rangeSelectable.selectTo(cell);
                                    }
                                } else {
                                    if (that.rangeSelectable._end && that.rangeSelectable._end.is(DOT + FOCUSED)) {
                                        that.rangeSelectable._lastActive = that.rangeSelectable._start;
                                    } else {
                                        that.rangeSelectable._lastActive = that._cellByDate(lastActive);
                                    }
                                    that.rangeSelectable.range(that.rangeSelectable._lastActive, cell);
                                }
                                that.rangeSelectable.change();
                                that._focusCell(cell);
                            }
                        }
                    }
                } else {
                    if (key == keys.ENTER || key == keys.SPACEBAR) {
                        if (that._currentView.name === 'month') {
                            if (that.selectable) {
                                that.selectable._lastActive = that._cellByDate(currentValue);
                            }
                            that.value(currentValue);
                            if (that.rangeSelectable) {
                                that.rangeSelectable.change();
                            }
                        } else {
                            that._click($(that._cell[0].firstChild), preventFocus);
                        }
                        prevent = true;
                    } else if (key == keys.PAGEUP || key == keys.PAGEDOWN) {
                        prevent = true;
                        cellIndex = table.find(CELLSELECTORVALID).index(focusedCell);
                        table = key == keys.PAGEUP ? table.prev() : table.next();
                        if (!table.length) {
                            if (key == keys.PAGEUP) {
                                navigate = that[PREVARROW] && !that[PREVARROW].hasClass(DISABLED);
                                that.navigateToPast();
                                table = that.element.find('table:first');
                            } else {
                                navigate = that[NEXTARROW] && !that[NEXTARROW].hasClass(DISABLED);
                                that.navigateToFuture();
                                table = that.element.find('table:last');
                            }
                        }
                        cell = table.find(CELLSELECTORVALID).eq(cellIndex);
                        if (cell.length) {
                            that._focusCell(cell);
                        } else {
                            that._focusCell(table.find(CELLSELECTORVALID).last());
                        }
                    }
                    if (value || method) {
                        if (!method) {
                            that._currentView.setDate(currentValue, value);
                        }
                        min = createDate(min.getFullYear(), min.getMonth(), min.getDate());
                        if (isInRange(currentValue, min, max)) {
                            if (that.selectable && options.disableDates(currentValue)) {
                                currentValue = that._nextNavigatable(currentValue, value);
                            }
                            if (!that._dateInViews(currentValue)) {
                                if (value > 0) {
                                    navigate = that[NEXTARROW] && !that[NEXTARROW].hasClass(DISABLED);
                                    that._navigate(NEXTARROW, 1, preventFocus);
                                } else {
                                    navigate = that[PREVARROW] && !that[PREVARROW].hasClass(DISABLED);
                                    that._navigate(NEXTARROW, -1, preventFocus);
                                }
                            }
                            cell = that._cellByDate(currentValue);
                            that._current = currentValue;
                            that._focusCell(cell, !preventFocus);
                        }
                    }
                }
                if (navigate) {
                    that.trigger(NAVIGATE);
                }
                if (prevent) {
                    e.preventDefault();
                }
                return that._current;
            },
            _visualizeSelectedDatesInView: function () {
                var that = this;
                var selectedDates = {};
                var cells;
                $.each(that._selectDates, function (index, value) {
                    selectedDates[kendo.calendar.views[0].toDateString(value)] = value;
                });
                that.selectable.clear();
                cells = that.element.find('table').find(CELLSELECTOR).filter(function (index, element) {
                    return selectedDates[$(element.firstChild).attr(kendo.attr(VALUE))];
                });
                if (cells.length > 0) {
                    that.selectable._selectElement(cells, true);
                }
            },
            _nextNavigatable: function (currentValue, value) {
                var that = this;
                var disabled = true;
                var view = that._currentView;
                var min = that.options.min;
                var max = that.options.max;
                var isDisabled = that.options.disableDates;
                var navigatableDate = new Date(currentValue.getTime());
                view.setDate(navigatableDate, -value);
                while (disabled) {
                    view.setDate(currentValue, value);
                    if (!isInRange(currentValue, min, max)) {
                        currentValue = navigatableDate;
                        break;
                    }
                    disabled = isDisabled(currentValue);
                }
                return currentValue;
            },
            _toggleSelection: function (event) {
                var that = this;
                that.selectable._lastActive = $(that._cell[0]);
                if ($(that._cell[0]).hasClass(SELECTED)) {
                    that.selectable._unselect($(that._cell[0]));
                    that.selectable.trigger(CHANGE, { event: event });
                } else {
                    that.selectable.value($(that._cell[0]), { event: event });
                }
            },
            _option: function (option, value) {
                var that = this;
                var options = that.options;
                var currentValue = that._value || that._current;
                var isBigger;
                if (value === undefined) {
                    return options[option];
                }
                value = kendo.parseDate(value, options.format, options.culture);
                if (!value) {
                    return;
                }
                options[option] = new DATE(+value);
                if (option === MIN) {
                    isBigger = value > currentValue;
                } else {
                    isBigger = currentValue > value;
                }
                if (isBigger) {
                    that._value = null;
                }
                that.navigate(that._value);
                that._toggle();
            },
            _cellByDate: function (value) {
                if (value instanceof Date) {
                    value = this._currentView.toDateString(value);
                }
                return this.element.find('table').find('td:not(.' + OTHERMONTH + ')').filter(function () {
                    return $(this.firstChild).attr(kendo.attr(VALUE)) === value;
                });
            },
            _selectable: function () {
                var that = this;
                var selectable = that.options.selectable;
                if (that.selectable) {
                    that.selectable.destroy();
                    that.selectable = null;
                }
                if (that.rangeSelectable) {
                    that.rangeSelectable.destroy();
                    that.rangeSelectable = null;
                }
                if (selectable.toLowerCase() === 'range') {
                    that.rangeSelectable = new RangeSelectable(that.wrapper, {
                        filter: 'table.k-month ' + CELLSELECTORVALID,
                        change: proxy(that._rangeSelection, that)
                    });
                } else {
                    that.selectable = new Selectable(that.wrapper, {
                        aria: true,
                        dragToSelect: false,
                        inputSelectors: 'input,textarea,.k-multiselect-wrap,select,button,.k-button>span,.k-button>img,span.k-icon.k-i-arrow-60-down,span.k-icon.k-i-arrow-60-up',
                        multiple: Selectable.parseOptions(selectable).multiple,
                        filter: 'table.k-content ' + CELLSELECTORVALID,
                        change: proxy(that._selection, that),
                        relatedTarget: proxy(that._onRelatedTarget, that),
                        unselect: proxy(that._unselecting, that)
                    });
                }
            },
            _onRelatedTarget: function (target) {
                var that = this;
                if (that.selectable.options.multiple && target.is(CELLSELECTORVALID) && target.length > 1) {
                    that._focusCell(target.first(), true);
                }
            },
            _getFirstViewDate: function (currentView) {
                var that = this;
                var options = that.options;
                var ranges = [];
                var start;
                var end;
                var current = new Date(+that._current);
                var i;
                for (i = 0; i < options.views; i++) {
                    start = currentView.first(current);
                    end = currentView.last(current);
                    if (+end > +options.max) {
                        if (+start <= +options.max) {
                            ranges.push({
                                start: start,
                                end: new Date(+options.max)
                            });
                        }
                        break;
                    }
                    ranges.push({
                        start: start,
                        end: end
                    });
                    current = new Date(+shiftDate(end, currentView.name, 1));
                }
                current = new Date(+that._current);
                for (i = 0; i < options.views; i++) {
                    start = currentView.first(current);
                    end = currentView.last(current);
                    if (+start < +options.min) {
                        if (+end >= +options.min) {
                            ranges.push({
                                start: new Date(+options.min),
                                end: end
                            });
                        }
                        break;
                    }
                    ranges.push({
                        start: start,
                        end: end
                    });
                    current = new Date(+shiftDate(start, currentView.name, -1));
                }
                start = ranges[0].start;
                for (i = 0; i < options.views + 1; i++) {
                    if (!ranges[i]) {
                        break;
                    }
                    if (+start > +ranges[i].start) {
                        start = ranges[i].start;
                    }
                }
                return new Date(+start);
            },
            _canRenderNextView: function (viewDate) {
                var fullYear = viewDate.getFullYear();
                var month = viewDate.getMonth();
                var date = viewDate.getDate();
                var max = this.options.max;
                var maxYear = max.getFullYear();
                var maxMonth = max.getMonth();
                if (fullYear < maxYear) {
                    return true;
                }
                if (fullYear === maxYear && month < maxMonth) {
                    return true;
                }
                if (fullYear === maxYear && month === maxMonth && date < max.getDate()) {
                    return true;
                }
                if (fullYear === maxYear && month === maxMonth && date === max.getDate()) {
                    return true;
                }
                return false;
            },
            _initViews: function (viewOptions) {
                var that = this;
                var options = that.options;
                var index = calendar.viewsEnum[viewOptions.viewName];
                var currentView = calendar.views[index];
                var viewDate;
                that._current = new DATE(+calendar.restrictValue(viewOptions.value, options.min, options.max));
                that._views = [];
                that._index = index;
                viewDate = that._getFirstViewDate(currentView);
                viewDate.setDate(1);
                that._firstViewValue = new Date(+viewDate);
                for (var i = 0; i < options.views; i++) {
                    viewDate = i ? shiftDate(viewDate, currentView.name, 1) : viewDate;
                    viewDate.setDate(1);
                    if (!that._canRenderNextView(viewDate)) {
                        break;
                    }
                    that._table = $(currentView.content($.extend({
                        min: options.min,
                        max: options.max,
                        date: viewDate,
                        url: options.url,
                        dates: options.dates,
                        format: options.format,
                        culture: options.culture,
                        disableDates: options.disableDates,
                        showHeader: options.showViewHeader,
                        isWeekColumnVisible: options.weekNumber,
                        otherMonth: options.otherMonth,
                        messages: options.messages
                    }, that[currentView.name])));
                    that._table.appendTo(that.tablesWrapper).addClass('k-' + currentView.name);
                    that._views.push(that._table);
                }
                that._currentView = currentView;
                that.tablesWrapper.attr('class', 'k-calendar-view k-calendar-' + currentView.name + 'view');
                that._updateHeader();
            },
            _rangeSelection: function (e) {
                var that = this;
                var range = e.sender.range();
                var start;
                var end;
                if (range.start) {
                    start = toDateObject(range.start.find('a'));
                }
                if (range.end) {
                    end = toDateObject(range.end.find('a'));
                }
                that._range = {
                    start: start,
                    end: end
                };
                if (!that._preventChange) {
                    that.trigger(CHANGE);
                }
            },
            _selection: function (e) {
                var that = this;
                var selectElements = e.sender.value();
                var domEvent = e.event;
                var currentTarget = $(domEvent && domEvent.currentTarget);
                var isCell = currentTarget.is('td');
                var currentValue;
                if (that.options.selectable === 'single') {
                    that._validateValue(selectElements[0] ? toDateObject(selectElements.first().find('a')) : e.sender._lastActive ? toDateObject(e.sender._lastActive.find('a')) : that.value());
                }
                if (that.options.selectable == 'multiple') {
                    if (isCell) {
                        currentValue = toDateObject(currentTarget.find('a'));
                    }
                    if (domEvent && domEvent.ctrlKey) {
                        if (isCell) {
                            if (currentTarget.hasClass(SELECTED)) {
                                that._selectDates.push(currentValue);
                            } else {
                                that._deselect(currentValue);
                            }
                        } else {
                            that.element.find('table ' + CELLSELECTORVALID).each(function (index, element) {
                                var value = toDateObject($(element).find('a'));
                                that._deselect(value);
                            });
                            that._addSelectedCellsToArray();
                        }
                    } else if (domEvent && domEvent.shiftKey) {
                        that._selectRange(toDateObject(e.sender._lastActive ? e.sender._lastActive.find('a') : selectElements.first().find('a')), currentValue);
                    } else if (isCell) {
                        that._selectDates = [];
                        that._selectDates.push(currentValue);
                    } else {
                        that._selectDates = [];
                        that._addSelectedCellsToArray();
                    }
                }
                if (!that._preventChange) {
                    that.trigger(CHANGE);
                }
            },
            _addSelectedCellsToArray: function () {
                var that = this;
                that.selectable.value().each(function (index, item) {
                    var date = toDateObject($(item.firstChild));
                    if (!that.options.disableDates(date)) {
                        that._selectDates.push(date);
                    }
                });
            },
            _deselect: function (date) {
                var that = this;
                var currentDateIndex = that._selectDates.map(Number).indexOf(+date);
                if (currentDateIndex != -1) {
                    that._selectDates.splice(currentDateIndex, 1);
                }
            },
            _unselecting: function (e) {
                var that = this;
                var element = e.element;
                if (that.options.selectable === 'single' && !mobileOS && element.hasClass(FOCUSED)) {
                    e.preventDefault();
                }
            },
            _visibleRange: function () {
                var tables = this.element.find('.k-calendar-view table');
                var firstDateInView = toDateObject(tables.first().find(CELLSELECTOR + ':first').find('a'));
                var lastDateInView = toDateObject(tables.last().find(CELLSELECTOR + ':last').find('a'));
                return {
                    start: firstDateInView,
                    end: lastDateInView
                };
            },
            _dateInViews: function (date) {
                var that = this;
                var tables = that.element.find('.k-calendar-view table');
                var firstDateInView = toDateObject(tables.first().find(CELLSELECTOR + ':first').find('a'));
                var lastDateInView = toDateObject(tables.last().find(CELLSELECTOR + ':last').find('a'));
                return +date <= +lastDateInView && +date >= +firstDateInView;
            },
            _fillRange: function (start, end) {
                var that = this;
                var daysDifference;
                that._selectDates = [];
                daysDifference = daysBetweenTwoDates(start, end);
                addDaysToArray(that._selectDates, daysDifference, start, that.options.disableDates);
            },
            _selectRange: function (start, end) {
                var that = this;
                var current;
                if (+end < +start) {
                    current = end;
                    end = start;
                    start = current;
                }
                that._fillRange(start, end);
                that._visualizeSelectedDatesInView();
            },
            _header: function () {
                var that = this;
                var element = that.element;
                var buttons;
                var header = element.find('.k-calendar-header');
                if (!header.length) {
                    header = $('<div class="k-calendar-header">' + '<a href="#" role="button" class="k-button k-title" aria-live="assertive" aria-atomic="true"></a>' + '<span class="k-calendar-nav">' + '<a href="#" role="button" class="k-button k-button-icon k-prev-view" ' + ARIA_LABEL + '="Previous"><span class="k-icon k-i-arrow-60-left"></span></a>' + '<a href="#" role="button" class="k-button k-button-icon k-next-view" ' + ARIA_LABEL + '="Next"><span class="k-icon k-i-arrow-60-right"></span></a>' + '</span>' + '</div>').prependTo(element);
                }
                that.header = header;
                header.on(MOUSEENTER + ns + ' ' + MOUSELEAVE_NS + ' ' + FOCUS + ns + ' ' + BLUR + ns, '.k-button', mousetoggle).on('click', function () {
                    return false;
                }).on(CLICK + ns, '.k-button.k-title', function () {
                    that.navigateUp();
                    that._focusCell(that._cellByDate(that._current), true);
                    that.trigger(NAVIGATE);
                }).on(CLICK + ns, '.k-button.k-prev-view', function (e) {
                    e.preventDefault();
                    that.navigateToPast();
                    that.trigger(NAVIGATE);
                }).on(CLICK + ns, '.k-button.k-next-view', function (e) {
                    e.preventDefault();
                    that.navigateToFuture();
                    that.trigger(NAVIGATE);
                });
                buttons = header.find('.k-button');
                that._title = buttons.filter('.k-title');
                that._navContainer = header.find('.k-calendar-nav');
                that[PREVARROW] = buttons.filter('.k-prev-view');
                that[NEXTARROW] = buttons.filter('.k-next-view');
            },
            _wrapper: function () {
                this.tablesWrapper = $('<div class="k-calendar-view" />').insertAfter(this.element[0].firstChild);
            },
            _templates: function () {
                var that = this;
                var options = that.options;
                var month = options.month;
                var content = month.content;
                var weekNumber = month.weekNumber;
                var empty = month.empty;
                that.month = {
                    content: template('<td#=data.cssClass# role="gridcell"><a tabindex="-1" class="k-link#=data.linkClass#" href="#=data.url#" ' + kendo.attr(VALUE) + '="#=data.dateString#" title="#=data.title#">' + (content || '#=data.value#') + '</a></td>', { useWithBlock: !!content }),
                    empty: template('<td role="gridcell"' + (empty ? '>' : ' class="k-out-of-range">') + (empty || '<a class=\'k-link\'></a>') + '</td>', { useWithBlock: !!empty }),
                    weekNumber: template('<td class="k-alt">' + (weekNumber || '#= data.weekNumber #') + '</td>', { useWithBlock: !!weekNumber })
                };
            },
            _footer: function () {
                var that = this;
                var options = that.options;
                var template = options.footer !== false ? kendo.template(that.options.footer || '#= kendo.toString(data,"D","' + options.culture + '") #', { useWithBlock: false }) : null;
                var today = getToday();
                var element = that.element;
                var footer = element.find('.k-footer');
                if (!template) {
                    that._toggle(false);
                    footer.hide();
                    return;
                }
                if (!footer[0]) {
                    footer = $('<div class="k-footer"><a href="#" class="k-link k-nav-today"></a></div>').appendTo(element);
                }
                that._today = footer.show().find('.k-link').html(template(today)).attr('title', kendo.toString(today, 'D', that.options.culture));
                that._toggle();
            },
            _navigate: function (arrow, modifier, preventFocus) {
                var that = this;
                var index = that._index + 1;
                var currentValue = new DATE(+that._current);
                var originaValue = new DATE(+that._current);
                var offset;
                arrow = that[arrow];
                offset = that._cellByDate(currentValue).closest('table').index();
                if (modifier > 0) {
                    offset = 1 - offset;
                } else {
                    offset = offset + 1;
                }
                if (!arrow || !arrow.hasClass(DISABLED)) {
                    if (index > 3) {
                        currentValue.setFullYear(currentValue.getFullYear() + 100 * (modifier * offset));
                    } else {
                        calendar.views[index].setDate(currentValue, modifier * offset);
                    }
                    that.navigate(currentValue);
                    if (that._dateInViews(originaValue)) {
                        that._focusCell(that._cellByDate(originaValue), !preventFocus);
                        that._current = originaValue;
                    } else {
                        if (index > 3) {
                            originaValue.setFullYear(originaValue.getFullYear() + 100 * modifier);
                        } else {
                            calendar.views[index].setDate(originaValue, modifier);
                        }
                        that._focusCell(that._cellByDate(originaValue), !preventFocus);
                        that._current = originaValue;
                    }
                }
            },
            _toggle: function (toggle) {
                var that = this;
                var options = that.options;
                var isTodayDisabled = options.selectable !== 'range' && that.options.disableDates(getToday());
                var link = that._today;
                if (toggle === undefined) {
                    toggle = isInRange(getToday(), options.min, options.max);
                }
                if (link) {
                    link.off(CLICK + ns);
                    if (toggle && !isTodayDisabled) {
                        link.addClass(TODAY).removeClass(DISABLED).on(CLICK + ns, proxy(that._todayClick, that));
                    } else {
                        link.removeClass(TODAY).addClass(DISABLED).on(CLICK + ns, function prevent(e) {
                            e.preventDefault();
                        });
                    }
                }
            },
            _click: function (link, preventFocus) {
                var that = this;
                var options = that.options;
                var currentValue = new Date(+that._current);
                var value = toDateObject(link);
                kendo.date.adjustDST(value, 0);
                that._currentView.setDate(currentValue, value);
                that._current = value;
                if (that._currentView.name !== options.depth) {
                    that.navigateDown(calendar.restrictValue(currentValue, options.min, options.max));
                    that._focusCell(that._cellByDate(that._current), !preventFocus);
                    that.trigger(NAVIGATE);
                } else {
                    that._focusCell(link.closest('td'), !preventFocus);
                }
            },
            _blur: function () {
                var that = this;
                if (that._cell) {
                    that._cell.removeClass(FOCUSED);
                }
            },
            _focus: function (e) {
                var that = this;
                var table = $(e.currentTarget);
                var cell = that._cell;
                if (!cell || !$.contains(table[0], cell[0])) {
                    cell = table.find(CELLSELECTORVALID + ':first');
                }
                that._focusCell(cell);
            },
            _focusCell: function (cell, focusTable) {
                var that = this;
                var cellId = that._cellID;
                var table = cell.closest('table');
                if (that._cell && that._cell.length) {
                    that._cell[0].removeAttribute(ARIA_SELECTED);
                    that._cell[0].removeAttribute(ARIA_LABEL);
                    that._cell.removeClass(FOCUSED);
                    that._cell[0].removeAttribute(ID);
                    that._cell.closest('table')[0].removeAttribute('aria-activedescendant');
                }
                that._cell = cell;
                if (focusTable) {
                    table.trigger('focus');
                }
                if (cellId) {
                    cell.attr(ID, cellId);
                    table.attr('aria-activedescendant', cellId);
                }
                cell.attr(ARIA_SELECTED, true).addClass(FOCUSED);
                if (cell.length && that._currentView.name == 'month') {
                    that._current = toDateObject(cell.find('a'));
                }
            },
            _todayClick: function (e) {
                var that = this;
                var disabled = that.options.disableDates;
                var today = getToday();
                var navigate = false;
                e.preventDefault();
                if (disabled(today)) {
                    return;
                }
                that._value = today;
                if (that.options.selectable === 'multiple') {
                    that._selectDates = [today];
                }
                if (that.options.selectable === 'range') {
                    that.rangeSelectable.clear(true);
                    that._range = {
                        start: today,
                        end: null
                    };
                }
                if (that._currentView.name != 'month' || !that._dateInViews(today)) {
                    navigate = true;
                }
                that.navigate(today, that.options.depth);
                if (that.options.selectable === 'single') {
                    that.selectable._lastActive = null;
                }
                if (navigate) {
                    that.trigger(NAVIGATE);
                }
                that.trigger(CHANGE);
            },
            _validateValue: function (value) {
                var that = this;
                var options = that.options;
                var min = options.min;
                var max = options.max;
                value = kendo.parseDate(value, options.format, options.culture);
                if (value !== null) {
                    value = new DATE(+value);
                    if (!isInRange(value, min, max)) {
                        value = null;
                    }
                }
                if (value === null || !that.options.disableDates(new Date(+value))) {
                    that._value = value;
                } else if (that._value === undefined) {
                    that._value = null;
                }
                return that._value;
            },
            clearSelection: function () {
                var that = this;
                if (that.selectable) {
                    that.element.find(DOT + SELECTED).removeClass(SELECTED);
                }
                if (that.rangeSelectable) {
                    that.rangeSelectable.clear(true);
                }
            },
            _restoreSelection: function () {
                var that = this;
                var range;
                var selectable = that.options.selectable;
                if (that._currentView.name !== that.options.depth) {
                    return;
                }
                that._preventChange = true;
                if (selectable === 'range') {
                    range = that.selectRange();
                    if (!range || !range.start) {
                        that._preventChange = false;
                        return;
                    }
                    that.selectRange(range);
                }
                if (selectable === 'single' && that.value()) {
                    that.selectable.value(that._cellByDate(that.value()));
                }
                if (selectable === 'multiple') {
                    that._visualizeSelectedDatesInView();
                }
                that._preventChange = false;
            },
            value: function (value) {
                var that = this;
                var cell;
                if (value === undefined) {
                    return that._value;
                }
                value = that._validateValue(value);
                that.clearSelection();
                if (value && !that._dateInViews(value)) {
                    that.navigate(value);
                }
                if (value !== null && that._currentView.name === MONTH) {
                    cell = that._cellByDate(value);
                    if (that.selectable) {
                        that.selectable.value(cell);
                    }
                    if (that.rangeSelectable) {
                        that.rangeSelectable.start(cell);
                        that.rangeSelectable._lastActive = cell;
                    }
                }
            },
            selectDates: function (dates) {
                var that = this;
                var validSelectedDates;
                var datesUnique;
                if (dates === undefined) {
                    return that._selectDates;
                }
                datesUnique = dates.map(function (date) {
                    return date.getTime();
                }).filter(function (date, position, array) {
                    return array.indexOf(date) === position;
                }).map(function (time) {
                    return new Date(time);
                });
                validSelectedDates = $.grep(datesUnique, function (value) {
                    if (value) {
                        return +that._validateValue(new Date(value.setHours(0, 0, 0, 0))) === +value;
                    }
                });
                that._selectDates = validSelectedDates.length > 0 ? validSelectedDates : datesUnique.length === 0 ? datesUnique : that._selectDates;
                that._visualizeSelectedDatesInView();
            },
            selectRange: function (range) {
                var that = this;
                var startInRange;
                var endInRange;
                var visibleRange;
                if (range === undefined) {
                    return that._range;
                }
                that._range = range;
                if (!range.start) {
                    return;
                }
                visibleRange = that._visibleRange();
                startInRange = that._dateInViews(range.start);
                endInRange = range.end && that._dateInViews(range.end);
                if (!startInRange && endInRange) {
                    that.rangeSelectable.selectTo(that._cellByDate(range.end));
                }
                if (startInRange && endInRange) {
                    that.rangeSelectable.range(that._cellByDate(range.start), that._cellByDate(range.end));
                }
                if (range.end && startInRange && !endInRange) {
                    that.rangeSelectable.selectFrom(that._cellByDate(range.start));
                }
                if (!range.end && startInRange) {
                    that.rangeSelectable.start(that._cellByDate(range.start));
                }
                if (+visibleRange.start > +range.start && +visibleRange.end < +range.end) {
                    that.rangeSelectable.mid(that.element.find(CELLSELECTORVALID));
                }
            }
        });
        kendo.ui.plugin(MultiViewCalendar);
        function mousetoggle(e) {
            var disabled = $(this).hasClass('k-state-disabled');
            if (!disabled) {
                $(this).toggleClass(HOVER, MOUSEENTER.indexOf(e.type) > -1 || e.type == FOCUS);
            }
        }
        function addDaysToArray(array, numberOfDays, fromDate, disableDates) {
            for (var i = 0; i <= numberOfDays; i++) {
                var nextDay = new Date(fromDate.getTime());
                nextDay = new Date(nextDay.setDate(nextDay.getDate() + i));
                if (!disableDates(nextDay)) {
                    array.push(nextDay);
                }
            }
        }
        function daysBetweenTwoDates(startDate, endDate) {
            if (+endDate < +startDate) {
                var temp = +startDate;
                calendar.views[0].setDate(startDate, endDate);
                calendar.views[0].setDate(endDate, new Date(temp));
            }
            var fromDateUTC = Date.UTC(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
            var endDateUTC = Date.UTC(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
            return Math.ceil((+endDateUTC - +fromDateUTC) / kendo.date.MS_PER_DAY);
        }
        function shiftDate(value, dimension, numberOfViews) {
            var current;
            if (dimension === 'month') {
                current = new DATE(value.getFullYear(), value.getMonth() + numberOfViews, value.getDate());
                current.setFullYear(value.getFullYear());
                if (Math.abs(current.getMonth() - value.getMonth()) > numberOfViews || numberOfViews > 10) {
                    current.setMonth(value.getMonth() + numberOfViews);
                    current = calendar.views[0].last(current);
                }
                return current;
            } else if (dimension === 'year') {
                current = new DATE(1, value.getMonth(), value.getDate());
                current.setFullYear(value.getFullYear() + numberOfViews);
                if (Math.abs(current.getFullYear() - value.getFullYear()) > numberOfViews) {
                    current = new DATE(1, value.getMonth(), 1);
                    current.setFullYear(value.getFullYear() + numberOfViews);
                    current = calendar.views[1].last(current);
                }
                return current;
            } else if (dimension === 'decade') {
                current = new DATE(1, value.getMonth(), value.getDate());
                current.setFullYear(value.getFullYear() + 10 * numberOfViews);
                if (Math.abs(current.getFullYear() - value.getFullYear()) > 10 * numberOfViews) {
                    current = new DATE(1, value.getMonth(), 1);
                    current.setFullYear(value.getFullYear() + 10 * numberOfViews);
                    current = calendar.views[2].last(current);
                }
                return current;
            } else if (dimension === 'century') {
                current = new DATE(1, value.getMonth(), value.getDate());
                current.setFullYear(value.getFullYear() + 100 * numberOfViews);
                if (Math.abs(current.getFullYear() - value.getFullYear()) > 100 * numberOfViews) {
                    current = new DATE(1, value.getMonth(), 1);
                    current.setFullYear(value.getFullYear() + 100 * numberOfViews);
                    current = calendar.views[3].last(current);
                }
                return current;
            }
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.virtuallist', ['kendo.data'], f);
}(function () {
    var __meta__ = {
        id: 'virtuallist',
        name: 'VirtualList',
        category: 'framework',
        depends: ['data'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, DataBoundWidget = ui.DataBoundWidget, proxy = $.proxy, percentageUnitsRegex = /^\d+(\.\d+)?%$/i, WRAPPER = 'k-virtual-wrap', VIRTUALLIST = 'k-virtual-list', CONTENT = 'k-virtual-content', LIST = 'k-list', HEADER = 'k-group-header', VIRTUALITEM = 'k-virtual-item', ITEM = 'k-item', HEIGHTCONTAINER = 'k-height-container', GROUPITEM = 'k-group', SELECTED = 'k-state-selected', FOCUSED = 'k-state-focused', HOVER = 'k-state-hover', CHANGE = 'change', CLICK = 'click', LISTBOUND = 'listBound', ITEMCHANGE = 'itemChange', ACTIVATE = 'activate', DEACTIVATE = 'deactivate', VIRTUAL_LIST_NS = '.VirtualList';
        function lastFrom(array) {
            return array[array.length - 1];
        }
        function toArray(value) {
            return value instanceof Array ? value : [value];
        }
        function isPrimitive(dataItem) {
            return typeof dataItem === 'string' || typeof dataItem === 'number' || typeof dataItem === 'boolean';
        }
        function getItemCount(screenHeight, listScreens, itemHeight) {
            return Math.ceil(screenHeight * listScreens / itemHeight);
        }
        function appendChild(parent, className, tagName) {
            var element = document.createElement(tagName || 'div');
            if (className) {
                element.className = className;
            }
            parent.appendChild(element);
            return element;
        }
        function getDefaultItemHeight() {
            var mockList = $('<div class="k-popup"><ul class="k-list"><li class="k-item"><li></ul></div>'), lineHeight;
            mockList.css({
                position: 'absolute',
                left: '-200000px',
                visibility: 'hidden'
            });
            mockList.appendTo(document.body);
            lineHeight = parseFloat(kendo.getComputedStyles(mockList.find('.k-item')[0], ['line-height'])['line-height']);
            mockList.remove();
            return lineHeight;
        }
        function bufferSizes(screenHeight, listScreens, opposite) {
            return {
                down: screenHeight * opposite,
                up: screenHeight * (listScreens - 1 - opposite)
            };
        }
        function listValidator(options, screenHeight) {
            var downThreshold = (options.listScreens - 1 - options.threshold) * screenHeight;
            var upThreshold = options.threshold * screenHeight;
            return function (list, scrollTop, lastScrollTop) {
                if (scrollTop > lastScrollTop) {
                    return scrollTop - list.top < downThreshold;
                } else {
                    return list.top === 0 || scrollTop - list.top > upThreshold;
                }
            };
        }
        function scrollCallback(element, callback) {
            return function (force) {
                return callback(element.scrollTop, force);
            };
        }
        function syncList(reorder) {
            return function (list, force) {
                reorder(list.items, list.index, force);
                return list;
            };
        }
        function position(element, y) {
            if (kendo.support.browser.msie && kendo.support.browser.version < 10) {
                element.style.top = y + 'px';
            } else {
                element.style.webkitTransform = 'translateY(' + y + 'px)';
                element.style.transform = 'translateY(' + y + 'px)';
            }
        }
        function map2(callback, templates) {
            return function (arr1, arr2) {
                for (var i = 0, len = arr1.length; i < len; i++) {
                    callback(arr1[i], arr2[i], templates);
                    if (arr2[i].item) {
                        this.trigger(ITEMCHANGE, {
                            item: $(arr1[i]),
                            data: arr2[i].item,
                            ns: kendo.ui
                        });
                    }
                }
            };
        }
        function reshift(items, diff) {
            var range;
            if (diff > 0) {
                range = items.splice(0, diff);
                items.push.apply(items, range);
            } else {
                range = items.splice(diff, -diff);
                items.unshift.apply(items, range);
            }
            return range;
        }
        function render(element, data, templates) {
            var itemTemplate = templates.template;
            element = $(element);
            if (!data.item) {
                itemTemplate = templates.placeholderTemplate;
            }
            if (data.index === 0 && this.header && data.group) {
                this.header.html(templates.fixedGroupTemplate(data.group));
            }
            this.angular('cleanup', function () {
                return { elements: [element] };
            });
            element.attr('data-uid', data.item ? data.item.uid : '').attr('data-offset-index', data.index);
            if (this.options.columns && this.options.columns.length && data.item) {
                element.html(renderColumns(this.options, data.item, templates));
            } else {
                element.html(itemTemplate(data.item || {}));
            }
            element.toggleClass(FOCUSED, data.current);
            element.toggleClass(SELECTED, data.selected);
            element.toggleClass('k-first', data.newGroup);
            element.toggleClass('k-last', data.isLastGroupedItem);
            element.toggleClass('k-loading-item', !data.item);
            if (data.index !== 0 && data.newGroup) {
                $('<div class=' + GROUPITEM + '></div>').appendTo(element).html(templates.groupTemplate(data.group));
            }
            if (data.top !== undefined) {
                position(element[0], data.top);
            }
            this.angular('compile', function () {
                return {
                    elements: [element],
                    data: [{
                            dataItem: data.item,
                            group: data.group,
                            newGroup: data.newGroup
                        }]
                };
            });
        }
        function renderColumns(options, dataItem, templates) {
            var item = '';
            for (var i = 0; i < options.columns.length; i++) {
                var currentWidth = options.columns[i].width;
                var currentWidthInt = parseInt(currentWidth, 10);
                var widthStyle = '';
                if (currentWidth) {
                    widthStyle += 'style=\'width:';
                    widthStyle += currentWidthInt;
                    widthStyle += percentageUnitsRegex.test(currentWidth) ? '%' : 'px';
                    widthStyle += ';\'';
                }
                item += '<span class=\'k-cell\' ' + widthStyle + '>';
                item += templates['column' + i](dataItem);
                item += '</span>';
            }
            return item;
        }
        function mapChangedItems(selected, itemsToMatch) {
            var itemsLength = itemsToMatch.length;
            var selectedLength = selected.length;
            var dataItem;
            var found;
            var i, j;
            var changed = [];
            var unchanged = [];
            if (selectedLength) {
                for (i = 0; i < selectedLength; i++) {
                    dataItem = selected[i];
                    found = false;
                    for (j = 0; j < itemsLength; j++) {
                        if (dataItem === itemsToMatch[j]) {
                            found = true;
                            changed.push({
                                index: i,
                                item: dataItem
                            });
                            break;
                        }
                    }
                    if (!found) {
                        unchanged.push(dataItem);
                    }
                }
            }
            return {
                changed: changed,
                unchanged: unchanged
            };
        }
        function isActivePromise(promise) {
            return promise && promise.state() !== 'resolved';
        }
        var VirtualList = DataBoundWidget.extend({
            init: function (element, options) {
                var that = this;
                that.bound(false);
                that._fetching = false;
                Widget.fn.init.call(that, element, options);
                if (!that.options.itemHeight) {
                    that.options.itemHeight = getDefaultItemHeight();
                }
                options = that.options;
                that.element.addClass(LIST + ' ' + VIRTUALLIST).attr('role', 'listbox');
                that.content = that.element.wrap('<div unselectable=\'on\' class=\'' + CONTENT + '\'></div>').parent();
                that.wrapper = that.content.wrap('<div class=\'' + WRAPPER + '\'></div>').parent();
                that.header = that.content.before('<div class=\'' + HEADER + '\'></div>').prev();
                if (options.columns && options.columns.length) {
                    that.element.removeClass(LIST);
                }
                that.element.on('mouseenter' + VIRTUAL_LIST_NS, 'li:not(.k-loading-item)', function () {
                    $(this).addClass(HOVER);
                }).on('mouseleave' + VIRTUAL_LIST_NS, 'li', function () {
                    $(this).removeClass(HOVER);
                });
                that._values = toArray(that.options.value);
                that._selectedDataItems = [];
                that._selectedIndexes = [];
                that._rangesList = {};
                that._promisesList = [];
                that._optionID = kendo.guid();
                that._templates();
                that.setDataSource(options.dataSource);
                that.content.on('scroll' + VIRTUAL_LIST_NS, kendo.throttle(function () {
                    that._renderItems();
                    that._triggerListBound();
                }, options.delay));
                that._selectable();
            },
            options: {
                name: 'VirtualList',
                autoBind: true,
                delay: 100,
                height: null,
                listScreens: 4,
                threshold: 0.5,
                itemHeight: null,
                oppositeBuffer: 1,
                type: 'flat',
                selectable: false,
                value: [],
                dataValueField: null,
                template: '#:data#',
                placeholderTemplate: 'loading...',
                groupTemplate: '#:data#',
                fixedGroupTemplate: '#:data#',
                mapValueTo: 'index',
                valueMapper: null
            },
            events: [
                CHANGE,
                CLICK,
                LISTBOUND,
                ITEMCHANGE,
                ACTIVATE,
                DEACTIVATE
            ],
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                if (this._selectProxy && this.options.selectable === false) {
                    this.element.off(CLICK, '.' + VIRTUALITEM, this._selectProxy);
                } else if (!this._selectProxy && this.options.selectable) {
                    this._selectable();
                }
                this._templates();
                this.refresh();
            },
            items: function () {
                return $(this._items);
            },
            destroy: function () {
                this.wrapper.off(VIRTUAL_LIST_NS);
                this.dataSource.unbind(CHANGE, this._refreshHandler);
                Widget.fn.destroy.call(this);
            },
            setDataSource: function (source) {
                var that = this;
                var dataSource = source || {};
                var value;
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                dataSource = kendo.data.DataSource.create(dataSource);
                if (that.dataSource) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                    that._clean();
                    that.bound(false);
                    that._deferValueSet = true;
                    value = that.value();
                    that.value([]);
                    that.mute(function () {
                        that.value(value);
                    });
                } else {
                    that._refreshHandler = $.proxy(that.refresh, that);
                }
                that.dataSource = dataSource.bind(CHANGE, that._refreshHandler);
                that.setDSFilter(dataSource.filter());
                if (dataSource.view().length !== 0) {
                    that.refresh();
                } else if (that.options.autoBind) {
                    dataSource.fetch();
                }
            },
            skip: function () {
                return this.dataSource.currentRangeStart();
            },
            _triggerListBound: function () {
                var that = this;
                var skip = that.skip();
                if (that.bound() && !that._selectingValue && that._skip !== skip) {
                    that._skip = skip;
                    that.trigger(LISTBOUND);
                }
            },
            _getValues: function (dataItems) {
                var getter = this._valueGetter;
                return $.map(dataItems, function (dataItem) {
                    return getter(dataItem);
                });
            },
            _highlightSelectedItems: function () {
                for (var i = 0; i < this._selectedDataItems.length; i++) {
                    var item = this._getElementByDataItem(this._selectedDataItems[i]);
                    if (item.length) {
                        item.addClass(SELECTED);
                    }
                }
            },
            refresh: function (e) {
                var that = this;
                var action = e && e.action;
                var isItemChange = action === 'itemchange';
                var filtered = this.isFiltered();
                var result;
                if (that._mute) {
                    return;
                }
                that._deferValueSet = false;
                if (!that._fetching) {
                    if (filtered) {
                        that.focus(0);
                    }
                    that._createList();
                    if (!action && that._values.length && !filtered && !that.options.skipUpdateOnBind && !that._emptySearch) {
                        that._selectingValue = true;
                        that.bound(true);
                        that.value(that._values, true).done(function () {
                            that._selectingValue = false;
                            that._triggerListBound();
                        });
                    } else {
                        that.bound(true);
                        that._highlightSelectedItems();
                        that._triggerListBound();
                    }
                } else {
                    if (that._renderItems) {
                        that._renderItems(true);
                    }
                    that._triggerListBound();
                }
                if (isItemChange || action === 'remove') {
                    result = mapChangedItems(that._selectedDataItems, e.items);
                    if (result.changed.length) {
                        if (isItemChange) {
                            that.trigger('selectedItemChange', { items: result.changed });
                        } else {
                            that.value(that._getValues(result.unchanged));
                        }
                    }
                }
                that._fetching = false;
            },
            removeAt: function (position) {
                this._selectedIndexes.splice(position, 1);
                this._values.splice(position, 1);
                return {
                    position: position,
                    dataItem: this._selectedDataItems.splice(position, 1)[0]
                };
            },
            setValue: function (value) {
                this._values = toArray(value);
            },
            value: function (value, _forcePrefetch) {
                var that = this;
                if (value === undefined) {
                    return that._values.slice();
                }
                if (value === null) {
                    value = [];
                }
                value = toArray(value);
                if (!that._valueDeferred || that._valueDeferred.state() === 'resolved') {
                    that._valueDeferred = $.Deferred();
                }
                var shouldClear = that.options.selectable === 'multiple' && that.select().length && value.length;
                if (shouldClear || !value.length) {
                    that.select(-1);
                }
                that._values = value;
                if (that.bound() && !that._mute && !that._deferValueSet || _forcePrefetch) {
                    that._prefetchByValue(value);
                }
                return that._valueDeferred;
            },
            _checkValuesOrder: function (value) {
                if (this._removedAddedIndexes && this._removedAddedIndexes.length === value.length) {
                    var newValue = this._removedAddedIndexes.slice();
                    this._removedAddedIndexes = null;
                    return newValue;
                }
                return value;
            },
            _prefetchByValue: function (value) {
                var that = this, dataView = that._dataView, valueGetter = that._valueGetter, mapValueTo = that.options.mapValueTo, item, match = false, forSelection = [];
                for (var i = 0; i < value.length; i++) {
                    for (var idx = 0; idx < dataView.length; idx++) {
                        item = dataView[idx].item;
                        if (item) {
                            match = isPrimitive(item) ? value[i] === item : value[i] === valueGetter(item);
                            if (match) {
                                forSelection.push(dataView[idx].index);
                            }
                        }
                    }
                }
                if (forSelection.length === value.length) {
                    that._values = [];
                    that.select(forSelection);
                    return;
                }
                if (typeof that.options.valueMapper === 'function') {
                    that.options.valueMapper({
                        value: this.options.selectable === 'multiple' ? value : value[0],
                        success: function (response) {
                            if (mapValueTo === 'index') {
                                that.mapValueToIndex(response);
                            } else if (mapValueTo === 'dataItem') {
                                that.mapValueToDataItem(response);
                            }
                        }
                    });
                } else {
                    if (!that.value()[0]) {
                        that.select([-1]);
                    } else {
                        that._selectingValue = false;
                        that._triggerListBound();
                    }
                }
            },
            mapValueToIndex: function (indexes) {
                if (indexes === undefined || indexes === -1 || indexes === null) {
                    indexes = [];
                } else {
                    indexes = toArray(indexes);
                }
                if (!indexes.length) {
                    indexes = [-1];
                } else {
                    var removed = this._deselect([]).removed;
                    if (removed.length) {
                        this._triggerChange(removed, []);
                    }
                }
                this.select(indexes);
            },
            mapValueToDataItem: function (dataItems) {
                var removed, added;
                if (dataItems === undefined || dataItems === null) {
                    dataItems = [];
                } else {
                    dataItems = toArray(dataItems);
                }
                if (!dataItems.length) {
                    this.select([-1]);
                } else {
                    removed = $.map(this._selectedDataItems, function (item, index) {
                        return {
                            index: index,
                            dataItem: item
                        };
                    });
                    added = $.map(dataItems, function (item, index) {
                        return {
                            index: index,
                            dataItem: item
                        };
                    });
                    this._selectedDataItems = dataItems;
                    this._selectedIndexes = [];
                    for (var i = 0; i < this._selectedDataItems.length; i++) {
                        var item = this._getElementByDataItem(this._selectedDataItems[i]);
                        this._selectedIndexes.push(this._getIndecies(item)[0]);
                        item.addClass(SELECTED);
                    }
                    this._triggerChange(removed, added);
                    if (this._valueDeferred) {
                        this._valueDeferred.resolve();
                    }
                }
            },
            deferredRange: function (index) {
                var dataSource = this.dataSource;
                var take = this.itemCount;
                var ranges = this._rangesList;
                var result = $.Deferred();
                var defs = [];
                var low = Math.floor(index / take) * take;
                var high = Math.ceil(index / take) * take;
                var pages = high === low ? [high] : [
                    low,
                    high
                ];
                $.each(pages, function (_, skip) {
                    var end = skip + take;
                    var existingRange = ranges[skip];
                    var deferred;
                    if (!existingRange || existingRange.end !== end) {
                        deferred = $.Deferred();
                        ranges[skip] = {
                            end: end,
                            deferred: deferred
                        };
                        dataSource._multiplePrefetch(skip, take, function () {
                            deferred.resolve();
                        });
                    } else {
                        deferred = existingRange.deferred;
                    }
                    defs.push(deferred);
                });
                $.when.apply($, defs).then(function () {
                    result.resolve();
                });
                return result;
            },
            prefetch: function (indexes) {
                var that = this, take = this.itemCount, isEmptyList = !that._promisesList.length;
                if (!isActivePromise(that._activeDeferred)) {
                    that._activeDeferred = $.Deferred();
                    that._promisesList = [];
                }
                $.each(indexes, function (_, index) {
                    that._promisesList.push(that.deferredRange(that._getSkip(index, take)));
                });
                if (isEmptyList) {
                    $.when.apply($, that._promisesList).done(function () {
                        that._promisesList = [];
                        that._activeDeferred.resolve();
                    });
                }
                return that._activeDeferred;
            },
            _findDataItem: function (view, index) {
                var group;
                if (this.options.type === 'group') {
                    for (var i = 0; i < view.length; i++) {
                        group = view[i].items;
                        if (group.length <= index) {
                            index = index - group.length;
                        } else {
                            return group[index];
                        }
                    }
                }
                return view[index];
            },
            _getRange: function (skip, take) {
                return this.dataSource._findRange(skip, Math.min(skip + take, this.dataSource.total()));
            },
            dataItemByIndex: function (index) {
                var that = this;
                var take = that.itemCount;
                var skip = that._getSkip(index, take);
                var view = this._getRange(skip, take);
                if (!that._getRange(skip, take).length) {
                    return null;
                }
                if (that.options.type === 'group') {
                    kendo.ui.progress($(that.wrapper), true);
                    that.mute(function () {
                        that.dataSource.range(skip, take, function () {
                            kendo.ui.progress($(that.wrapper), false);
                        });
                        view = that.dataSource.view();
                    });
                }
                return that._findDataItem(view, [index - skip]);
            },
            selectedDataItems: function () {
                return this._selectedDataItems.slice();
            },
            scrollWith: function (value) {
                this.content.scrollTop(this.content.scrollTop() + value);
            },
            scrollTo: function (y) {
                this.content.scrollTop(y);
            },
            scrollToIndex: function (index) {
                this.scrollTo(index * this.options.itemHeight);
            },
            focus: function (candidate) {
                var element, index, data, current, itemHeight = this.options.itemHeight, id = this._optionID, triggerEvent = true;
                if (candidate === undefined) {
                    current = this.element.find('.' + FOCUSED);
                    return current.length ? current : null;
                }
                if (typeof candidate === 'function') {
                    data = this.dataSource.flatView();
                    for (var idx = 0; idx < data.length; idx++) {
                        if (candidate(data[idx])) {
                            candidate = idx;
                            break;
                        }
                    }
                }
                if (candidate instanceof Array) {
                    candidate = lastFrom(candidate);
                }
                if (isNaN(candidate)) {
                    element = $(candidate);
                    index = parseInt($(element).attr('data-offset-index'), 10);
                } else {
                    index = candidate;
                    element = this._getElementByIndex(index);
                }
                if (index === -1) {
                    this.element.find('.' + FOCUSED).removeClass(FOCUSED);
                    this._focusedIndex = undefined;
                    return;
                }
                if (element.length) {
                    if (element.hasClass(FOCUSED)) {
                        triggerEvent = false;
                    }
                    if (this._focusedIndex !== undefined) {
                        current = this._getElementByIndex(this._focusedIndex);
                        current.removeClass(FOCUSED).removeAttr('id');
                        if (triggerEvent) {
                            this.trigger(DEACTIVATE);
                        }
                    }
                    this._focusedIndex = index;
                    element.addClass(FOCUSED).attr('id', id);
                    var position = this._getElementLocation(index);
                    if (position === 'top') {
                        this.scrollTo(index * itemHeight);
                    } else if (position === 'bottom') {
                        this.scrollTo(index * itemHeight + itemHeight - this._screenHeight);
                    } else if (position === 'outScreen') {
                        this.scrollTo(index * itemHeight);
                    }
                    if (triggerEvent) {
                        this.trigger(ACTIVATE);
                    }
                } else {
                    this._focusedIndex = index;
                    this.items().removeClass(FOCUSED);
                    this.scrollToIndex(index);
                }
            },
            focusIndex: function () {
                return this._focusedIndex;
            },
            focusFirst: function () {
                this.scrollTo(0);
                this.focus(0);
            },
            focusLast: function () {
                var lastIndex = this.dataSource.total();
                this.scrollTo(this.heightContainer.offsetHeight);
                this.focus(lastIndex - 1);
            },
            focusPrev: function () {
                var index = this._focusedIndex;
                var current;
                if (!isNaN(index) && index > 0) {
                    index -= 1;
                    this.focus(index);
                    current = this.focus();
                    if (current && current.hasClass('k-loading-item')) {
                        index += 1;
                        this.focus(index);
                    }
                    return index;
                } else {
                    index = this.dataSource.total() - 1;
                    this.focus(index);
                    return index;
                }
            },
            focusNext: function () {
                var index = this._focusedIndex;
                var lastIndex = this.dataSource.total() - 1;
                var current;
                if (!isNaN(index) && index < lastIndex) {
                    index += 1;
                    this.focus(index);
                    current = this.focus();
                    if (current && current.hasClass('k-loading-item')) {
                        index -= 1;
                        this.focus(index);
                    }
                    return index;
                } else {
                    index = 0;
                    this.focus(index);
                    return index;
                }
            },
            _triggerChange: function (removed, added) {
                removed = removed || [];
                added = added || [];
                if (removed.length || added.length) {
                    this.trigger(CHANGE, {
                        removed: removed,
                        added: added
                    });
                }
            },
            select: function (candidate) {
                var that = this, indices, initialIndices, singleSelection = that.options.selectable !== 'multiple', prefetchStarted = isActivePromise(that._activeDeferred), filtered = this.isFiltered(), isAlreadySelected, deferred, result, removed = [];
                if (candidate === undefined) {
                    return that._selectedIndexes.slice();
                }
                if (!that._selectDeferred || that._selectDeferred.state() === 'resolved') {
                    that._selectDeferred = $.Deferred();
                }
                indices = that._getIndecies(candidate);
                isAlreadySelected = singleSelection && !filtered && lastFrom(indices) === lastFrom(this._selectedIndexes);
                removed = that._deselectCurrentValues(indices);
                if (removed.length || !indices.length || isAlreadySelected) {
                    that._triggerChange(removed);
                    if (that._valueDeferred) {
                        that._valueDeferred.resolve().promise();
                    }
                    return that._selectDeferred.resolve().promise();
                }
                if (indices.length === 1 && indices[0] === -1) {
                    indices = [];
                }
                initialIndices = indices;
                result = that._deselect(indices);
                removed = result.removed;
                indices = result.indices;
                if (singleSelection) {
                    prefetchStarted = false;
                    if (indices.length) {
                        indices = [lastFrom(indices)];
                    }
                }
                var done = function () {
                    var added = that._select(indices);
                    if (initialIndices.length === indices.length || singleSelection) {
                        that.focus(indices);
                    }
                    that._triggerChange(removed, added);
                    if (that._valueDeferred) {
                        that._valueDeferred.resolve();
                    }
                    that._selectDeferred.resolve();
                };
                deferred = that.prefetch(indices);
                if (!prefetchStarted) {
                    if (deferred) {
                        deferred.done(done);
                    } else {
                        done();
                    }
                }
                return that._selectDeferred.promise();
            },
            bound: function (bound) {
                if (bound === undefined) {
                    return this._listCreated;
                }
                this._listCreated = bound;
            },
            mute: function (callback) {
                this._mute = true;
                proxy(callback(), this);
                this._mute = false;
            },
            setDSFilter: function (filter) {
                this._lastDSFilter = $.extend({}, filter);
            },
            isFiltered: function () {
                if (!this._lastDSFilter) {
                    this.setDSFilter(this.dataSource.filter());
                }
                return !kendo.data.Query.compareFilters(this.dataSource.filter(), this._lastDSFilter);
            },
            skipUpdate: $.noop,
            _getElementByIndex: function (index) {
                return this.items().filter(function (idx, element) {
                    return index === parseInt($(element).attr('data-offset-index'), 10);
                });
            },
            _getElementByDataItem: function (dataItem) {
                var dataView = this._dataView, valueGetter = this._valueGetter, element, match;
                for (var i = 0; i < dataView.length; i++) {
                    match = dataView[i].item && isPrimitive(dataView[i].item) ? dataView[i].item === dataItem : dataView[i].item && dataItem && valueGetter(dataView[i].item) == valueGetter(dataItem);
                    if (match) {
                        element = dataView[i];
                        break;
                    }
                }
                return element ? this._getElementByIndex(element.index) : $();
            },
            _clean: function () {
                this.result = undefined;
                this._lastScrollTop = undefined;
                this._skip = undefined;
                $(this.heightContainer).remove();
                this.heightContainer = undefined;
                this.element.empty();
            },
            _height: function () {
                var hasData = !!this.dataSource.view().length, height = this.options.height, itemHeight = this.options.itemHeight, total = this.dataSource.total();
                if (!hasData) {
                    height = 0;
                } else if (height / itemHeight > total) {
                    height = total * itemHeight;
                }
                return height;
            },
            setScreenHeight: function () {
                var height = this._height();
                this.content.height(height);
                this._screenHeight = height;
            },
            screenHeight: function () {
                return this._screenHeight;
            },
            _getElementLocation: function (index) {
                var scrollTop = this.content.scrollTop(), screenHeight = this._screenHeight, itemHeight = this.options.itemHeight, yPosition = index * itemHeight, yDownPostion = yPosition + itemHeight, screenEnd = scrollTop + screenHeight, position;
                if (yPosition === scrollTop - itemHeight || yDownPostion > scrollTop && yPosition < scrollTop) {
                    position = 'top';
                } else if (yPosition === screenEnd || yPosition < screenEnd && screenEnd < yDownPostion) {
                    position = 'bottom';
                } else if (yPosition >= scrollTop && yPosition <= scrollTop + (screenHeight - itemHeight)) {
                    position = 'inScreen';
                } else {
                    position = 'outScreen';
                }
                return position;
            },
            _templates: function () {
                var options = this.options;
                var templates = {
                    template: options.template,
                    placeholderTemplate: options.placeholderTemplate,
                    groupTemplate: options.groupTemplate,
                    fixedGroupTemplate: options.fixedGroupTemplate
                };
                if (options.columns) {
                    for (var i = 0; i < options.columns.length; i++) {
                        var currentColumn = options.columns[i];
                        var templateText = currentColumn.field ? currentColumn.field.toString() : 'text';
                        templates['column' + i] = currentColumn.template || '#: ' + templateText + '#';
                    }
                }
                for (var key in templates) {
                    if (typeof templates[key] !== 'function') {
                        templates[key] = kendo.template(templates[key] || '');
                    }
                }
                this.templates = templates;
            },
            _generateItems: function (element, count) {
                var items = [], item, itemHeight = this.options.itemHeight + 'px';
                while (count-- > 0) {
                    item = document.createElement('li');
                    item.tabIndex = -1;
                    item.className = VIRTUALITEM + ' ' + ITEM;
                    item.setAttribute('role', 'option');
                    item.style.height = itemHeight;
                    item.style.minHeight = itemHeight;
                    element.appendChild(item);
                    items.push(item);
                }
                return items;
            },
            _saveInitialRanges: function () {
                var ranges = this.dataSource._ranges;
                var deferred = $.Deferred();
                deferred.resolve();
                this._rangesList = {};
                for (var i = 0; i < ranges.length; i++) {
                    this._rangesList[ranges[i].start] = {
                        end: ranges[i].end,
                        deferred: deferred
                    };
                }
            },
            _createList: function () {
                var that = this, content = that.content.get(0), options = that.options, dataSource = that.dataSource;
                if (that.bound()) {
                    that._clean();
                }
                that._saveInitialRanges();
                that._buildValueGetter();
                that.setScreenHeight();
                that.itemCount = getItemCount(that._screenHeight, options.listScreens, options.itemHeight);
                if (that.itemCount > dataSource.total()) {
                    that.itemCount = dataSource.total();
                }
                that._items = that._generateItems(that.element[0], that.itemCount);
                that._setHeight(options.itemHeight * dataSource.total());
                that.options.type = (dataSource.group() || []).length ? 'group' : 'flat';
                if (that.options.type === 'flat') {
                    that.header.hide();
                } else {
                    that.header.show();
                }
                that.getter = that._getter(function () {
                    that._renderItems(true);
                });
                that._onScroll = function (scrollTop, force) {
                    var getList = that._listItems(that.getter);
                    return that._fixedHeader(scrollTop, getList(scrollTop, force));
                };
                that._renderItems = that._whenChanged(scrollCallback(content, that._onScroll), syncList(that._reorderList(that._items, $.proxy(render, that))));
                that._renderItems();
                that._calculateGroupPadding(that._screenHeight);
                that._calculateColumnsHeaderPadding();
            },
            _setHeight: function (height) {
                var currentHeight, heightContainer = this.heightContainer;
                if (!heightContainer) {
                    heightContainer = this.heightContainer = appendChild(this.content[0], HEIGHTCONTAINER);
                } else {
                    currentHeight = heightContainer.offsetHeight;
                }
                if (height !== currentHeight) {
                    heightContainer.innerHTML = '';
                    while (height > 0) {
                        var padHeight = Math.min(height, 250000);
                        appendChild(heightContainer).style.height = padHeight + 'px';
                        height -= padHeight;
                    }
                }
            },
            _getter: function () {
                var lastRequestedRange = null, dataSource = this.dataSource, lastRangeStart = dataSource.skip(), type = this.options.type, pageSize = this.itemCount, flatGroups = {};
                if (dataSource.pageSize() < pageSize) {
                    this.mute(function () {
                        dataSource.pageSize(pageSize);
                    });
                }
                return function (index, rangeStart) {
                    var that = this;
                    if (!dataSource.inRange(rangeStart, pageSize)) {
                        if (lastRequestedRange !== rangeStart) {
                            lastRequestedRange = rangeStart;
                            lastRangeStart = rangeStart;
                            if (that._getterDeferred) {
                                that._getterDeferred.reject();
                            }
                            that._getterDeferred = that.deferredRange(rangeStart);
                            that._getterDeferred.then(function () {
                                var firstItemIndex = that._indexConstraint(that.content[0].scrollTop);
                                that._getterDeferred = null;
                                if (rangeStart <= firstItemIndex && firstItemIndex <= rangeStart + pageSize) {
                                    that._fetching = true;
                                    dataSource.range(rangeStart, pageSize);
                                }
                            });
                        }
                        return null;
                    } else {
                        if (lastRangeStart !== rangeStart) {
                            this.mute(function () {
                                dataSource.range(rangeStart, pageSize);
                                lastRangeStart = rangeStart;
                            });
                        }
                        var result;
                        if (type === 'group') {
                            if (!flatGroups[rangeStart]) {
                                var flatGroup = flatGroups[rangeStart] = [];
                                var groups = dataSource.view();
                                for (var i = 0, len = groups.length; i < len; i++) {
                                    var group = groups[i];
                                    for (var j = 0, groupLength = group.items.length; j < groupLength; j++) {
                                        flatGroup.push({
                                            item: group.items[j],
                                            group: group.value
                                        });
                                    }
                                }
                            }
                            result = flatGroups[rangeStart][index - rangeStart];
                        } else {
                            result = dataSource.view()[index - rangeStart];
                        }
                        return result;
                    }
                };
            },
            _fixedHeader: function (scrollTop, list) {
                var group = this.currentVisibleGroup, itemHeight = this.options.itemHeight, firstVisibleDataItemIndex = Math.floor((scrollTop - list.top) / itemHeight), firstVisibleDataItem = list.items[firstVisibleDataItemIndex];
                if (firstVisibleDataItem && firstVisibleDataItem.item) {
                    var firstVisibleGroup = firstVisibleDataItem.group;
                    if (firstVisibleGroup !== group) {
                        var fixedGroupText = firstVisibleGroup || '';
                        this.header.html(this.templates.fixedGroupTemplate(fixedGroupText));
                        this.currentVisibleGroup = firstVisibleGroup;
                    }
                }
                return list;
            },
            _itemMapper: function (item, index, value) {
                var listType = this.options.type, itemHeight = this.options.itemHeight, currentIndex = this._focusedIndex, selected = false, current = false, newGroup = false, group = null, match = false, valueGetter = this._valueGetter;
                if (listType === 'group') {
                    if (item) {
                        newGroup = index === 0 || this._currentGroup !== false && this._currentGroup !== item.group;
                        this._currentGroup = item.group;
                    }
                    group = item ? item.group : null;
                    item = item ? item.item : null;
                }
                if (this.options.mapValueTo === 'dataItem' && this._selectedDataItems.length && item) {
                    for (var i = 0; i < this._selectedDataItems.length; i++) {
                        match = valueGetter(this._selectedDataItems[i]) === valueGetter(item);
                        if (match) {
                            selected = true;
                            break;
                        }
                    }
                } else if (!this.isFiltered() && value.length && item) {
                    for (var j = 0; j < value.length; j++) {
                        match = isPrimitive(item) ? value[j] === item : value[j] === valueGetter(item);
                        if (match) {
                            value.splice(j, 1);
                            selected = true;
                            break;
                        }
                    }
                }
                if (currentIndex === index) {
                    current = true;
                }
                return {
                    item: item ? item : null,
                    group: group,
                    newGroup: newGroup,
                    selected: selected,
                    current: current,
                    index: index,
                    top: index * itemHeight
                };
            },
            _range: function (index) {
                var itemCount = this.itemCount, value = this._values.slice(), items = [], item;
                this._view = {};
                this._currentGroup = false;
                for (var i = index, length = index + itemCount; i < length; i++) {
                    item = this._itemMapper(this.getter(i, index), i, value);
                    if (items[items.length - 1]) {
                        items[items.length - 1].isLastGroupedItem = item.newGroup;
                    }
                    items.push(item);
                    this._view[item.index] = item;
                }
                this._dataView = items;
                return items;
            },
            _getDataItemsCollection: function (scrollTop, lastScrollTop) {
                var items = this._range(this._listIndex(scrollTop, lastScrollTop));
                return {
                    index: items.length ? items[0].index : 0,
                    top: items.length ? items[0].top : 0,
                    items: items
                };
            },
            _listItems: function () {
                var screenHeight = this._screenHeight, options = this.options;
                var theValidator = listValidator(options, screenHeight);
                return $.proxy(function (value, force) {
                    var result = this.result, lastScrollTop = this._lastScrollTop;
                    if (force || !result || !theValidator(result, value, lastScrollTop)) {
                        result = this._getDataItemsCollection(value, lastScrollTop);
                    }
                    this._lastScrollTop = value;
                    this.result = result;
                    return result;
                }, this);
            },
            _whenChanged: function (getter, callback) {
                var current;
                return function (force) {
                    var theNew = getter(force);
                    if (theNew !== current) {
                        current = theNew;
                        callback(theNew, force);
                    }
                };
            },
            _reorderList: function (list, reorder) {
                var that = this;
                var length = list.length;
                var currentOffset = -Infinity;
                reorder = $.proxy(map2(reorder, this.templates), this);
                return function (list2, offset, force) {
                    var diff = offset - currentOffset;
                    var range, range2;
                    if (force || Math.abs(diff) >= length) {
                        range = list;
                        range2 = list2;
                    } else {
                        range = reshift(list, diff);
                        range2 = diff > 0 ? list2.slice(-diff) : list2.slice(0, -diff);
                    }
                    reorder(range, range2, that.bound());
                    currentOffset = offset;
                };
            },
            _bufferSizes: function () {
                var options = this.options;
                return bufferSizes(this._screenHeight, options.listScreens, options.oppositeBuffer);
            },
            _indexConstraint: function (position) {
                var itemCount = this.itemCount, itemHeight = this.options.itemHeight, total = this.dataSource.total();
                return Math.min(Math.max(total - itemCount, 0), Math.max(0, Math.floor(position / itemHeight)));
            },
            _listIndex: function (scrollTop, lastScrollTop) {
                var buffers = this._bufferSizes(), position;
                position = scrollTop - (scrollTop > lastScrollTop ? buffers.down : buffers.up);
                return this._indexConstraint(position);
            },
            _selectable: function () {
                if (this.options.selectable) {
                    this._selectProxy = $.proxy(this, '_clickHandler');
                    this.element.on(CLICK + VIRTUAL_LIST_NS, '.' + VIRTUALITEM, this._selectProxy);
                }
            },
            getElementIndex: function (element) {
                if (!(element instanceof jQuery)) {
                    return undefined;
                }
                return parseInt(element.attr('data-offset-index'), 10);
            },
            _getIndecies: function (candidate) {
                var result = [], data;
                if (typeof candidate === 'function') {
                    data = this.dataSource.flatView();
                    for (var idx = 0; idx < data.length; idx++) {
                        if (candidate(data[idx])) {
                            result.push(idx);
                            break;
                        }
                    }
                }
                if (typeof candidate === 'number') {
                    result.push(candidate);
                }
                var elementIndex = this.getElementIndex(candidate);
                if (!isNaN(elementIndex)) {
                    result.push(elementIndex);
                }
                if (candidate instanceof Array) {
                    result = candidate;
                }
                return result;
            },
            _deselect: function (indices) {
                var removed = [], selectedIndex, dataItem, selectedIndexes = this._selectedIndexes, selectedDataItems = this._selectedDataItems, position = 0, selectable = this.options.selectable, removedindexesCounter = 0, valueGetter = this._valueGetter, item, match, result = null;
                indices = indices.slice();
                if (selectable === true || !indices.length) {
                    for (var idx = 0; idx < selectedIndexes.length; idx++) {
                        if (selectedIndexes[idx] !== undefined) {
                            this._getElementByIndex(selectedIndexes[idx]).removeClass(SELECTED);
                        } else if (selectedDataItems[idx]) {
                            this._getElementByDataItem(selectedDataItems[idx]).removeClass(SELECTED);
                        }
                        removed.push({
                            index: selectedIndexes[idx],
                            position: idx,
                            dataItem: selectedDataItems[idx]
                        });
                    }
                    this._values = [];
                    this._selectedDataItems = [];
                    this._selectedIndexes = [];
                } else if (selectable === 'multiple') {
                    for (var i = 0; i < indices.length; i++) {
                        result = null;
                        position = $.inArray(indices[i], selectedIndexes);
                        dataItem = this.dataItemByIndex(indices[i]);
                        if (position === -1 && dataItem) {
                            for (var j = 0; j < selectedDataItems.length; j++) {
                                match = isPrimitive(dataItem) ? selectedDataItems[j] === dataItem : valueGetter(selectedDataItems[j]) === valueGetter(dataItem);
                                if (match) {
                                    item = this._getElementByIndex(indices[i]);
                                    result = this._deselectSingleItem(item, j, indices[i], removedindexesCounter);
                                }
                            }
                        } else {
                            selectedIndex = selectedIndexes[position];
                            if (selectedIndex !== undefined) {
                                item = this._getElementByIndex(selectedIndex);
                                result = this._deselectSingleItem(item, position, selectedIndex, removedindexesCounter);
                            }
                        }
                        if (result) {
                            indices.splice(i, 1);
                            removed.push(result);
                            removedindexesCounter++;
                            i--;
                        }
                    }
                }
                return {
                    indices: indices,
                    removed: removed
                };
            },
            _deselectSingleItem: function (item, position, selectedIndex, removedindexesCounter) {
                var dataItem;
                if (!item.hasClass('k-state-selected')) {
                    return;
                }
                item.removeClass(SELECTED);
                this._values.splice(position, 1);
                this._selectedIndexes.splice(position, 1);
                dataItem = this._selectedDataItems.splice(position, 1)[0];
                return {
                    index: selectedIndex,
                    position: position + removedindexesCounter,
                    dataItem: dataItem
                };
            },
            _deselectCurrentValues: function (indices) {
                var children = this.element[0].children;
                var value, index, position;
                var values = this._values;
                var removed = [];
                var idx = 0;
                var j;
                if (this.options.selectable !== 'multiple' || !this.isFiltered()) {
                    return [];
                }
                if (indices[0] === -1) {
                    $(children).removeClass('k-state-selected');
                    removed = $.map(this._selectedDataItems.slice(0), function (dataItem, idx) {
                        return {
                            dataItem: dataItem,
                            position: idx
                        };
                    });
                    this._selectedIndexes = [];
                    this._selectedDataItems = [];
                    this._values = [];
                    return removed;
                }
                for (; idx < indices.length; idx++) {
                    position = -1;
                    index = indices[idx];
                    if (this.dataItemByIndex(index)) {
                        value = this._valueGetter(this.dataItemByIndex(index));
                    }
                    for (j = 0; j < values.length; j++) {
                        if (value == values[j]) {
                            position = j;
                            break;
                        }
                    }
                    if (position > -1) {
                        removed.push(this.removeAt(position));
                        $(children[index]).removeClass('k-state-selected');
                    }
                }
                return removed;
            },
            _getSkip: function (index, take) {
                var page = index < take ? 1 : Math.floor(index / take) + 1;
                return (page - 1) * take;
            },
            _select: function (indexes) {
                var that = this, singleSelection = this.options.selectable !== 'multiple', dataSource = this.dataSource, dataItem, oldSkip, take = this.itemCount, valueGetter = this._valueGetter, added = [];
                if (singleSelection) {
                    that._selectedIndexes = [];
                    that._selectedDataItems = [];
                    that._values = [];
                }
                oldSkip = dataSource.skip();
                $.each(indexes, function (_, index) {
                    var skip = that._getSkip(index, take);
                    that.mute(function () {
                        dataSource.range(skip, take);
                        dataItem = that._findDataItem(dataSource.view(), [index - skip]);
                        that._selectedIndexes.push(index);
                        that._selectedDataItems.push(dataItem);
                        that._values.push(isPrimitive(dataItem) ? dataItem : valueGetter(dataItem));
                        added.push({
                            index: index,
                            dataItem: dataItem
                        });
                        that._getElementByIndex(index).addClass(SELECTED);
                        dataSource.range(oldSkip, take);
                    });
                });
                that._values = that._checkValuesOrder(that._values);
                return added;
            },
            _clickHandler: function (e) {
                var item = $(e.currentTarget);
                if (!e.isDefaultPrevented() && item.attr('data-uid')) {
                    this.trigger(CLICK, { item: item });
                }
            },
            _buildValueGetter: function () {
                this._valueGetter = kendo.getter(this.options.dataValueField);
            },
            _calculateGroupPadding: function (height) {
                var firstItem = this.items().first(), groupHeader = this.header, padding = 0;
                if (groupHeader[0] && groupHeader[0].style.display !== 'none') {
                    if (height !== 'auto') {
                        padding = kendo.support.scrollbar();
                    }
                    padding += parseFloat(firstItem.css('border-right-width'), 10) + parseFloat(firstItem.children('.k-group').css('right'), 10);
                    groupHeader.css('padding-right', padding);
                }
            },
            _calculateColumnsHeaderPadding: function () {
                if (this.options.columns && this.options.columns.length) {
                    var isRtl = kendo.support.isRtl(this.wrapper);
                    var scrollbar = kendo.support.scrollbar();
                    var columnsHeader = this.content.parent().parent().find('.k-grid-header');
                    var total = this.dataSource.total();
                    columnsHeader.css(isRtl ? 'padding-left' : 'padding-right', total ? scrollbar : 0);
                }
            }
        });
        kendo.ui.VirtualList = VirtualList;
        kendo.ui.plugin(VirtualList);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.autocomplete', [
        'kendo.list',
        'kendo.mobile.scroller',
        'kendo.virtuallist'
    ], f);
}(function () {
    var __meta__ = {
        id: 'autocomplete',
        name: 'AutoComplete',
        category: 'web',
        description: 'The AutoComplete widget provides suggestions depending on the typed text.It also allows multiple value entries.',
        depends: ['list'],
        features: [
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            },
            {
                id: 'virtualization',
                name: 'VirtualList',
                description: 'Support for virtualization',
                depends: ['virtuallist']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, support = kendo.support, caret = kendo.caret, activeElement = kendo._activeElement, placeholderSupported = support.placeholder, ui = kendo.ui, List = ui.List, keys = kendo.keys, DataSource = kendo.data.DataSource, ARIA_DISABLED = 'aria-disabled', ARIA_READONLY = 'aria-readonly', CHANGE = 'change', DEFAULT = 'k-state-default', DISABLED = 'disabled', READONLY = 'readonly', FOCUSED = 'k-state-focused', SELECTED = 'k-state-selected', STATEDISABLED = 'k-state-disabled', AUTOCOMPLETEVALUE = support.browser.chrome ? 'disabled' : 'off', HOVER = 'k-state-hover', ns = '.kendoAutoComplete', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, proxy = $.proxy;
        function indexOfWordAtCaret(caretIdx, text, separator) {
            return separator ? text.substring(0, caretIdx).split(separator).length - 1 : 0;
        }
        function wordAtCaret(caretIdx, text, separator) {
            return text.split(separator)[indexOfWordAtCaret(caretIdx, text, separator)];
        }
        function replaceWordAtCaret(caretIdx, text, word, separator, defaultSeparator) {
            var words = text.split(separator);
            words.splice(indexOfWordAtCaret(caretIdx, text, separator), 1, word);
            if (separator && words[words.length - 1] !== '') {
                words.push('');
            }
            return words.join(defaultSeparator);
        }
        var AutoComplete = List.extend({
            init: function (element, options) {
                var that = this, wrapper, disabled;
                that.ns = ns;
                options = $.isArray(options) ? { dataSource: options } : options;
                List.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.placeholder = options.placeholder || element.attr('placeholder');
                if (placeholderSupported) {
                    element.attr('placeholder', options.placeholder);
                }
                that._wrapper();
                that._loader();
                that._clearButton();
                that._dataSource();
                that._ignoreCase();
                element[0].type = 'text';
                wrapper = that.wrapper;
                that._popup();
                element.addClass('k-input').on('keydown' + ns, proxy(that._keydown, that)).on('keypress' + ns, proxy(that._keypress, that)).on('input' + ns, proxy(that._search, that)).on('paste' + ns, proxy(that._search, that)).on('focus' + ns, function () {
                    that._prev = that._accessor();
                    that._oldText = that._prev;
                    that._placeholder(false);
                    wrapper.addClass(FOCUSED);
                }).on('focusout' + ns, function () {
                    that._change();
                    that._placeholder();
                    that.close();
                    wrapper.removeClass(FOCUSED);
                }).attr({
                    autocomplete: AUTOCOMPLETEVALUE,
                    role: 'textbox',
                    'aria-haspopup': true
                });
                that._clear.on('click' + ns + ' touchend' + ns, proxy(that._clearValue, that));
                that._enable();
                that._old = that._accessor();
                if (element[0].id) {
                    element.attr('aria-owns', that.ul[0].id);
                }
                that._aria();
                that._placeholder();
                that._initList();
                disabled = $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                }
                that.listView.bind('click', function (e) {
                    e.preventDefault();
                });
                that._resetFocusItemHandler = $.proxy(that._resetFocusItem, that);
                kendo.notify(that);
                that._toggleCloseVisibility();
            },
            options: {
                name: 'AutoComplete',
                enabled: true,
                suggest: false,
                template: '',
                groupTemplate: '#:data#',
                fixedGroupTemplate: '#:data#',
                dataTextField: '',
                minLength: 1,
                enforceMinLength: false,
                delay: 200,
                height: 200,
                filter: 'startswith',
                ignoreCase: true,
                highlightFirst: false,
                separator: null,
                placeholder: '',
                animation: {},
                virtual: false,
                value: null,
                clearButton: true,
                autoWidth: false,
                popup: null
            },
            _dataSource: function () {
                var that = this;
                if (that.dataSource && that._refreshHandler) {
                    that._unbindDataSource();
                } else {
                    that._progressHandler = proxy(that._showBusy, that);
                    that._errorHandler = proxy(that._hideBusy, that);
                }
                that.dataSource = DataSource.create(that.options.dataSource).bind('progress', that._progressHandler).bind('error', that._errorHandler);
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                this.listView.setDataSource(this.dataSource);
            },
            events: [
                'open',
                'close',
                CHANGE,
                'select',
                'filtering',
                'dataBinding',
                'dataBound'
            ],
            setOptions: function (options) {
                var listOptions = this._listOptions(options);
                List.fn.setOptions.call(this, options);
                this.listView.setOptions(listOptions);
                this._accessors();
                this._aria();
                this._clearButton();
            },
            _listOptions: function (options) {
                var listOptions = List.fn._listOptions.call(this, $.extend(options, { skipUpdateOnBind: true }));
                listOptions.dataValueField = listOptions.dataTextField;
                listOptions.selectedItemChange = null;
                return listOptions;
            },
            _editable: function (options) {
                var that = this, element = that.element, wrapper = that.wrapper.off(ns), readonly = options.readonly, disable = options.disable;
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    element.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false).attr(ARIA_READONLY, false);
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    element.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable).attr(ARIA_READONLY, readonly);
                }
            },
            close: function () {
                var that = this;
                var current = that.listView.focus();
                if (current) {
                    current.removeClass(SELECTED);
                }
                that.popup.close();
            },
            destroy: function () {
                var that = this;
                that.element.off(ns);
                that._clear.off(ns);
                that.wrapper.off(ns);
                List.fn.destroy.call(that);
            },
            refresh: function () {
                this.listView.refresh();
            },
            select: function (li) {
                this._select(li);
            },
            search: function (word) {
                var that = this, options = that.options, ignoreCase = options.ignoreCase, separator = that._separator(), length, accentFoldingFiltering = that.dataSource.options.accentFoldingFiltering;
                word = word || that._accessor();
                clearTimeout(that._typingTimeout);
                if (separator) {
                    word = wordAtCaret(caret(that.element)[0], word, separator);
                }
                length = word.length;
                if (!options.enforceMinLength && !length || length >= options.minLength) {
                    that._open = true;
                    that._mute(function () {
                        this.listView.value([]);
                    });
                    that._filterSource({
                        value: ignoreCase ? accentFoldingFiltering ? word.toLocaleLowerCase(accentFoldingFiltering) : word.toLowerCase() : word,
                        operator: options.filter,
                        field: options.dataTextField,
                        ignoreCase: ignoreCase
                    });
                    that.one('close', $.proxy(that._unifySeparators, that));
                }
                that._toggleCloseVisibility();
            },
            suggest: function (word) {
                var that = this, key = that._last, value = that._accessor(), element = that.element[0], caretIdx = caret(element)[0], separator = that._separator(), words = value.split(separator), wordIndex = indexOfWordAtCaret(caretIdx, value, separator), selectionEnd = caretIdx, idx, accentFoldingFiltering = that.dataSource.options.accentFoldingFiltering;
                if (key == keys.BACKSPACE || key == keys.DELETE) {
                    that._last = undefined;
                    return;
                }
                word = word || '';
                if (typeof word !== 'string') {
                    if (word[0]) {
                        word = that.dataSource.view()[List.inArray(word[0], that.ul[0])];
                    }
                    word = word ? that._text(word) : '';
                }
                if (caretIdx <= 0) {
                    caretIdx = (accentFoldingFiltering ? value.toLocaleLowerCase(accentFoldingFiltering) : value.toLowerCase()).indexOf(accentFoldingFiltering ? word.toLocaleLowerCase(accentFoldingFiltering) : word.toLowerCase()) + 1;
                }
                idx = value.substring(0, caretIdx).lastIndexOf(separator);
                idx = idx > -1 ? caretIdx - (idx + separator.length) : caretIdx;
                value = words[wordIndex].substring(0, idx);
                if (word) {
                    word = word.toString();
                    idx = (accentFoldingFiltering ? word.toLocaleLowerCase(accentFoldingFiltering) : word.toLowerCase()).indexOf(accentFoldingFiltering ? value.toLocaleLowerCase(accentFoldingFiltering) : value.toLowerCase());
                    if (idx > -1) {
                        word = word.substring(idx + value.length);
                        selectionEnd = caretIdx + word.length;
                        value += word;
                    }
                    if (separator && words[words.length - 1] !== '') {
                        words.push('');
                    }
                }
                words[wordIndex] = value;
                that._accessor(words.join(separator || ''));
                if (element === activeElement()) {
                    caret(element, caretIdx, selectionEnd);
                }
            },
            value: function (value) {
                if (value !== undefined) {
                    this.listView.value(value);
                    this._accessor(value);
                    this._old = this._accessor();
                    this._oldText = this._accessor();
                } else {
                    return this._accessor();
                }
                this._toggleCloseVisibility();
            },
            _click: function (e) {
                var item = e.item;
                var that = this;
                var element = that.element;
                var dataItem = that.listView.dataItemByIndex(that.listView.getElementIndex(item));
                e.preventDefault();
                that._active = true;
                if (that.trigger('select', {
                        dataItem: dataItem,
                        item: item
                    })) {
                    that.close();
                    return;
                }
                that._oldText = element.val();
                that._select(item).done(function () {
                    that._blur();
                    caret(element, element.val().length);
                });
            },
            _clearText: $.noop,
            _resetFocusItem: function () {
                var index = this.options.highlightFirst ? 0 : -1;
                if (this.options.virtual) {
                    this.listView.scrollTo(0);
                }
                this.listView.focus(index);
            },
            _listBound: function () {
                var that = this;
                var popup = that.popup;
                var options = that.options;
                var data = that.dataSource.flatView();
                var length = data.length;
                var groupsLength = that.dataSource._group.length;
                var isActive = that.element[0] === activeElement();
                var action;
                that._renderFooter();
                that._renderNoData();
                that._toggleNoData(!length);
                that._toggleHeader(!!groupsLength && !!length);
                that._resizePopup();
                popup.position();
                if (length) {
                    if (options.suggest && isActive) {
                        that.suggest(data[0]);
                    }
                }
                if (that._open) {
                    that._open = false;
                    action = that._allowOpening() ? 'open' : 'close';
                    if (that._typingTimeout && !isActive) {
                        action = 'close';
                    }
                    if (length) {
                        that._resetFocusItem();
                        if (options.virtual) {
                            that.popup.unbind('activate', that._resetFocusItemHandler).one('activate', that._resetFocusItemHandler);
                        }
                    }
                    popup[action]();
                    that._typingTimeout = undefined;
                }
                if (that._touchScroller) {
                    that._touchScroller.reset();
                }
                that._hideBusy();
                that._makeUnselectable();
                that.trigger('dataBound');
            },
            _mute: function (callback) {
                this._muted = true;
                callback.call(this);
                this._muted = false;
            },
            _listChange: function () {
                var isActive = this._active || this.element[0] === activeElement();
                if (isActive && !this._muted) {
                    this._selectValue(this.listView.selectedDataItems()[0]);
                }
            },
            _selectValue: function (dataItem) {
                var separator = this._separator();
                var text = '';
                if (dataItem) {
                    text = this._text(dataItem);
                }
                if (text === null) {
                    text = '';
                }
                if (separator) {
                    text = replaceWordAtCaret(caret(this.element)[0], this._accessor(), text, separator, this._defaultSeparator());
                }
                this._prev = text;
                this._accessor(text);
                this._placeholder();
            },
            _unifySeparators: function () {
                this._accessor(this.value().split(this._separator()).join(this._defaultSeparator()));
                return this;
            },
            _preselect: function (value, text) {
                this._inputValue(text);
                this._accessor(value);
                this._old = this.oldText = this._accessor();
                this.listView.setValue(value);
                this._placeholder();
            },
            _change: function () {
                var that = this;
                var value = that._unifySeparators().value();
                var trigger = value !== List.unifyType(that._old, typeof value);
                var valueUpdated = trigger && !that._typing;
                var itemSelected = that._oldText !== value;
                that._old = value;
                that._oldText = value;
                if (valueUpdated || itemSelected) {
                    that.element.trigger(CHANGE);
                }
                if (trigger) {
                    that.trigger(CHANGE);
                }
                that.typing = false;
                that._toggleCloseVisibility();
            },
            _accessor: function (value) {
                var that = this, element = that.element[0];
                if (value !== undefined) {
                    element.value = value === null ? '' : value;
                    that._placeholder();
                } else {
                    value = element.value;
                    if (element.className.indexOf('k-readonly') > -1) {
                        if (value === that.options.placeholder) {
                            return '';
                        } else {
                            return value;
                        }
                    }
                    return value;
                }
            },
            _keydown: function (e) {
                var that = this;
                var key = e.keyCode;
                var listView = that.listView;
                var visible = that.popup.visible();
                var current = listView.focus();
                that._last = key;
                if (key === keys.DOWN) {
                    if (visible) {
                        this._move(current ? 'focusNext' : 'focusFirst');
                    } else if (that.value()) {
                        that._filterSource({
                            value: that.ignoreCase ? that.value().toLowerCase() : that.value(),
                            operator: that.options.filter,
                            field: that.options.dataTextField,
                            ignoreCase: that.ignoreCase
                        }).done(function () {
                            if (that._allowOpening()) {
                                that._resetFocusItem();
                                that.popup.open();
                            }
                        });
                    }
                    e.preventDefault();
                } else if (key === keys.UP) {
                    if (visible) {
                        this._move(current ? 'focusPrev' : 'focusLast');
                    }
                    e.preventDefault();
                } else if (key === keys.HOME) {
                    this._move('focusFirst');
                } else if (key === keys.END) {
                    this._move('focusLast');
                } else if (key === keys.ENTER || key === keys.TAB) {
                    if (key === keys.ENTER && visible) {
                        e.preventDefault();
                    }
                    if (visible && current) {
                        var dataItem = listView.dataItemByIndex(listView.getElementIndex(current));
                        if (that.trigger('select', {
                                dataItem: dataItem,
                                item: current
                            })) {
                            return;
                        }
                        this._select(current);
                    }
                    this._blur();
                } else if (key === keys.ESC) {
                    if (visible) {
                        e.preventDefault();
                    } else {
                        that._clearValue();
                    }
                    that.close();
                } else if (that.popup.visible() && (key === keys.PAGEDOWN || key === keys.PAGEUP)) {
                    e.preventDefault();
                    var direction = key === keys.PAGEDOWN ? 1 : -1;
                    listView.scrollWith(direction * listView.screenHeight());
                } else {
                    that.popup._hovered = true;
                    that._search();
                }
            },
            _keypress: function () {
                this._oldText = this.element.val();
                this._typing = true;
            },
            _move: function (action) {
                this.listView[action]();
                if (this.options.suggest) {
                    this.suggest(this.listView.focus());
                }
            },
            _hideBusy: function () {
                var that = this;
                clearTimeout(that._busy);
                that._loading.hide();
                that.element.attr('aria-busy', false);
                that._busy = null;
                that._showClear();
            },
            _showBusy: function () {
                var that = this;
                if (that._busy) {
                    return;
                }
                that._busy = setTimeout(function () {
                    that.element.attr('aria-busy', true);
                    that._loading.show();
                    that._hideClear();
                }, 100);
            },
            _placeholder: function (show) {
                if (placeholderSupported) {
                    return;
                }
                var that = this, element = that.element, placeholder = that.options.placeholder, value;
                if (placeholder) {
                    value = element.val();
                    if (show === undefined) {
                        show = !value;
                    }
                    if (!show) {
                        if (value !== placeholder) {
                            placeholder = value;
                        } else {
                            placeholder = '';
                        }
                    }
                    if (value === that._old && !show) {
                        return;
                    }
                    element.toggleClass('k-readonly', show).val(placeholder);
                    if (!placeholder && element[0] === document.activeElement) {
                        caret(element[0], 0, 0);
                    }
                }
            },
            _separator: function () {
                var separator = this.options.separator;
                if (separator instanceof Array) {
                    return new RegExp(separator.join('|'), 'gi');
                }
                return separator;
            },
            _defaultSeparator: function () {
                var separator = this.options.separator;
                if (separator instanceof Array) {
                    return separator[0];
                }
                return separator;
            },
            _inputValue: function () {
                return this.element.val();
            },
            _search: function () {
                var that = this;
                clearTimeout(that._typingTimeout);
                that._typingTimeout = setTimeout(function () {
                    if (that._prev !== that._accessor()) {
                        that._prev = that._accessor();
                        that.search();
                    }
                }, that.options.delay);
            },
            _select: function (candidate) {
                var that = this;
                that._active = true;
                return that.listView.select(candidate).done(function () {
                    that._active = false;
                });
            },
            _loader: function () {
                this._loading = $('<span class="k-icon k-i-loading" style="display:none"></span>').insertAfter(this.element);
            },
            _clearButton: function () {
                List.fn._clearButton.call(this);
                if (this.options.clearButton) {
                    this._clear.insertAfter(this.element);
                    this.wrapper.addClass('k-autocomplete-clearable');
                }
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _toggleCloseVisibility: function () {
                if (this.value()) {
                    this._showClear();
                } else {
                    this._hideClear();
                }
            },
            _wrapper: function () {
                var that = this, element = that.element, DOMelement = element[0], wrapper;
                wrapper = element.parent();
                if (!wrapper.is('span.k-widget')) {
                    wrapper = element.wrap('<span />').parent();
                }
                wrapper.attr('tabindex', -1);
                wrapper.attr('role', 'presentation');
                wrapper[0].style.cssText = DOMelement.style.cssText;
                element.css({
                    width: '',
                    height: DOMelement.style.height
                });
                that._focused = that.element;
                that.wrapper = wrapper.addClass('k-widget k-autocomplete').addClass(DOMelement.className);
                that._inputWrapper = $(wrapper[0]);
            }
        });
        ui.plugin(AutoComplete);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dropdownlist', [
        'kendo.list',
        'kendo.mobile.scroller',
        'kendo.virtuallist'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dropdownlist',
        name: 'DropDownList',
        category: 'web',
        description: 'The DropDownList widget displays a list of values and allows the selection of a single value from the list.',
        depends: ['list'],
        features: [
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            },
            {
                id: 'virtualization',
                name: 'VirtualList',
                description: 'Support for virtualization',
                depends: ['virtuallist']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, List = ui.List, Select = ui.Select, support = kendo.support, activeElement = kendo._activeElement, ObservableObject = kendo.data.ObservableObject, keys = kendo.keys, ns = '.kendoDropDownList', nsFocusEvent = ns + 'FocusEvent', DISABLED = 'disabled', READONLY = 'readonly', CHANGE = 'change', FOCUSED = 'k-state-focused', DEFAULT = 'k-state-default', STATEDISABLED = 'k-state-disabled', ARIA_DISABLED = 'aria-disabled', CLICKEVENTS = 'click' + ns + ' touchend' + ns, HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, TABINDEX = 'tabindex', STATE_FILTER = 'filter', STATE_ACCEPT = 'accept', MSG_INVALID_OPTION_LABEL = 'The `optionLabel` option is not valid due to missing fields. Define a custom optionLabel as shown here http://docs.telerik.com/kendo-ui/api/javascript/ui/dropdownlist#configuration-optionLabel', proxy = $.proxy;
        var DropDownList = Select.extend({
            init: function (element, options) {
                var that = this;
                var index = options && options.index;
                var optionLabel, text, disabled;
                that.ns = ns;
                options = $.isArray(options) ? { dataSource: options } : options;
                Select.fn.init.call(that, element, options);
                options = that.options;
                element = that.element.on('focus' + ns, proxy(that._focusHandler, that));
                that._focusInputHandler = $.proxy(that._focusInput, that);
                that.optionLabel = $();
                that._optionLabel();
                that._inputTemplate();
                that._reset();
                that._prev = '';
                that._word = '';
                that._wrapper();
                that._tabindex();
                that.wrapper.data(TABINDEX, that.wrapper.attr(TABINDEX));
                that._span();
                that._popup();
                that._mobile();
                that._dataSource();
                that._ignoreCase();
                that._filterHeader();
                that._aria();
                that.wrapper.attr('aria-live', 'polite');
                that._enable();
                that._attachFocusHandlers();
                that._oldIndex = that.selectedIndex = -1;
                if (index !== undefined) {
                    options.index = index;
                }
                that._initialIndex = options.index;
                that.requireValueMapper(that.options);
                that._initList();
                that._cascade();
                that.one('set', function (e) {
                    if (!e.sender.listView.bound() && that.hasOptionLabel()) {
                        that._textAccessor(that._optionLabelText());
                    }
                });
                if (options.autoBind) {
                    that.dataSource.fetch();
                } else if (that.selectedIndex === -1) {
                    text = options.text || '';
                    if (!text) {
                        optionLabel = options.optionLabel;
                        if (optionLabel && options.index === 0) {
                            text = optionLabel;
                        } else if (that._isSelect) {
                            text = element.children(':selected').text();
                        }
                    }
                    that._textAccessor(text);
                }
                disabled = $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                }
                that.listView.bind('click', function (e) {
                    e.preventDefault();
                });
                kendo.notify(that);
            },
            options: {
                name: 'DropDownList',
                enabled: true,
                autoBind: true,
                index: 0,
                text: null,
                value: null,
                delay: 500,
                height: 200,
                dataTextField: '',
                dataValueField: '',
                optionLabel: '',
                cascadeFrom: '',
                cascadeFromField: '',
                cascadeFromParentField: '',
                ignoreCase: true,
                animation: {},
                filter: 'none',
                minLength: 1,
                enforceMinLength: false,
                virtual: false,
                template: null,
                valueTemplate: null,
                optionLabelTemplate: null,
                groupTemplate: '#:data#',
                fixedGroupTemplate: '#:data#',
                autoWidth: false,
                popup: null
            },
            events: [
                'open',
                'close',
                CHANGE,
                'select',
                'filtering',
                'dataBinding',
                'dataBound',
                'cascade',
                'set'
            ],
            setOptions: function (options) {
                Select.fn.setOptions.call(this, options);
                this.listView.setOptions(this._listOptions(options));
                this._optionLabel();
                this._inputTemplate();
                this._accessors();
                this._filterHeader();
                this._enable();
                this._aria();
                if (!this.value() && this.hasOptionLabel()) {
                    this.select(0);
                }
            },
            destroy: function () {
                var that = this;
                Select.fn.destroy.call(that);
                that.wrapper.off(ns);
                that.wrapper.off(nsFocusEvent);
                that.element.off(ns);
                that._inputWrapper.off(ns);
                that._arrow.off();
                that._arrow = null;
                that._arrowIcon = null;
                that.optionLabel.off();
                if (that.filterInput) {
                    that.filterInput.off(nsFocusEvent);
                }
            },
            open: function () {
                var that = this;
                var isFiltered = that.dataSource.filter() ? that.dataSource.filter().filters.length > 0 : false;
                if (that.popup.visible()) {
                    return;
                }
                if (!that.listView.bound() || that._state === STATE_ACCEPT) {
                    that._open = true;
                    that._state = 'rebind';
                    if (that.filterInput) {
                        that.filterInput.val('');
                        that._prev = '';
                    }
                    if (that.filterInput && that.options.minLength !== 1 && !isFiltered) {
                        that.refresh();
                        that.popup.one('activate', that._focusInputHandler);
                        that.popup.open();
                        that._resizeFilterInput();
                    } else {
                        that._filterSource();
                    }
                } else if (that._allowOpening()) {
                    that._focusFilter = true;
                    that.popup.one('activate', that._focusInputHandler);
                    that.popup._hovered = true;
                    that.popup.open();
                    that._resizeFilterInput();
                    that._focusItem();
                }
            },
            _focusInput: function () {
                this._focusElement(this.filterInput);
            },
            _resizeFilterInput: function () {
                var filterInput = this.filterInput;
                var originalPrevent = this._prevent;
                if (!filterInput) {
                    return;
                }
                var isInputActive = this.filterInput[0] === activeElement();
                var caret = kendo.caret(this.filterInput[0])[0];
                this._prevent = true;
                filterInput.css('display', 'none').css('width', this.popup.element.css('width')).css('display', 'inline-block');
                if (isInputActive) {
                    filterInput.focus();
                    kendo.caret(filterInput[0], caret);
                }
                this._prevent = originalPrevent;
            },
            _allowOpening: function () {
                return this.hasOptionLabel() || this.filterInput || Select.fn._allowOpening.call(this);
            },
            toggle: function (toggle) {
                this._toggle(toggle, true);
            },
            current: function (candidate) {
                var current;
                if (candidate === undefined) {
                    current = this.listView.focus();
                    if (!current && this.selectedIndex === 0 && this.hasOptionLabel()) {
                        return this.optionLabel;
                    }
                    return current;
                }
                this._focus(candidate);
            },
            dataItem: function (index) {
                var that = this;
                var dataItem = null;
                if (index === null) {
                    return index;
                }
                if (index === undefined) {
                    dataItem = that.listView.selectedDataItems()[0];
                } else {
                    if (typeof index !== 'number') {
                        if (that.options.virtual) {
                            return that.dataSource.getByUid($(index).data('uid'));
                        }
                        if (index.hasClass('k-list-optionlabel')) {
                            index = -1;
                        } else {
                            index = $(that.items()).index(index);
                        }
                    } else if (that.hasOptionLabel()) {
                        index -= 1;
                    }
                    dataItem = that.dataSource.flatView()[index];
                }
                if (!dataItem) {
                    dataItem = that._optionLabelDataItem();
                }
                return dataItem;
            },
            refresh: function () {
                this.listView.refresh();
            },
            text: function (text) {
                var that = this;
                var loweredText;
                var ignoreCase = that.options.ignoreCase;
                text = text === null ? '' : text;
                if (text !== undefined) {
                    if (typeof text !== 'string') {
                        that._textAccessor(text);
                        return;
                    }
                    loweredText = ignoreCase ? text.toLowerCase() : text;
                    that._select(function (data) {
                        data = that._text(data);
                        if (ignoreCase) {
                            data = (data + '').toLowerCase();
                        }
                        return data === loweredText;
                    }).done(function () {
                        that._textAccessor(that.dataItem() || text);
                    });
                } else {
                    return that._textAccessor();
                }
            },
            _clearFilter: function () {
                $(this.filterInput).val('');
                Select.fn._clearFilter.call(this);
            },
            value: function (value) {
                var that = this;
                var listView = that.listView;
                var dataSource = that.dataSource;
                if (value === undefined) {
                    value = that._accessor() || that.listView.value()[0];
                    return value === undefined || value === null ? '' : value;
                }
                that.requireValueMapper(that.options, value);
                if (value || !that.hasOptionLabel()) {
                    that._initialIndex = null;
                }
                this.trigger('set', { value: value });
                if (that._request && that.options.cascadeFrom && that.listView.bound()) {
                    if (that._valueSetter) {
                        dataSource.unbind(CHANGE, that._valueSetter);
                    }
                    that._valueSetter = proxy(function () {
                        that.value(value);
                    }, that);
                    dataSource.one(CHANGE, that._valueSetter);
                    return;
                }
                if (that._isFilterEnabled() && listView.bound() && listView.isFiltered()) {
                    that._clearFilter();
                } else {
                    that._fetchData();
                }
                listView.value(value).done(function () {
                    that._old = that._valueBeforeCascade = that._accessor();
                    that._oldIndex = that.selectedIndex;
                });
            },
            hasOptionLabel: function () {
                return this.optionLabel && !!this.optionLabel[0];
            },
            _optionLabel: function () {
                var that = this;
                var options = that.options;
                var optionLabel = options.optionLabel;
                var template = options.optionLabelTemplate;
                if (!optionLabel) {
                    that.optionLabel.off().remove();
                    that.optionLabel = $();
                    return;
                }
                if (!template) {
                    template = '#:';
                    if (typeof optionLabel === 'string') {
                        template += 'data';
                    } else {
                        template += kendo.expr(options.dataTextField, 'data');
                    }
                    template += '#';
                }
                if (typeof template !== 'function') {
                    template = kendo.template(template);
                }
                that.optionLabelTemplate = template;
                if (!that.hasOptionLabel()) {
                    that.optionLabel = $('<div class="k-list-optionlabel"></div>').prependTo(that.list);
                }
                that.optionLabel.html(template(optionLabel)).off().on(CLICKEVENTS, proxy(that._click, that)).on(HOVEREVENTS, that._toggleHover);
                that.angular('compile', function () {
                    return {
                        elements: that.optionLabel,
                        data: [{ dataItem: that._optionLabelDataItem() }]
                    };
                });
            },
            _optionLabelText: function () {
                var optionLabel = this.options.optionLabel;
                return typeof optionLabel === 'string' ? optionLabel : this._text(optionLabel);
            },
            _optionLabelDataItem: function () {
                var that = this;
                var optionLabel = that.options.optionLabel;
                if (that.hasOptionLabel()) {
                    return $.isPlainObject(optionLabel) ? new ObservableObject(optionLabel) : that._assignInstance(that._optionLabelText(), '');
                }
                return undefined;
            },
            _buildOptions: function (data) {
                var that = this;
                if (!that._isSelect) {
                    return;
                }
                var value = that.listView.value()[0];
                var optionLabel = that._optionLabelDataItem();
                var optionLabelValue = optionLabel && that._value(optionLabel);
                if (value === undefined || value === null) {
                    value = '';
                }
                if (optionLabel) {
                    if (optionLabelValue === undefined || optionLabelValue === null) {
                        optionLabelValue = '';
                    }
                    optionLabel = '<option value="' + optionLabelValue + '">' + that._text(optionLabel) + '</option>';
                }
                that._options(data, optionLabel, value);
                if (value !== List.unifyType(that._accessor(), typeof value)) {
                    that._customOption = null;
                    that._custom(value);
                }
            },
            _listBound: function () {
                var that = this;
                var initialIndex = that._initialIndex;
                var filtered = that._state === STATE_FILTER;
                var data = that.dataSource.flatView();
                var dataItem;
                that._presetValue = false;
                that._renderFooter();
                that._renderNoData();
                that._toggleNoData(!data.length);
                that._resizePopup(true);
                that.popup.position();
                that._buildOptions(data);
                that._makeUnselectable();
                if (!filtered) {
                    if (that._open) {
                        that.toggle(that._allowOpening());
                    }
                    that._open = false;
                    if (!that._fetch) {
                        if (data.length) {
                            if (!that.listView.value().length && initialIndex > -1 && initialIndex !== null) {
                                that.select(initialIndex);
                            }
                            that._initialIndex = null;
                            dataItem = that.listView.selectedDataItems()[0];
                            if (dataItem && that.text() !== that._text(dataItem)) {
                                that._selectValue(dataItem);
                            }
                        } else if (that._textAccessor() !== that._optionLabelText()) {
                            that.listView.value('');
                            that._selectValue(null);
                            that._oldIndex = that.selectedIndex;
                        }
                    }
                }
                that._hideBusy();
                that.trigger('dataBound');
            },
            _listChange: function () {
                this._selectValue(this.listView.selectedDataItems()[0]);
                if (this._presetValue || this._old && this._oldIndex === -1) {
                    this._oldIndex = this.selectedIndex;
                }
            },
            _filterPaste: function () {
                this._search();
            },
            _attachFocusHandlers: function () {
                var that = this;
                var wrapper = that.wrapper;
                wrapper.on('focusin' + nsFocusEvent, proxy(that._focusinHandler, that)).on('focusout' + nsFocusEvent, proxy(that._focusoutHandler, that));
                if (that.filterInput) {
                    that.filterInput.on('focusin' + nsFocusEvent, proxy(that._focusinHandler, that)).on('focusout' + nsFocusEvent, proxy(that._focusoutHandler, that));
                }
            },
            _focusHandler: function () {
                this.wrapper.focus();
            },
            _focusinHandler: function () {
                this._inputWrapper.addClass(FOCUSED);
                this._prevent = false;
            },
            _focusoutHandler: function () {
                var that = this;
                var isIFrame = window.self !== window.top;
                if (!that._prevent) {
                    clearTimeout(that._typingTimeout);
                    if (support.mobileOS.ios && isIFrame) {
                        that._change();
                    } else {
                        that._blur();
                    }
                    that._inputWrapper.removeClass(FOCUSED);
                    that._prevent = true;
                    that._open = false;
                    that.element.blur();
                }
            },
            _wrapperMousedown: function () {
                this._prevent = !!this.filterInput;
            },
            _wrapperClick: function (e) {
                e.preventDefault();
                this.popup.unbind('activate', this._focusInputHandler);
                this._focused = this.wrapper;
                this._prevent = false;
                this._toggle();
            },
            _editable: function (options) {
                var that = this;
                var element = that.element;
                var disable = options.disable;
                var readonly = options.readonly;
                var wrapper = that.wrapper.add(that.filterInput).off(ns);
                var dropDownWrapper = that._inputWrapper.off(HOVEREVENTS);
                if (!readonly && !disable) {
                    element.removeAttr(DISABLED).removeAttr(READONLY);
                    dropDownWrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    wrapper.attr(TABINDEX, wrapper.data(TABINDEX)).attr(ARIA_DISABLED, false).on('keydown' + ns, proxy(that._keydown, that)).on(kendo.support.mousedown + ns, proxy(that._wrapperMousedown, that)).on('paste' + ns, proxy(that._filterPaste, that));
                    that.wrapper.on('click' + ns, proxy(that._wrapperClick, that));
                    if (!that.filterInput) {
                        wrapper.on('keypress' + ns, proxy(that._keypress, that));
                    } else {
                        wrapper.on('input' + ns, proxy(that._search, that));
                    }
                } else if (disable) {
                    wrapper.removeAttr(TABINDEX);
                    dropDownWrapper.addClass(STATEDISABLED).removeClass(DEFAULT);
                } else {
                    dropDownWrapper.addClass(DEFAULT).removeClass(STATEDISABLED);
                }
                element.attr(DISABLED, disable).attr(READONLY, readonly);
                wrapper.attr(ARIA_DISABLED, disable);
            },
            _keydown: function (e) {
                var that = this;
                var key = e.keyCode;
                var altKey = e.altKey;
                var isInputActive;
                var handled;
                var isPopupVisible = that.popup.visible();
                if (that.filterInput) {
                    isInputActive = that.filterInput[0] === activeElement();
                }
                if (key === keys.LEFT) {
                    key = keys.UP;
                    handled = true;
                } else if (key === keys.RIGHT) {
                    key = keys.DOWN;
                    handled = true;
                }
                if (handled && isInputActive) {
                    return;
                }
                e.keyCode = key;
                if (altKey && key === keys.UP || key === keys.ESC) {
                    that._focusElement(that.wrapper);
                }
                if (that._state === STATE_FILTER && key === keys.ESC) {
                    that._clearFilter();
                    that._open = false;
                    that._state = STATE_ACCEPT;
                }
                if (key === keys.ENTER && that._typingTimeout && that.filterInput && isPopupVisible) {
                    e.preventDefault();
                    return;
                }
                if (key === keys.SPACEBAR && !isInputActive) {
                    that.toggle(!isPopupVisible);
                    e.preventDefault();
                }
                handled = that._move(e);
                if (handled) {
                    return;
                }
                if (!isPopupVisible || !that.filterInput) {
                    var current = that._focus();
                    if (key === keys.HOME) {
                        handled = true;
                        that._firstItem();
                    } else if (key === keys.END) {
                        handled = true;
                        that._lastItem();
                    }
                    if (handled) {
                        if (that.trigger('select', {
                                dataItem: that._getElementDataItem(that._focus()),
                                item: that._focus()
                            })) {
                            that._focus(current);
                            return;
                        }
                        that._select(that._focus(), true).done(function () {
                            if (!isPopupVisible) {
                                that._blur();
                            }
                        });
                        e.preventDefault();
                    }
                }
                if (!altKey && !handled && that.filterInput) {
                    that._search();
                }
            },
            _matchText: function (text, word) {
                var ignoreCase = this.options.ignoreCase;
                if (text === undefined || text === null) {
                    return false;
                }
                text = text + '';
                if (ignoreCase) {
                    text = text.toLowerCase();
                }
                return text.indexOf(word) === 0;
            },
            _shuffleData: function (data, splitIndex) {
                var optionDataItem = this._optionLabelDataItem();
                if (optionDataItem) {
                    data = [optionDataItem].concat(data);
                }
                return data.slice(splitIndex).concat(data.slice(0, splitIndex));
            },
            _selectNext: function () {
                var that = this;
                var data = that.dataSource.flatView();
                var dataLength = data.length + (that.hasOptionLabel() ? 1 : 0);
                var isInLoop = sameCharsOnly(that._word, that._last);
                var startIndex = that.selectedIndex;
                var oldFocusedItem;
                var text;
                if (startIndex === -1) {
                    startIndex = 0;
                } else {
                    startIndex += isInLoop ? 1 : 0;
                    startIndex = normalizeIndex(startIndex, dataLength);
                }
                data = data.toJSON ? data.toJSON() : data.slice();
                data = that._shuffleData(data, startIndex);
                for (var idx = 0; idx < dataLength; idx++) {
                    text = that._text(data[idx]);
                    if (isInLoop && that._matchText(text, that._last)) {
                        break;
                    } else if (that._matchText(text, that._word)) {
                        break;
                    }
                }
                if (idx !== dataLength) {
                    oldFocusedItem = that._focus();
                    that._select(normalizeIndex(startIndex + idx, dataLength)).done(function () {
                        var done = function () {
                            if (!that.popup.visible()) {
                                that._change();
                            }
                        };
                        if (that.trigger('select', {
                                dataItem: that._getElementDataItem(that._focus()),
                                item: that._focus()
                            })) {
                            that._select(oldFocusedItem).done(done);
                        } else {
                            done();
                        }
                    });
                }
            },
            _keypress: function (e) {
                var that = this;
                if (e.which === 0 || e.keyCode === kendo.keys.ENTER) {
                    return;
                }
                var character = String.fromCharCode(e.charCode || e.keyCode);
                if (that.options.ignoreCase) {
                    character = character.toLowerCase();
                }
                if (character === ' ') {
                    e.preventDefault();
                }
                that._word += character;
                that._last = character;
                that._search();
            },
            _popupOpen: function () {
                var popup = this.popup;
                popup.wrapper = kendo.wrap(popup.element);
                if (popup.element.closest('.km-root')[0]) {
                    popup.wrapper.addClass('km-popup km-widget');
                    this.wrapper.addClass('km-widget');
                }
            },
            _popup: function () {
                Select.fn._popup.call(this);
                this.popup.one('open', proxy(this._popupOpen, this));
            },
            _getElementDataItem: function (element) {
                if (!element || !element[0]) {
                    return null;
                }
                if (element[0] === this.optionLabel[0]) {
                    return this._optionLabelDataItem();
                }
                return this.listView.dataItemByIndex(this.listView.getElementIndex(element));
            },
            _click: function (e) {
                var that = this;
                var item = e.item || $(e.currentTarget);
                e.preventDefault();
                if (that.trigger('select', {
                        dataItem: that._getElementDataItem(item),
                        item: item
                    })) {
                    that.close();
                    return;
                }
                that._userTriggered = true;
                that._select(item).done(function () {
                    that._focusElement(that.wrapper);
                    that._blur();
                });
            },
            _focusElement: function (element) {
                var active = activeElement();
                var wrapper = this.wrapper;
                var filterInput = this.filterInput;
                var compareElement = element === filterInput ? wrapper : filterInput;
                var touchEnabled = support.mobileOS && (support.touch || support.MSPointers || support.pointers);
                if (filterInput && filterInput[0] === element[0] && touchEnabled) {
                    return;
                }
                if (filterInput && (compareElement[0] === active || this._focusFilter)) {
                    this._focusFilter = false;
                    this._prevent = true;
                    this._focused = element.focus();
                }
            },
            _searchByWord: function (word) {
                if (!word) {
                    return;
                }
                var that = this;
                var ignoreCase = that.options.ignoreCase;
                if (ignoreCase) {
                    word = word.toLowerCase();
                }
                that._select(function (dataItem) {
                    return that._matchText(that._text(dataItem), word);
                });
            },
            _inputValue: function () {
                return this.text();
            },
            _search: function () {
                var that = this;
                var dataSource = that.dataSource;
                clearTimeout(that._typingTimeout);
                if (that._isFilterEnabled()) {
                    that._typingTimeout = setTimeout(function () {
                        var value = that.filterInput.val();
                        if (that._prev !== value) {
                            that._prev = value;
                            that.search(value);
                            that._resizeFilterInput();
                        }
                        that._typingTimeout = null;
                    }, that.options.delay);
                } else {
                    that._typingTimeout = setTimeout(function () {
                        that._word = '';
                    }, that.options.delay);
                    if (!that.listView.bound()) {
                        dataSource.fetch().done(function () {
                            that._selectNext();
                        });
                        return;
                    }
                    that._selectNext();
                }
            },
            _get: function (candidate) {
                var data, found, idx;
                var isFunction = typeof candidate === 'function';
                var jQueryCandidate = !isFunction ? $(candidate) : $();
                if (this.hasOptionLabel()) {
                    if (typeof candidate === 'number') {
                        if (candidate > -1) {
                            candidate -= 1;
                        }
                    } else if (jQueryCandidate.hasClass('k-list-optionlabel')) {
                        candidate = -1;
                    }
                }
                if (isFunction) {
                    data = this.dataSource.flatView();
                    for (idx = 0; idx < data.length; idx++) {
                        if (candidate(data[idx])) {
                            candidate = idx;
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        candidate = -1;
                    }
                }
                return candidate;
            },
            _firstItem: function () {
                if (this.hasOptionLabel()) {
                    this._focus(this.optionLabel);
                } else {
                    this.listView.focusFirst();
                }
            },
            _lastItem: function () {
                this._resetOptionLabel();
                this.listView.focusLast();
            },
            _nextItem: function () {
                if (this.optionLabel.hasClass('k-state-focused')) {
                    this._resetOptionLabel();
                    this.listView.focusFirst();
                } else {
                    this.listView.focusNext();
                }
            },
            _prevItem: function () {
                if (this.optionLabel.hasClass('k-state-focused')) {
                    return;
                }
                this.listView.focusPrev();
                if (!this.listView.focus()) {
                    this._focus(this.optionLabel);
                }
            },
            _focusItem: function () {
                var options = this.options;
                var listView = this.listView;
                var focusedItem = listView.focus();
                var index = listView.select();
                index = index[index.length - 1];
                if (index === undefined && options.highlightFirst && !focusedItem) {
                    index = 0;
                }
                if (index !== undefined) {
                    listView.focus(index);
                } else {
                    if (options.optionLabel && (!options.virtual || options.virtual.mapValueTo !== 'dataItem')) {
                        this._focus(this.optionLabel);
                        this._select(this.optionLabel);
                        this.listView.content.scrollTop(0);
                    } else {
                        listView.scrollToIndex(0);
                    }
                }
            },
            _resetOptionLabel: function (additionalClass) {
                this.optionLabel.removeClass('k-state-focused' + (additionalClass || '')).removeAttr('id');
            },
            _focus: function (candidate) {
                var listView = this.listView;
                var optionLabel = this.optionLabel;
                if (candidate === undefined) {
                    candidate = listView.focus();
                    if (!candidate && optionLabel.hasClass('k-state-focused')) {
                        candidate = optionLabel;
                    }
                    return candidate;
                }
                this._resetOptionLabel();
                candidate = this._get(candidate);
                listView.focus(candidate);
                if (candidate === -1) {
                    optionLabel.addClass('k-state-focused').attr('id', listView._optionID);
                    this._focused.add(this.filterInput).removeAttr('aria-activedescendant').attr('aria-activedescendant', listView._optionID);
                }
            },
            _select: function (candidate, keepState) {
                var that = this;
                candidate = that._get(candidate);
                return that.listView.select(candidate).done(function () {
                    if (!keepState && that._state === STATE_FILTER) {
                        that._state = STATE_ACCEPT;
                    }
                    if (candidate === -1) {
                        that._selectValue(null);
                    }
                });
            },
            _selectValue: function (dataItem) {
                var that = this;
                var optionLabel = that.options.optionLabel;
                var idx = that.listView.select();
                var value = '';
                var text = '';
                idx = idx[idx.length - 1];
                if (idx === undefined) {
                    idx = -1;
                }
                this._resetOptionLabel(' k-state-selected');
                if (dataItem || dataItem === 0) {
                    text = dataItem;
                    value = that._dataValue(dataItem);
                    if (optionLabel) {
                        idx += 1;
                    }
                } else if (optionLabel) {
                    that._focus(that.optionLabel.addClass('k-state-selected'));
                    text = that._optionLabelText();
                    if (typeof optionLabel === 'string') {
                        value = '';
                    } else {
                        value = that._value(optionLabel);
                    }
                    idx = 0;
                }
                that.selectedIndex = idx;
                if (value === null) {
                    value = '';
                }
                that._textAccessor(text);
                that._accessor(value, idx);
                that._triggerCascade();
            },
            _mobile: function () {
                var that = this, popup = that.popup, mobileOS = support.mobileOS, root = popup.element.parents('.km-root').eq(0);
                if (root.length && mobileOS) {
                    popup.options.animation.open.effects = mobileOS.android || mobileOS.meego ? 'fadeIn' : mobileOS.ios || mobileOS.wp ? 'slideIn:up' : popup.options.animation.open.effects;
                }
            },
            _filterHeader: function () {
                var icon;
                if (this.filterInput) {
                    this.filterInput.off(ns).parent().remove();
                    this.filterInput = null;
                }
                if (this._isFilterEnabled()) {
                    icon = '<span class="k-icon k-i-zoom"></span>';
                    this.filterInput = $('<input class="k-textbox"/>').attr({
                        placeholder: this.element.attr('placeholder'),
                        title: this.element.attr('title'),
                        role: 'listbox',
                        'aria-haspopup': true,
                        'aria-expanded': false
                    });
                    this.list.prepend($('<span class="k-list-filter" />').append(this.filterInput.add(icon)));
                }
            },
            _span: function () {
                var that = this, wrapper = that.wrapper, SELECTOR = 'span.k-input', span;
                span = wrapper.find(SELECTOR);
                if (!span[0]) {
                    wrapper.append('<span unselectable="on" class="k-dropdown-wrap k-state-default"><span unselectable="on" class="k-input">&nbsp;</span><span unselectable="on" class="k-select" aria-label="select"><span class="k-icon k-i-arrow-60-down"></span></span></span>').append(that.element);
                    span = wrapper.find(SELECTOR);
                }
                that.span = span;
                that._inputWrapper = $(wrapper[0].firstChild);
                that._arrow = wrapper.find('.k-select');
                that._arrowIcon = that._arrow.find('.k-icon');
            },
            _wrapper: function () {
                var that = this, element = that.element, DOMelement = element[0], wrapper;
                wrapper = element.parent();
                if (!wrapper.is('span.k-widget')) {
                    wrapper = element.wrap('<span />').parent();
                    wrapper[0].style.cssText = DOMelement.style.cssText;
                    wrapper[0].title = DOMelement.title;
                }
                that._focused = that.wrapper = wrapper.addClass('k-widget k-dropdown').addClass(DOMelement.className).css('display', '').attr({
                    accesskey: element.attr('accesskey'),
                    unselectable: 'on',
                    role: 'listbox',
                    'aria-haspopup': true,
                    'aria-expanded': false
                });
                element.hide().removeAttr('accesskey');
            },
            _clearSelection: function (parent) {
                this.select(parent.value() ? 0 : -1);
            },
            _inputTemplate: function () {
                var that = this, template = that.options.valueTemplate;
                if (!template) {
                    template = $.proxy(kendo.template('#:this._text(data)#', { useWithBlock: false }), that);
                } else {
                    template = kendo.template(template);
                }
                that.valueTemplate = template;
                if (that.hasOptionLabel() && !that.options.optionLabelTemplate) {
                    try {
                        that.valueTemplate(that._optionLabelDataItem());
                    } catch (e) {
                        throw new Error(MSG_INVALID_OPTION_LABEL);
                    }
                }
            },
            _textAccessor: function (text) {
                var dataItem = null;
                var template = this.valueTemplate;
                var optionLabelText = this._optionLabelText();
                var span = this.span;
                if (text === undefined) {
                    return span.text();
                }
                if ($.isPlainObject(text) || text instanceof ObservableObject) {
                    dataItem = text;
                } else if (optionLabelText && optionLabelText === text) {
                    dataItem = this.options.optionLabel;
                }
                if (!dataItem) {
                    dataItem = this._assignInstance(text, this._accessor());
                }
                if (this.hasOptionLabel()) {
                    if (dataItem === optionLabelText || this._text(dataItem) === optionLabelText) {
                        template = this.optionLabelTemplate;
                        if (typeof this.options.optionLabel === 'string' && !this.options.optionLabelTemplate) {
                            dataItem = optionLabelText;
                        }
                    }
                }
                var getElements = function () {
                    return {
                        elements: span.get(),
                        data: [{ dataItem: dataItem }]
                    };
                };
                this.angular('cleanup', getElements);
                try {
                    span.html(template(dataItem));
                } catch (e) {
                    span.html('');
                }
                this.angular('compile', getElements);
            },
            _preselect: function (value, text) {
                if (!value && !text) {
                    text = this._optionLabelText();
                }
                this._accessor(value);
                this._textAccessor(text);
                this._old = this._accessor();
                this._oldIndex = this.selectedIndex;
                this.listView.setValue(value);
                this._initialIndex = null;
                this._presetValue = true;
            },
            _assignInstance: function (text, value) {
                var dataTextField = this.options.dataTextField;
                var dataItem = {};
                if (dataTextField) {
                    assign(dataItem, dataTextField.split('.'), text);
                    assign(dataItem, this.options.dataValueField.split('.'), value);
                    dataItem = new ObservableObject(dataItem);
                } else {
                    dataItem = text;
                }
                return dataItem;
            }
        });
        function assign(instance, fields, value) {
            var idx = 0, lastIndex = fields.length - 1, field;
            for (; idx < lastIndex; ++idx) {
                field = fields[idx];
                if (!(field in instance)) {
                    instance[field] = {};
                }
                instance = instance[field];
            }
            instance[fields[lastIndex]] = value;
        }
        function normalizeIndex(index, length) {
            if (index >= length) {
                index -= length;
            }
            return index;
        }
        function sameCharsOnly(word, character) {
            for (var idx = 0; idx < word.length; idx++) {
                if (word.charAt(idx) !== character) {
                    return false;
                }
            }
            return true;
        }
        ui.plugin(DropDownList);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.treeview.draganddrop', [
        'kendo.data',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'treeview.draganddrop',
        name: 'Hierarchical Drag & Drop',
        category: 'framework',
        depends: [
            'core',
            'draganddrop'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var ui = kendo.ui;
        var proxy = $.proxy;
        var extend = $.extend;
        var VISIBILITY = 'visibility';
        var KSTATEHOVER = 'k-state-hover';
        var INPUTSELECTOR = 'input,a:not(.k-in),textarea,.k-multiselect-wrap,select,button,a.k-button>.k-icon,button.k-button>.k-icon,span.k-icon.k-i-arrow-60-right,span.k-icon.k-i-arrow-45-down-right';
        ui.HierarchicalDragAndDrop = kendo.Class.extend({
            init: function (element, options) {
                this.element = element;
                this.hovered = element;
                this.options = extend({
                    dragstart: $.noop,
                    drag: $.noop,
                    drop: $.noop,
                    dragend: $.noop
                }, options);
                this._draggable = new ui.Draggable(element, {
                    ignore: INPUTSELECTOR,
                    filter: options.filter,
                    autoScroll: options.autoScroll,
                    cursorOffset: {
                        left: 10,
                        top: kendo.support.mobileOS ? -40 / kendo.support.zoomLevel() : 10
                    },
                    hint: proxy(this._hint, this),
                    dragstart: proxy(this.dragstart, this),
                    dragcancel: proxy(this.dragcancel, this),
                    drag: proxy(this.drag, this),
                    dragend: proxy(this.dragend, this),
                    $angular: options.$angular
                });
            },
            _hint: function (element) {
                return '<div class=\'k-header k-drag-clue\'>' + '<span class=\'k-icon k-drag-status\' />' + this.options.hintText(element) + '</div>';
            },
            _removeTouchHover: function () {
                if (kendo.support.touch && this.hovered) {
                    this.hovered.find('.' + KSTATEHOVER).removeClass(KSTATEHOVER);
                    this.hovered = false;
                }
            },
            _hintStatus: function (newStatus) {
                var statusElement = this._draggable.hint.find('.k-drag-status')[0];
                if (newStatus) {
                    statusElement.className = 'k-icon k-drag-status ' + newStatus;
                } else {
                    return $.trim(statusElement.className.replace(/(p|k)-(icon|drag-status)/g, ''));
                }
            },
            dragstart: function (e) {
                this.source = e.currentTarget.closest(this.options.itemSelector);
                if (this.options.dragstart(this.source)) {
                    e.preventDefault();
                }
                if (this.options.reorderable) {
                    this.dropHint = $('<div class=\'k-icon k-i-drag-and-drop\' />').css(VISIBILITY, 'hidden').appendTo(this.element);
                } else {
                    this.dropHint = $();
                }
            },
            drag: function (e) {
                var options = this.options;
                var source = this.source;
                var target = this.dropTarget = $(kendo.eventTarget(e));
                var container = target.closest(options.allowedContainers);
                var hoveredItem, itemHeight, itemTop, itemContent, delta;
                var insertOnTop, insertOnBottom, addChild;
                var itemData, position, status;
                if (!container.length) {
                    status = 'k-i-cancel';
                    this._removeTouchHover();
                } else if (source[0] == target[0] || options.contains(source[0], target[0])) {
                    status = 'k-i-cancel';
                } else {
                    status = 'k-i-insert-middle';
                    itemData = options.itemFromTarget(target);
                    hoveredItem = itemData.item;
                    if (hoveredItem.length) {
                        this._removeTouchHover();
                        itemHeight = kendo._outerHeight(hoveredItem);
                        itemContent = itemData.content;
                        if (options.reorderable) {
                            delta = itemHeight / (itemContent.length > 0 ? 4 : 2);
                            itemTop = kendo.getOffset(hoveredItem).top;
                            insertOnTop = e.y.location < itemTop + delta;
                            insertOnBottom = itemTop + itemHeight - delta < e.y.location;
                            addChild = itemContent.length && !insertOnTop && !insertOnBottom;
                        } else {
                            addChild = true;
                            insertOnTop = false;
                            insertOnBottom = false;
                        }
                        this.hovered = addChild ? container : false;
                        this.dropHint.css(VISIBILITY, addChild ? 'hidden' : 'visible');
                        if (this._lastHover && this._lastHover[0] != itemContent[0]) {
                            this._lastHover.removeClass(KSTATEHOVER);
                        }
                        this._lastHover = itemContent.toggleClass(KSTATEHOVER, addChild);
                        if (addChild) {
                            status = 'k-i-plus';
                        } else {
                            position = hoveredItem.position();
                            position.top += insertOnTop ? 0 : itemHeight;
                            this.dropHint.css(position)[insertOnTop ? 'prependTo' : 'appendTo'](options.dropHintContainer(hoveredItem));
                            if (insertOnTop && itemData.first) {
                                status = 'k-i-insert-up';
                            }
                            if (insertOnBottom && itemData.last) {
                                status = 'k-i-insert-down';
                            }
                        }
                    } else if (target[0] != this.dropHint[0]) {
                        if (this._lastHover) {
                            this._lastHover.removeClass(KSTATEHOVER);
                        }
                        if (!$.contains(this.element[0], container[0])) {
                            status = 'k-i-plus';
                        } else {
                            status = 'k-i-cancel';
                        }
                    }
                }
                this.options.drag({
                    originalEvent: e.originalEvent,
                    source: source,
                    target: target,
                    pageY: e.y.location,
                    pageX: e.x.location,
                    status: status.substring(2),
                    setStatus: function (value) {
                        status = value;
                    }
                });
                if (status.indexOf('k-i-insert') !== 0) {
                    this.dropHint.css(VISIBILITY, 'hidden');
                }
                this._hintStatus(status);
            },
            dragcancel: function () {
                this.dropHint.remove();
            },
            dragend: function (e) {
                var position = 'over', source = this.source, destination, dropHint = this.dropHint, dropTarget = this.dropTarget, eventArgs, dropPrevented;
                if (dropHint.css(VISIBILITY) == 'visible') {
                    position = this.options.dropPositionFrom(dropHint);
                    destination = dropHint.closest(this.options.itemSelector);
                } else if (dropTarget) {
                    destination = dropTarget.closest(this.options.itemSelector);
                    if (!destination.length) {
                        destination = dropTarget.closest(this.options.allowedContainers);
                    }
                }
                eventArgs = {
                    originalEvent: e.originalEvent,
                    source: source[0],
                    destination: destination[0],
                    valid: this._hintStatus() != 'k-i-cancel',
                    setValid: function (newValid) {
                        this.valid = newValid;
                    },
                    dropTarget: dropTarget[0],
                    position: position
                };
                dropPrevented = this.options.drop(eventArgs);
                dropHint.remove();
                this._removeTouchHover();
                if (this._lastHover) {
                    this._lastHover.removeClass(KSTATEHOVER);
                }
                if (!eventArgs.valid || dropPrevented) {
                    this._draggable.dropped = eventArgs.valid;
                    return;
                }
                this._draggable.dropped = true;
                this.options.dragend({
                    originalEvent: e.originalEvent,
                    source: source,
                    destination: destination,
                    position: position
                });
            },
            destroy: function () {
                this._lastHover = this.hovered = null;
                this._draggable.destroy();
            }
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.treeview', [
        'kendo.data',
        'kendo.treeview.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'treeview',
        name: 'TreeView',
        category: 'web',
        description: 'The TreeView widget displays hierarchical data in a traditional tree structure,with support for interactive drag-and-drop operations.',
        depends: ['data'],
        features: [{
                id: 'treeview-dragging',
                name: 'Drag & Drop',
                description: 'Support for drag & drop',
                depends: ['treeview.draganddrop']
            }]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, data = kendo.data, extend = $.extend, template = kendo.template, isArray = $.isArray, Widget = ui.Widget, HierarchicalDataSource = data.HierarchicalDataSource, proxy = $.proxy, keys = kendo.keys, NS = '.kendoTreeView', TEMP_NS = '.kendoTreeViewTemp', SELECT = 'select', CHECK = 'check', NAVIGATE = 'navigate', EXPAND = 'expand', CHANGE = 'change', ERROR = 'error', CHECKED = 'checked', INDETERMINATE = 'indeterminate', COLLAPSE = 'collapse', DRAGSTART = 'dragstart', DRAG = 'drag', DROP = 'drop', DRAGEND = 'dragend', DATABOUND = 'dataBound', CLICK = 'click', UNDEFINED = 'undefined', KSTATEHOVER = 'k-state-hover', KTREEVIEW = 'k-treeview', VISIBLE = ':visible', NODE = '.k-item', STRING = 'string', ARIACHECKED = 'aria-checked', ARIASELECTED = 'aria-selected', ARIADISABLED = 'aria-disabled', DISABLED = 'k-state-disabled', TreeView, subGroup, nodeContents, nodeIcon, spriteRe, bindings = {
                text: 'dataTextField',
                url: 'dataUrlField',
                spriteCssClass: 'dataSpriteCssClassField',
                imageUrl: 'dataImageUrlField'
            }, isJQueryInstance = function (obj) {
                return obj instanceof kendo.jQuery || window.jQuery && obj instanceof window.jQuery;
            }, isDomElement = function (o) {
                return typeof HTMLElement === 'object' ? o instanceof HTMLElement : o && typeof o === 'object' && o.nodeType === 1 && typeof o.nodeName === STRING;
            };
        function contentChild(filter) {
            return function (node) {
                var result = node.children('.k-animation-container');
                if (!result.length) {
                    result = node;
                }
                return result.children(filter);
            };
        }
        function templateNoWith(code) {
            return kendo.template(code, { useWithBlock: false });
        }
        subGroup = contentChild('.k-group');
        nodeContents = contentChild('.k-group,.k-content');
        nodeIcon = function (node) {
            return node.children('div').children('.k-icon');
        };
        function checkboxes(node) {
            return node.find('.k-checkbox-wrapper:first input[type=checkbox]');
        }
        function insertAction(indexOffset) {
            return function (nodeData, referenceNode) {
                referenceNode = referenceNode.closest(NODE);
                var group = referenceNode.parent(), parentNode;
                if (group.parent().is('li')) {
                    parentNode = group.parent();
                }
                return this._dataSourceMove(nodeData, group, parentNode, function (dataSource, model) {
                    var referenceItem = this.dataItem(referenceNode);
                    var referenceNodeIndex = referenceItem ? referenceItem.parent().indexOf(referenceItem) : referenceNode.index();
                    return this._insert(dataSource.data(), model, referenceNodeIndex + indexOffset);
                });
            };
        }
        spriteRe = /k-sprite/;
        function moveContents(node, container) {
            var tmp;
            while (node && node.nodeName.toLowerCase() != 'ul') {
                tmp = node;
                node = node.nextSibling;
                if (tmp.nodeType == 3) {
                    tmp.nodeValue = $.trim(tmp.nodeValue);
                }
                if (spriteRe.test(tmp.className)) {
                    container.insertBefore(tmp, container.firstChild);
                } else {
                    container.appendChild(tmp);
                }
            }
        }
        function updateNodeHtml(node) {
            var wrapper = node.children('div'), group = node.children('ul'), toggleButton = wrapper.children('.k-icon'), checkbox = node.children('input[type=checkbox]'), innerWrapper = wrapper.children('.k-in');
            if (node.hasClass('k-treeview')) {
                return;
            }
            if (!wrapper.length) {
                wrapper = $('<div />').prependTo(node);
            }
            if (!toggleButton.length && group.length) {
                toggleButton = $('<span class=\'k-icon\' />').prependTo(wrapper);
            } else if (!group.length || !group.children().length) {
                toggleButton.remove();
                group.remove();
            }
            if (checkbox.length) {
                $('<span class=\'k-checkbox-wrapper\' />').appendTo(wrapper).append(checkbox);
            }
            if (!innerWrapper.length) {
                innerWrapper = node.children('a').eq(0).addClass('k-in k-link');
                if (!innerWrapper.length) {
                    innerWrapper = $('<span class=\'k-in\' />');
                }
                innerWrapper.appendTo(wrapper);
                if (wrapper.length) {
                    moveContents(wrapper[0].nextSibling, innerWrapper[0]);
                }
            }
        }
        TreeView = kendo.ui.DataBoundWidget.extend({
            init: function (element, options) {
                var that = this, inferred = false, hasDataSource = options && !!options.dataSource, list;
                if (isArray(options)) {
                    options = { dataSource: options };
                }
                if (options && typeof options.loadOnDemand == UNDEFINED && isArray(options.dataSource)) {
                    options.loadOnDemand = false;
                }
                Widget.prototype.init.call(that, element, options);
                element = that.element;
                options = that.options;
                that._dataSourceUids = {};
                list = element.is('ul') && element || element.hasClass(KTREEVIEW) && element.children('ul');
                inferred = !hasDataSource && list.length;
                if (inferred) {
                    options.dataSource.list = list;
                }
                that._animation();
                that._accessors();
                that._templates();
                if (!element.hasClass(KTREEVIEW)) {
                    that._wrapper();
                    if (list) {
                        that.root = element;
                        that._group(that.wrapper);
                    }
                } else {
                    that.wrapper = element;
                    that.root = element.children('ul').eq(0);
                }
                that._tabindex();
                that.wrapper.attr('role', 'tree');
                that._dataSource(inferred);
                that._attachEvents();
                that._dragging();
                if (!inferred) {
                    if (options.autoBind) {
                        that._progress(true);
                        that.dataSource.fetch();
                    }
                } else {
                    that._syncHtmlAndDataSource();
                }
                if (options.checkboxes && options.checkboxes.checkChildren) {
                    that.updateIndeterminate();
                }
                if (that.element[0].id) {
                    that._ariaId = kendo.format('{0}_tv_active', that.element[0].id);
                }
                kendo.notify(that);
            },
            _attachEvents: function () {
                var that = this, clickableItems = '.k-in:not(.k-state-selected,.k-state-disabled)', MOUSEENTER = 'mouseenter';
                that.wrapper.on(MOUSEENTER + NS, '.k-in.k-state-selected', function (e) {
                    e.preventDefault();
                }).on(MOUSEENTER + NS, clickableItems, function () {
                    $(this).addClass(KSTATEHOVER);
                }).on('mouseleave' + NS, clickableItems, function () {
                    $(this).removeClass(KSTATEHOVER);
                }).on(CLICK + NS, clickableItems, proxy(that._click, that)).on('dblclick' + NS, '.k-in:not(.k-state-disabled)', proxy(that._toggleButtonClick, that)).on(CLICK + NS, '.k-i-expand,.k-i-collapse', proxy(that._toggleButtonClick, that)).on('keydown' + NS, proxy(that._keydown, that)).on('keypress' + NS, proxy(that._keypress, that)).on('focus' + NS, proxy(that._focus, that)).on('blur' + NS, proxy(that._blur, that)).on('mousedown' + NS, '.k-in,.k-checkbox-wrapper :checkbox,.k-i-expand,.k-i-collapse', proxy(that._mousedown, that)).on('change' + NS, '.k-checkbox-wrapper :checkbox', proxy(that._checkboxChange, that)).on('click' + NS, '.checkbox-span', proxy(that._checkboxLabelClick, that)).on('click' + NS, '.k-request-retry', proxy(that._retryRequest, that)).on('click' + NS, '.k-link.k-state-disabled', function (e) {
                    e.preventDefault();
                }).on('click' + NS, function (e) {
                    var target = $(e.target);
                    if (!target.is(':kendoFocusable') && !target.find('input,select,textarea,button,object').is(':kendoFocusable')) {
                        that.focus();
                    }
                });
            },
            _checkboxLabelClick: function (e) {
                var checkbox = $(e.target.previousSibling);
                if (checkbox.is('[disabled]')) {
                    return;
                }
                checkbox.prop('checked', !checkbox.prop('checked'));
                checkbox.trigger('change');
            },
            _syncHtmlAndDataSource: function (root, dataSource) {
                root = root || this.root;
                dataSource = dataSource || this.dataSource;
                var data = dataSource.view(), uidAttr = kendo.attr('uid'), expandedAttr = kendo.attr('expanded'), checkboxesEnabled = this.options.checkboxes, items = root.children('li'), i, item, dataItem, uid, itemCheckbox;
                for (i = 0; i < items.length; i++) {
                    dataItem = data[i];
                    uid = dataItem.uid;
                    item = items.eq(i);
                    item.attr('role', 'treeitem').attr(uidAttr, uid).attr(ARIASELECTED, item.hasClass('k-state-selected'));
                    dataItem.expanded = item.attr(expandedAttr) === 'true';
                    if (checkboxesEnabled) {
                        itemCheckbox = checkboxes(item);
                        dataItem.checked = itemCheckbox.prop(CHECKED);
                        itemCheckbox.attr('id', '_' + uid);
                        itemCheckbox.next('.k-checkbox-label').attr('for', '_' + uid);
                    }
                    this._syncHtmlAndDataSource(item.children('ul'), dataItem.children);
                }
            },
            _animation: function () {
                var options = this.options, animationOptions = options.animation, hasCollapseAnimation = animationOptions.collapse && 'effects' in animationOptions.collapse, collapse = extend({}, animationOptions.expand, animationOptions.collapse);
                if (!hasCollapseAnimation) {
                    collapse = extend(collapse, { reverse: true });
                }
                if (animationOptions === false) {
                    animationOptions = {
                        expand: { effects: {} },
                        collapse: {
                            hide: true,
                            effects: {}
                        }
                    };
                }
                animationOptions.collapse = extend(collapse, { hide: true });
                options.animation = animationOptions;
            },
            _dragging: function () {
                var enabled = this.options.dragAndDrop;
                var dragging = this.dragging;
                if (enabled && !dragging) {
                    var widget = this;
                    this.dragging = new ui.HierarchicalDragAndDrop(this.element, {
                        reorderable: true,
                        $angular: this.options.$angular,
                        autoScroll: this.options.autoScroll,
                        filter: 'div:not(.k-state-disabled) .k-in',
                        allowedContainers: '.k-treeview',
                        itemSelector: '.k-treeview .k-item',
                        hintText: proxy(this._hintText, this),
                        contains: function (source, destination) {
                            return $.contains(source, destination);
                        },
                        dropHintContainer: function (item) {
                            return item;
                        },
                        itemFromTarget: function (target) {
                            var item = target.closest('.k-top,.k-mid,.k-bot');
                            return {
                                item: item,
                                content: target.closest('.k-in'),
                                first: item.hasClass('k-top'),
                                last: item.hasClass('k-bot')
                            };
                        },
                        dropPositionFrom: function (dropHint) {
                            return dropHint.prevAll('.k-in').length > 0 ? 'after' : 'before';
                        },
                        dragstart: function (source) {
                            return widget.trigger(DRAGSTART, { sourceNode: source[0] });
                        },
                        drag: function (options) {
                            widget.trigger(DRAG, {
                                originalEvent: options.originalEvent,
                                sourceNode: options.source[0],
                                dropTarget: options.target[0],
                                pageY: options.pageY,
                                pageX: options.pageX,
                                statusClass: options.status,
                                setStatusClass: options.setStatus
                            });
                        },
                        drop: function (options) {
                            var dropTarget = $(options.dropTarget);
                            var navigationTarget = dropTarget.closest('a');
                            if (navigationTarget && navigationTarget.attr('href')) {
                                widget._tempPreventNavigation(navigationTarget);
                            }
                            return widget.trigger(DROP, {
                                originalEvent: options.originalEvent,
                                sourceNode: options.source,
                                destinationNode: options.destination,
                                valid: options.valid,
                                setValid: function (state) {
                                    this.valid = state;
                                    options.setValid(state);
                                },
                                dropTarget: options.dropTarget,
                                dropPosition: options.position
                            });
                        },
                        dragend: function (options) {
                            var source = options.source;
                            var destination = options.destination;
                            var position = options.position;
                            function triggerDragEnd(source) {
                                if (widget.options.checkboxes && widget.options.checkboxes.checkChildren) {
                                    widget.updateIndeterminate();
                                }
                                widget.trigger(DRAGEND, {
                                    originalEvent: options.originalEvent,
                                    sourceNode: source && source[0],
                                    destinationNode: destination[0],
                                    dropPosition: position
                                });
                            }
                            if (position == 'over') {
                                widget.append(source, destination, triggerDragEnd);
                            } else {
                                if (position == 'before') {
                                    source = widget.insertBefore(source, destination);
                                } else if (position == 'after') {
                                    source = widget.insertAfter(source, destination);
                                }
                                triggerDragEnd(source);
                            }
                        }
                    });
                } else if (!enabled && dragging) {
                    dragging.destroy();
                    this.dragging = null;
                }
            },
            _tempPreventNavigation: function (node) {
                node.on(CLICK + NS + TEMP_NS, function (ev) {
                    ev.preventDefault();
                    node.off(CLICK + NS + TEMP_NS);
                });
            },
            _hintText: function (node) {
                return this.templates.dragClue({
                    item: this.dataItem(node),
                    treeview: this.options
                });
            },
            _templates: function () {
                var that = this, options = that.options, fieldAccessor = proxy(that._fieldAccessor, that);
                if (options.template && typeof options.template == STRING) {
                    options.template = template(options.template);
                } else if (!options.template) {
                    options.template = templateNoWith('# var text = ' + fieldAccessor('text') + '(data.item); #' + '# if (typeof data.item.encoded != \'undefined\' && data.item.encoded === false) {#' + '#= text #' + '# } else { #' + '#: text #' + '# } #');
                }
                that._checkboxes();
                that.templates = {
                    setAttributes: function (item) {
                        var result = '';
                        var attributes = item.attr || {};
                        for (var attr in attributes) {
                            if (attributes.hasOwnProperty(attr) && attr !== 'class') {
                                result += attr + '="' + attributes[attr] + '" ';
                            }
                        }
                        return result;
                    },
                    wrapperCssClass: function (group, item) {
                        var result = 'k-item', index = item.index;
                        if (group.firstLevel && index === 0) {
                            result += ' k-first';
                        }
                        if (index == group.length - 1) {
                            result += ' k-last';
                        }
                        return result;
                    },
                    cssClass: function (group, item) {
                        var result = '', index = item.index, groupLength = group.length - 1;
                        if (group.firstLevel && index === 0) {
                            result += 'k-top ';
                        }
                        if (index === 0 && index != groupLength) {
                            result += 'k-top';
                        } else if (index == groupLength) {
                            result += 'k-bot';
                        } else {
                            result += 'k-mid';
                        }
                        return result;
                    },
                    textClass: function (item, isLink) {
                        var result = 'k-in';
                        if (isLink) {
                            result += ' k-link';
                        }
                        if (item.enabled === false) {
                            result += ' k-state-disabled';
                        }
                        if (item.selected === true) {
                            result += ' k-state-selected';
                        }
                        return result;
                    },
                    toggleButtonClass: function (item) {
                        var result = 'k-icon';
                        if (item.expanded !== true) {
                            result += ' k-i-expand';
                        } else {
                            result += ' k-i-collapse';
                        }
                        return result;
                    },
                    groupAttributes: function (group) {
                        var attributes = '';
                        if (!group.firstLevel) {
                            attributes = 'role=\'group\'';
                        }
                        return attributes + (group.expanded !== true ? ' style=\'display:none\'' : '');
                    },
                    groupCssClass: function (group) {
                        var cssClass = 'k-group';
                        if (group.firstLevel) {
                            cssClass += ' k-treeview-lines';
                        }
                        return cssClass;
                    },
                    dragClue: templateNoWith('#= data.treeview.template(data) #'),
                    group: templateNoWith('<ul class=\'#= data.r.groupCssClass(data.group) #\'#= data.r.groupAttributes(data.group) #>' + '#= data.renderItems(data) #' + '</ul>'),
                    itemContent: templateNoWith('# var imageUrl = ' + fieldAccessor('imageUrl') + '(data.item); #' + '# var spriteCssClass = ' + fieldAccessor('spriteCssClass') + '(data.item); #' + '# if (imageUrl) { #' + '<img class=\'k-image\' alt=\'\' src=\'#= imageUrl #\'>' + '# } #' + '# if (spriteCssClass) { #' + '<span class=\'k-sprite #= spriteCssClass #\' />' + '# } #' + '#= data.treeview.template(data) #'),
                    itemElement: templateNoWith('# var item = data.item, r = data.r; #' + '# var url = ' + fieldAccessor('url') + '(item); #' + '<div class=\'#= r.cssClass(data.group, item) #\'>' + '# if (item.hasChildren) { #' + '<span class=\'#= r.toggleButtonClass(item) #\'/>' + '# } #' + '# if (data.treeview.checkboxes) { #' + '<span class=\'k-checkbox-wrapper\' role=\'presentation\'>' + '#= data.treeview.checkboxes.template(data) #' + '</span>' + '# } #' + '# var tag = url ? \'a\' : \'span\'; #' + '# var textAttr = url ? \' href=\\\'\' + url + \'\\\'\' : \'\'; #' + '<#=tag# class=\'#= r.textClass(item, !!url) #\'#= textAttr #>' + '#= r.itemContent(data) #' + '</#=tag#>' + '</div>'),
                    item: templateNoWith('# var item = data.item, r = data.r; #' + '<li role=\'treeitem\' class=\'#= r.wrapperCssClass(data.group, item) #\'' + kendo.attr('uid') + '=\'#= item.uid #\' ' + '#= r.setAttributes(item.toJSON ? item.toJSON() : item) # ' + '# if (data.treeview.checkboxes) { #' + 'aria-checked=\'#= item.checked ? "true" : "false" #\' ' + '# } #' + 'aria-selected=\'#= item.selected ? "true" : "false" #\' ' + '#=item.enabled === false ? "aria-disabled=\'true\'" : \'\'#' + 'aria-expanded=\'#= item.expanded ? "true" : "false" #\' ' + 'data-expanded=\'#= item.expanded ? "true" : "false" #\' ' + '>' + '#= r.itemElement(data) #' + '</li>'),
                    loading: templateNoWith('<div class=\'k-icon k-i-loading\' /> #: data.messages.loading #'),
                    retry: templateNoWith('#: data.messages.requestFailed # ' + '<button class=\'k-button k-request-retry\'>#: data.messages.retry #</button>')
                };
            },
            items: function () {
                return this.element.find('.k-item > div:first-child');
            },
            setDataSource: function (dataSource) {
                var options = this.options;
                options.dataSource = dataSource;
                this._dataSourceUids = {};
                this._dataSource();
                if (options.checkboxes && options.checkboxes.checkChildren) {
                    this.dataSource.one('change', $.proxy(this.updateIndeterminate, this, null));
                }
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
            },
            _bindDataSource: function () {
                this._refreshHandler = proxy(this.refresh, this);
                this._errorHandler = proxy(this._error, this);
                this.dataSource.bind(CHANGE, this._refreshHandler);
                this.dataSource.bind(ERROR, this._errorHandler);
            },
            _unbindDataSource: function () {
                var dataSource = this.dataSource;
                if (dataSource) {
                    dataSource.unbind(CHANGE, this._refreshHandler);
                    dataSource.unbind(ERROR, this._errorHandler);
                }
            },
            _dataSource: function (silentRead) {
                var that = this, options = that.options, dataSource = options.dataSource;
                function recursiveRead(data) {
                    for (var i = 0; i < data.length; i++) {
                        data[i]._initChildren();
                        data[i].children.fetch();
                        recursiveRead(data[i].children.view());
                    }
                }
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                that._unbindDataSource();
                if (!dataSource.fields) {
                    dataSource.fields = [
                        { field: 'text' },
                        { field: 'url' },
                        { field: 'spriteCssClass' },
                        { field: 'imageUrl' }
                    ];
                }
                that.dataSource = dataSource = HierarchicalDataSource.create(dataSource);
                if (silentRead) {
                    dataSource.fetch();
                    recursiveRead(dataSource.view());
                }
                that._bindDataSource();
            },
            events: [
                DRAGSTART,
                DRAG,
                DROP,
                DRAGEND,
                DATABOUND,
                EXPAND,
                COLLAPSE,
                SELECT,
                CHANGE,
                NAVIGATE,
                CHECK
            ],
            options: {
                name: 'TreeView',
                dataSource: {},
                animation: {
                    expand: {
                        effects: 'expand:vertical',
                        duration: 200
                    },
                    collapse: { duration: 100 }
                },
                messages: {
                    loading: 'Loading...',
                    requestFailed: 'Request failed.',
                    retry: 'Retry'
                },
                dragAndDrop: false,
                checkboxes: false,
                autoBind: true,
                autoScroll: false,
                loadOnDemand: true,
                template: '',
                dataTextField: null
            },
            _accessors: function () {
                var that = this, options = that.options, i, field, textField, element = that.element;
                for (i in bindings) {
                    field = options[bindings[i]];
                    textField = element.attr(kendo.attr(i + '-field'));
                    if (!field && textField) {
                        field = textField;
                    }
                    if (!field) {
                        field = i;
                    }
                    if (!isArray(field)) {
                        field = [field];
                    }
                    options[bindings[i]] = field;
                }
            },
            _fieldAccessor: function (fieldName) {
                var fieldBindings = this.options[bindings[fieldName]], count = fieldBindings.length, result = '(function(item) {';
                if (count === 0) {
                    result += 'return item[\'' + fieldName + '\'];';
                } else {
                    result += 'var levels = [' + $.map(fieldBindings, function (x) {
                        return 'function(d){ return ' + kendo.expr(x) + '}';
                    }).join(',') + '];';
                    result += 'return levels[Math.min(item.level(), ' + count + '-1)](item)';
                }
                result += '})';
                return result;
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._animation();
                this._dragging();
                this._templates();
            },
            _trigger: function (eventName, node) {
                return this.trigger(eventName, { node: node.closest(NODE)[0] });
            },
            _setChecked: function (datasource, value) {
                if (!datasource || !$.isFunction(datasource.view)) {
                    return;
                }
                for (var i = 0, nodes = datasource.view(); i < nodes.length; i++) {
                    if (nodes[i].enabled !== false) {
                        this._setCheckedValue(nodes[i], value);
                    }
                    if (nodes[i].children) {
                        this._setChecked(nodes[i].children, value);
                    }
                }
            },
            _setCheckedValue: function (node, value) {
                node[CHECKED] = value;
            },
            _setIndeterminate: function (node) {
                var group = subGroup(node), siblings, length, all = true, i;
                if (!group.length) {
                    return;
                }
                siblings = checkboxes(group.children());
                length = siblings.length;
                if (!length) {
                    return;
                } else if (length > 1) {
                    for (i = 1; i < length; i++) {
                        if (siblings[i].checked != siblings[i - 1].checked || siblings[i].indeterminate || siblings[i - 1].indeterminate) {
                            all = false;
                            break;
                        }
                    }
                } else {
                    all = !siblings[0].indeterminate;
                }
                node.attr(ARIACHECKED, all ? siblings[0].checked : 'mixed');
                return checkboxes(node).data(INDETERMINATE, !all).prop(INDETERMINATE, !all).prop(CHECKED, all && siblings[0].checked);
            },
            updateIndeterminate: function (node) {
                node = node || this.wrapper;
                var subnodes = subGroup(node).children();
                var i;
                var checkbox;
                var dataItem;
                if (subnodes.length) {
                    for (i = 0; i < subnodes.length; i++) {
                        this.updateIndeterminate(subnodes.eq(i));
                    }
                    if (node.is('.k-treeview')) {
                        return;
                    }
                    checkbox = this._setIndeterminate(node);
                    dataItem = this.dataItem(node);
                    if (checkbox && checkbox.prop(CHECKED)) {
                        dataItem.checked = true;
                    } else {
                        if (dataItem) {
                            delete dataItem.checked;
                        }
                    }
                }
            },
            _bubbleIndeterminate: function (node, skipDownward) {
                if (!node.length) {
                    return;
                }
                if (!skipDownward) {
                    this.updateIndeterminate(node);
                }
                var parentNode = this.parent(node), checkbox;
                if (parentNode.length) {
                    this._setIndeterminate(parentNode);
                    checkbox = parentNode.children('div').find('.k-checkbox-wrapper input[type=checkbox]');
                    this._skip = true;
                    if (checkbox.prop(INDETERMINATE) === false) {
                        this.dataItem(parentNode).set(CHECKED, checkbox.prop(CHECKED));
                    } else {
                        this.dataItem(parentNode).set(CHECKED, false);
                    }
                    this._skip = false;
                    this._bubbleIndeterminate(parentNode, true);
                }
            },
            _checkboxChange: function (e) {
                var checkbox = $(e.target);
                var isChecked = checkbox.prop(CHECKED);
                var node = checkbox.closest(NODE);
                var dataItem = this.dataItem(node);
                if (this._preventChange) {
                    return;
                }
                if (dataItem.checked != isChecked) {
                    dataItem.set(CHECKED, isChecked);
                    node.attr(ARIACHECKED, isChecked);
                    this._trigger(CHECK, node);
                }
            },
            _toggleButtonClick: function (e) {
                var node = $(e.currentTarget).closest(NODE);
                if (node.is('[aria-disabled=\'true\']')) {
                    return;
                }
                this.toggle(node);
            },
            _mousedown: function (e) {
                var that = this;
                var currentTarget = $(e.currentTarget);
                var node = $(e.currentTarget).closest(NODE);
                var browser = kendo.support.browser;
                if (node.is('[aria-disabled=\'true\']')) {
                    return;
                }
                if ((browser.msie || browser.edge) && currentTarget.is(':checkbox')) {
                    if (currentTarget.prop(INDETERMINATE)) {
                        that._preventChange = false;
                        currentTarget.prop(CHECKED, !currentTarget.prop(CHECKED));
                        currentTarget.trigger(CHANGE);
                        currentTarget.on(CLICK + NS, function (e) {
                            e.preventDefault();
                        });
                        that._preventChange = true;
                    } else {
                        currentTarget.off(CLICK + NS);
                        that._preventChange = false;
                    }
                }
                that._clickTarget = node;
                that.current(node);
            },
            _focusable: function (node) {
                return node && node.length && node.is(':visible') && !node.find('.k-in:first').hasClass(DISABLED);
            },
            _focus: function () {
                var current = this.select(), clickTarget = this._clickTarget;
                if (kendo.support.touch) {
                    return;
                }
                if (clickTarget && clickTarget.length) {
                    current = clickTarget;
                }
                if (!this._focusable(current)) {
                    current = this.current();
                }
                if (!this._focusable(current)) {
                    current = this._nextVisible($());
                }
                this.current(current);
            },
            focus: function () {
                var wrapper = this.wrapper, scrollContainer = wrapper[0], containers = [], offsets = [], documentElement = document.documentElement, i;
                do {
                    scrollContainer = scrollContainer.parentNode;
                    if (scrollContainer.scrollHeight > scrollContainer.clientHeight) {
                        containers.push(scrollContainer);
                        offsets.push(scrollContainer.scrollTop);
                    }
                } while (scrollContainer != documentElement);
                kendo.focusElement(wrapper);
                for (i = 0; i < containers.length; i++) {
                    containers[i].scrollTop = offsets[i];
                }
            },
            _blur: function () {
                this.current().find('.k-in:first').removeClass('k-state-focused');
            },
            _enabled: function (node) {
                return !node.children('div').children('.k-in').hasClass(DISABLED);
            },
            parent: function (node) {
                var wrapperRe = /\bk-treeview\b/, itemRe = /\bk-item\b/, result, skipSelf;
                if (typeof node == STRING) {
                    node = this.element.find(node);
                }
                if (!isDomElement(node)) {
                    node = node[0];
                }
                skipSelf = itemRe.test(node.className);
                do {
                    node = node.parentNode;
                    if (itemRe.test(node.className)) {
                        if (skipSelf) {
                            result = node;
                        } else {
                            skipSelf = true;
                        }
                    }
                } while (!wrapperRe.test(node.className) && !result);
                return $(result);
            },
            _nextVisible: function (node) {
                var that = this, expanded = that._expanded(node), result;
                function nextParent(node) {
                    while (node.length && !node.next().length) {
                        node = that.parent(node);
                    }
                    if (node.next().length) {
                        return node.next();
                    } else {
                        return node;
                    }
                }
                if (!node.length || !node.is(':visible')) {
                    result = that.root.children().eq(0);
                } else if (expanded) {
                    result = subGroup(node).children().first();
                    if (!result.length) {
                        result = nextParent(node);
                    }
                } else {
                    result = nextParent(node);
                }
                return result;
            },
            _previousVisible: function (node) {
                var that = this, lastChild, result;
                if (!node.length || node.prev().length) {
                    if (node.length) {
                        result = node.prev();
                    } else {
                        result = that.root.children().last();
                    }
                    while (that._expanded(result)) {
                        lastChild = subGroup(result).children().last();
                        if (!lastChild.length) {
                            break;
                        }
                        result = lastChild;
                    }
                } else {
                    result = that.parent(node) || node;
                }
                return result;
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, target, focused = that.current(), expanded = that._expanded(focused), checkbox = focused.find('.k-checkbox-wrapper:first :checkbox'), rtl = kendo.support.isRtl(that.element);
                if (e.target != e.currentTarget) {
                    return;
                }
                if (!rtl && key == keys.RIGHT || rtl && key == keys.LEFT) {
                    if (expanded) {
                        target = that._nextVisible(focused);
                    } else if (!focused.find('.k-in:first').hasClass(DISABLED)) {
                        that.expand(focused);
                    }
                } else if (!rtl && key == keys.LEFT || rtl && key == keys.RIGHT) {
                    if (expanded && !focused.find('.k-in:first').hasClass(DISABLED)) {
                        that.collapse(focused);
                    } else {
                        target = that.parent(focused);
                        if (!that._enabled(target)) {
                            target = undefined;
                        }
                    }
                } else if (key == keys.DOWN) {
                    target = that._nextVisible(focused);
                } else if (key == keys.UP) {
                    target = that._previousVisible(focused);
                } else if (key == keys.HOME) {
                    target = that._nextVisible($());
                } else if (key == keys.END) {
                    target = that._previousVisible($());
                } else if (key == keys.ENTER && !focused.find('.k-in:first').hasClass(DISABLED)) {
                    if (!focused.find('.k-in:first').hasClass('k-state-selected')) {
                        if (!that._trigger(SELECT, focused)) {
                            that.select(focused);
                        }
                    }
                } else if (key == keys.SPACEBAR && checkbox.length) {
                    if (!focused.find('.k-in:first').hasClass(DISABLED)) {
                        checkbox.prop(CHECKED, !checkbox.prop(CHECKED)).data(INDETERMINATE, false).prop(INDETERMINATE, false);
                        that._checkboxChange({ target: checkbox });
                    }
                    target = focused;
                }
                if (target) {
                    e.preventDefault();
                    if (focused[0] != target[0]) {
                        that._trigger(NAVIGATE, target);
                        that.current(target);
                    }
                }
            },
            _keypress: function (e) {
                var that = this;
                var delay = 300;
                var focusedNode = that.current().get(0);
                var matchToFocus;
                var key = e.key;
                var isPrintable = key.length === 1;
                if (!isPrintable) {
                    return;
                }
                if (!that._match) {
                    that._match = '';
                }
                that._match += key;
                clearTimeout(that._matchTimer);
                that._matchTimer = setTimeout(function () {
                    that._match = '';
                }, delay);
                matchToFocus = focusedNode && that._matchNextByText(Array.prototype.indexOf.call(that.element.find('.k-item'), focusedNode), that._match);
                if (!matchToFocus.length) {
                    matchToFocus = that._matchNextByText(-1, that._match);
                }
                if (matchToFocus.get(0) && matchToFocus.get(0) !== focusedNode) {
                    that._trigger(NAVIGATE, matchToFocus);
                    that.current(matchToFocus);
                }
            },
            _matchNextByText: function (startIndex, text) {
                var element = this.element;
                var textNodes = element.find('.k-in').filter(function (i, element) {
                    return i > startIndex && $(element).is(':visible') && $(element).text().toLowerCase().indexOf(text) === 0;
                });
                return textNodes.eq(0).closest(NODE);
            },
            _click: function (e) {
                var that = this, node = $(e.currentTarget), contents = nodeContents(node.closest(NODE)), href = node.attr('href'), shouldNavigate;
                if (href) {
                    shouldNavigate = href == '#' || href.indexOf('#' + this.element.id + '-') >= 0;
                } else {
                    shouldNavigate = contents.length && !contents.children().length;
                }
                if (shouldNavigate) {
                    e.preventDefault();
                }
                if (!node.hasClass('.k-state-selected') && !that._trigger(SELECT, node)) {
                    that.select(node);
                }
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper, root, wrapperClasses = 'k-widget k-treeview';
                if (element.is('ul')) {
                    wrapper = element.wrap('<div />').parent();
                    root = element;
                } else {
                    wrapper = element;
                    root = wrapper.children('ul').eq(0);
                }
                that.wrapper = wrapper.addClass(wrapperClasses);
                that.root = root;
            },
            _getSelectedNode: function () {
                return this.element.find('.k-state-selected').closest(NODE);
            },
            _group: function (item) {
                var that = this, firstLevel = item.hasClass(KTREEVIEW), group = {
                        firstLevel: firstLevel,
                        expanded: firstLevel || that._expanded(item)
                    }, groupElement = item.children('ul');
                groupElement.addClass(that.templates.groupCssClass(group)).css('display', group.expanded ? '' : 'none');
                that._nodes(groupElement, group);
            },
            _nodes: function (groupElement, groupData) {
                var that = this, nodes = groupElement.children('li'), nodeData;
                groupData = extend({ length: nodes.length }, groupData);
                nodes.each(function (i, node) {
                    node = $(node);
                    nodeData = {
                        index: i,
                        expanded: that._expanded(node)
                    };
                    updateNodeHtml(node);
                    that._updateNodeClasses(node, groupData, nodeData);
                    that._group(node);
                });
            },
            _checkboxes: function () {
                var options = this.options;
                var checkboxes = options.checkboxes;
                var defaultTemplate;
                if (checkboxes) {
                    defaultTemplate = '<input type=\'checkbox\' tabindex=\'-1\' #= (item.enabled === false) ? \'disabled\' : \'\' # #= item.checked ? \'checked\' : \'\' #';
                    if (checkboxes.name) {
                        defaultTemplate += ' name=\'' + checkboxes.name + '\'';
                    }
                    defaultTemplate += ' id=\'_#= item.uid #\' class=\'k-checkbox\' /><span class=\'k-checkbox-label checkbox-span\'></span>';
                    checkboxes = extend({ template: defaultTemplate }, options.checkboxes);
                    if (typeof checkboxes.template == STRING) {
                        checkboxes.template = template(checkboxes.template);
                    }
                    options.checkboxes = checkboxes;
                }
            },
            _updateNodeClasses: function (node, groupData, nodeData) {
                var wrapper = node.children('div'), group = node.children('ul'), templates = this.templates;
                if (node.hasClass('k-treeview')) {
                    return;
                }
                nodeData = nodeData || {};
                nodeData.expanded = typeof nodeData.expanded != UNDEFINED ? nodeData.expanded : this._expanded(node);
                nodeData.index = typeof nodeData.index != UNDEFINED ? nodeData.index : node.index();
                nodeData.enabled = typeof nodeData.enabled != UNDEFINED ? nodeData.enabled : !wrapper.children('.k-in').hasClass('k-state-disabled');
                groupData = groupData || {};
                groupData.firstLevel = typeof groupData.firstLevel != UNDEFINED ? groupData.firstLevel : node.parent().parent().hasClass(KTREEVIEW);
                groupData.length = typeof groupData.length != UNDEFINED ? groupData.length : node.parent().children().length;
                node.removeClass('k-first k-last').addClass(templates.wrapperCssClass(groupData, nodeData));
                wrapper.removeClass('k-top k-mid k-bot').addClass(templates.cssClass(groupData, nodeData));
                var textWrap = wrapper.children('.k-in');
                var isLink = textWrap[0] && textWrap[0].nodeName.toLowerCase() == 'a';
                textWrap.removeClass('k-in k-link k-state-default k-state-disabled').addClass(templates.textClass(nodeData, isLink));
                if (group.length || node.attr('data-hasChildren') == 'true') {
                    wrapper.children('.k-icon').removeClass('k-i-expand k-i-collapse').addClass(templates.toggleButtonClass(nodeData));
                    group.addClass('k-group');
                }
            },
            _processNodes: function (nodes, callback) {
                var that = this;
                var items = that.element.find(nodes);
                for (var i = 0; i < items.length; i++) {
                    callback.call(that, i, $(items[i]).closest(NODE));
                }
            },
            dataItem: function (node) {
                var uid = $(node).closest(NODE).attr(kendo.attr('uid')), dataSource = this.dataSource;
                return dataSource && dataSource.getByUid(uid);
            },
            _dataItem: function (node) {
                var uid = $(node).closest(NODE).attr(kendo.attr('uid')), dataSource = this.dataSource;
                return dataSource && this._dataSourceUids[uid];
            },
            _insertNode: function (nodeData, index, parentNode, insertCallback, collapsed) {
                var that = this, group = subGroup(parentNode), updatedGroupLength = group.children().length + 1, childrenData, groupData = {
                        firstLevel: parentNode.hasClass(KTREEVIEW),
                        expanded: !collapsed,
                        length: updatedGroupLength
                    }, node, i, item, nodeHtml = '', firstChild, lastChild, append = function (item, group) {
                        item.appendTo(group);
                    };
                for (i = 0; i < nodeData.length; i++) {
                    item = nodeData[i];
                    item.index = index + i;
                    nodeHtml += that._renderItem({
                        group: groupData,
                        item: item
                    });
                }
                node = $(nodeHtml);
                if (!node.length) {
                    return;
                }
                that.angular('compile', function () {
                    return {
                        elements: node.get(),
                        data: nodeData.map(function (item) {
                            return { dataItem: item };
                        })
                    };
                });
                if (!group.length) {
                    group = $(that._renderGroup({ group: groupData })).appendTo(parentNode);
                }
                insertCallback(node, group);
                if (parentNode.hasClass('k-item')) {
                    updateNodeHtml(parentNode);
                    that._updateNodeClasses(parentNode, groupData, { expanded: !collapsed });
                }
                firstChild = node.prev().first();
                lastChild = node.next().last();
                that._updateNodeClasses(firstChild, {}, { expanded: firstChild.attr(kendo.attr('expanded')) == 'true' });
                that._updateNodeClasses(lastChild, {}, { expanded: lastChild.attr(kendo.attr('expanded')) == 'true' });
                for (i = 0; i < nodeData.length; i++) {
                    item = nodeData[i];
                    if (item.hasChildren) {
                        childrenData = item.children.data();
                        if (childrenData.length) {
                            that._insertNode(childrenData, item.index, node.eq(i), append, !item.expanded);
                        }
                    }
                }
                return node;
            },
            _updateNodes: function (items, field) {
                var that = this;
                var i, node, nodeWrapper, item, isChecked, isCollapsed;
                var context = {
                    treeview: that.options,
                    item: item
                };
                var render = field != 'expanded' && field != 'checked';
                function setCheckedState(root, state) {
                    if (root.is('.k-group')) {
                        root.find('.k-item:not([aria-disabled])').attr(ARIACHECKED, state);
                    }
                    root.find('.k-checkbox-wrapper input[type=checkbox]:not([disabled])').prop(CHECKED, state).data(INDETERMINATE, false).prop(INDETERMINATE, false);
                }
                if (field == 'selected') {
                    item = items[0];
                    node = that.findByUid(item.uid).find('.k-in:first').removeClass('k-state-hover').toggleClass('k-state-selected', item[field]).end();
                    if (item[field]) {
                        that.current(node);
                    }
                    node.attr(ARIASELECTED, !!item[field]);
                } else {
                    var elements = $.map(items, function (item) {
                        return that.findByUid(item.uid).children('div');
                    });
                    if (render) {
                        that.angular('cleanup', function () {
                            return { elements: elements };
                        });
                    }
                    for (i = 0; i < items.length; i++) {
                        context.item = item = items[i];
                        nodeWrapper = elements[i];
                        node = nodeWrapper.parent();
                        if (render) {
                            nodeWrapper.children('.k-in').html(that.templates.itemContent(context));
                        }
                        if (field == CHECKED) {
                            isChecked = item[field];
                            setCheckedState(nodeWrapper, isChecked);
                            node.attr(ARIACHECKED, isChecked);
                            if (that.options.checkboxes.checkChildren) {
                                setCheckedState(node.children('.k-group'), isChecked);
                                that._setChecked(item.children, isChecked);
                                that._bubbleIndeterminate(node);
                            }
                        } else if (field == 'expanded') {
                            that._toggle(node, item, item[field]);
                        } else if (field == 'enabled') {
                            node.find('.k-checkbox-wrapper input[type=checkbox]').prop('disabled', !item[field]);
                            isCollapsed = !nodeContents(node).is(VISIBLE);
                            node.removeAttr(ARIADISABLED);
                            if (!item[field]) {
                                if (item.selected) {
                                    item.set('selected', false);
                                }
                                if (item.expanded) {
                                    item.set('expanded', false);
                                }
                                isCollapsed = true;
                                node.attr(ARIASELECTED, false).attr(ARIADISABLED, true);
                            }
                            that._updateNodeClasses(node, {}, {
                                enabled: item[field],
                                expanded: !isCollapsed
                            });
                        }
                        if (nodeWrapper.length) {
                            this.trigger('itemChange', {
                                item: nodeWrapper,
                                data: item,
                                ns: ui
                            });
                        }
                    }
                    if (render) {
                        that.angular('compile', function () {
                            return {
                                elements: elements,
                                data: $.map(items, function (item) {
                                    return [{ dataItem: item }];
                                })
                            };
                        });
                    }
                }
            },
            _appendItems: function (index, items, parentNode) {
                var group = subGroup(parentNode);
                var children = group.children();
                var collapsed = !this._expanded(parentNode);
                if (this.element === parentNode) {
                    var dataItems = this.dataSource.data();
                    var viewItems = this.dataSource.view();
                    var rootItems = viewItems.length < dataItems.length ? viewItems : dataItems;
                    index = rootItems.indexOf(items[0]);
                } else if (items.length) {
                    index = items[0].parent().indexOf(items[0]);
                }
                if (typeof index == UNDEFINED) {
                    index = children.length;
                }
                this._insertNode(items, index, parentNode, function (item, group) {
                    if (index >= children.length) {
                        item.appendTo(group);
                    } else {
                        item.insertBefore(children.eq(index));
                    }
                }, collapsed);
                if (!collapsed) {
                    this._updateNodeClasses(parentNode, {}, { expanded: !collapsed });
                    subGroup(parentNode).css('display', 'block');
                }
            },
            _refreshChildren: function (parentNode, items, index) {
                var i, children, child;
                var options = this.options;
                var loadOnDemand = options.loadOnDemand;
                var checkChildren = options.checkboxes && options.checkboxes.checkChildren;
                subGroup(parentNode).empty();
                if (!items.length) {
                    updateNodeHtml(parentNode);
                } else {
                    this._appendItems(index, items, parentNode);
                    children = subGroup(parentNode).children();
                    if (loadOnDemand && checkChildren) {
                        this._bubbleIndeterminate(children.last());
                    }
                    for (i = 0; i < children.length; i++) {
                        child = children.eq(i);
                        this.trigger('itemChange', {
                            item: child.children('div'),
                            data: items[i],
                            ns: ui
                        });
                    }
                }
            },
            _refreshRoot: function (items) {
                var groupHtml = this._renderGroup({
                    items: items,
                    group: {
                        firstLevel: true,
                        expanded: true
                    }
                });
                if (this.root.length) {
                    this._angularItems('cleanup');
                    var group = $(groupHtml);
                    this.root.attr('class', group.attr('class')).html(group.html());
                } else {
                    this.root = this.wrapper.html(groupHtml).children('ul');
                }
                var elements = this.root.children('.k-item');
                for (var i = 0; i < items.length; i++) {
                    this.trigger('itemChange', {
                        item: elements.eq(i),
                        data: items[i],
                        ns: ui
                    });
                }
                this._angularItems('compile');
            },
            refresh: function (e) {
                var node = e.node;
                var action = e.action;
                var items = e.items;
                var parentNode = this.wrapper;
                var options = this.options;
                var loadOnDemand = options.loadOnDemand;
                var checkChildren = options.checkboxes && options.checkboxes.checkChildren;
                var i;
                if (this._skip) {
                    return;
                }
                for (i = 0; i < items.length; i++) {
                    this._dataSourceUids[items[i].uid] = items[i];
                }
                if (e.field) {
                    if (!items[0] || !items[0].level) {
                        return;
                    }
                    return this._updateNodes(items, e.field);
                }
                if (node) {
                    parentNode = this.findByUid(node.uid);
                    this._progress(parentNode, false);
                }
                if (checkChildren && action != 'remove') {
                    var bubble = false;
                    for (i = 0; i < items.length; i++) {
                        if ('checked' in items[i]) {
                            bubble = true;
                            break;
                        }
                    }
                    if (!bubble && node && node.checked) {
                        for (i = 0; i < items.length; i++) {
                            items[i].checked = true;
                        }
                    }
                }
                if (action == 'add') {
                    this._appendItems(e.index, items, parentNode);
                } else if (action == 'remove') {
                    this._remove(this.findByUid(items[0].uid), false);
                } else if (action == 'itemchange') {
                    this._updateNodes(items);
                } else if (action == 'itemloaded') {
                    this._refreshChildren(parentNode, items, e.index);
                } else {
                    this._refreshRoot(items);
                }
                if (action != 'remove') {
                    for (i = 0; i < items.length; i++) {
                        if (!loadOnDemand || items[i].expanded || items[i]._loaded) {
                            items[i].load();
                        }
                    }
                }
                this.trigger(DATABOUND, { node: node ? parentNode : undefined });
                if (this.dataSource.filter() && this.options.checkboxes.checkChildren) {
                    this.updateIndeterminate(parentNode);
                }
            },
            _error: function (e) {
                var node = e.node && this.findByUid(e.node.uid);
                var retryHtml = this.templates.retry({ messages: this.options.messages });
                if (node) {
                    this._progress(node, false);
                    this._expanded(node, false);
                    nodeIcon(node).addClass('k-i-reload');
                    e.node.loaded(false);
                } else {
                    this._progress(false);
                    this.element.html(retryHtml);
                }
            },
            _retryRequest: function (e) {
                e.preventDefault();
                this.dataSource.fetch();
            },
            expand: function (nodes) {
                this._processNodes(nodes, function (index, item) {
                    this.toggle(item, true);
                });
            },
            collapse: function (nodes) {
                this._processNodes(nodes, function (index, item) {
                    this.toggle(item, false);
                });
            },
            enable: function (nodes, enable) {
                if (typeof nodes === 'boolean') {
                    enable = nodes;
                    nodes = this.items();
                } else {
                    enable = arguments.length == 2 ? !!enable : true;
                }
                this._processNodes(nodes, function (index, item) {
                    this.dataItem(item).set('enabled', enable);
                });
            },
            current: function (node) {
                var that = this, current = that._current, element = that.element, id = that._ariaId;
                if (arguments.length > 0 && node && node.length) {
                    if (current) {
                        if (current[0].id === id) {
                            current.removeAttr('id');
                        }
                        current.find('.k-in:first').removeClass('k-state-focused');
                    }
                    current = that._current = $(node, element).closest(NODE);
                    current.find('.k-in:first').addClass('k-state-focused');
                    id = current[0].id || id;
                    if (id) {
                        that.wrapper.removeAttr('aria-activedescendant');
                        current.attr('id', id);
                        that.wrapper.attr('aria-activedescendant', id);
                    }
                    return;
                }
                if (!current) {
                    current = that._nextVisible($());
                }
                return current;
            },
            select: function (node) {
                var that = this, element = that.element;
                if (!arguments.length) {
                    return element.find('.k-state-selected').closest(NODE);
                }
                node = $(node, element).closest(NODE);
                element.find('.k-state-selected').each(function () {
                    var dataItem = that.dataItem(this);
                    if (dataItem) {
                        dataItem.set('selected', false);
                        delete dataItem.selected;
                    } else {
                        $(this).removeClass('k-state-selected');
                    }
                });
                if (node.length) {
                    that.dataItem(node).set('selected', true);
                    that._clickTarget = node;
                }
                that.trigger(CHANGE);
            },
            _toggle: function (node, dataItem, expand) {
                var options = this.options;
                var contents = nodeContents(node);
                var direction = expand ? 'expand' : 'collapse';
                var loaded;
                if (contents.data('animating')) {
                    return;
                }
                loaded = dataItem && dataItem.loaded();
                if (expand && !loaded) {
                    if (options.loadOnDemand) {
                        this._progress(node, true);
                    }
                    contents.remove();
                    dataItem.load();
                } else {
                    this._updateNodeClasses(node, {}, { expanded: expand });
                    if (!expand) {
                        contents.css('height', contents.height()).css('height');
                    }
                    contents.kendoStop(true, true).kendoAnimate(extend({ reset: true }, options.animation[direction], {
                        complete: function () {
                            if (expand) {
                                contents.css('height', '');
                            }
                        }
                    }));
                }
            },
            toggle: function (node, expand) {
                node = $(node);
                if (!nodeIcon(node).is('.k-i-expand, .k-i-collapse')) {
                    return;
                }
                if (arguments.length == 1) {
                    expand = !this._expanded(node);
                }
                this._expanded(node, expand);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.wrapper.off(NS);
                that.wrapper.find('.k-checkbox-wrapper :checkbox').off(NS);
                that._unbindDataSource();
                if (that.dragging) {
                    that.dragging.destroy();
                }
                that._dataSourceUids = {};
                kendo.destroy(that.element);
                that.root = that.wrapper = that.element = null;
            },
            _expanded: function (node, value, force) {
                var expandedAttr = kendo.attr('expanded');
                var dataItem;
                var expanded = value;
                var direction = expanded ? 'expand' : 'collapse';
                if (arguments.length == 1) {
                    dataItem = this._dataItem(node);
                    return node.attr(expandedAttr) === 'true' || dataItem && dataItem.expanded;
                }
                dataItem = this.dataItem(node);
                if (nodeContents(node).data('animating')) {
                    return;
                }
                if (force || !this._trigger(direction, node)) {
                    if (expanded) {
                        node.attr(expandedAttr, 'true');
                        node.attr('aria-expanded', 'true');
                    } else {
                        node.removeAttr(expandedAttr);
                        node.attr('aria-expanded', 'false');
                    }
                    if (dataItem) {
                        dataItem.set('expanded', expanded);
                        expanded = dataItem.expanded;
                    }
                }
            },
            _progress: function (node, showProgress) {
                var element = this.element;
                var loadingText = this.templates.loading({ messages: this.options.messages });
                if (arguments.length == 1) {
                    showProgress = node;
                    if (showProgress) {
                        element.html(loadingText);
                    } else {
                        element.empty();
                    }
                } else {
                    nodeIcon(node).toggleClass('k-i-loading', showProgress).removeClass('k-i-reload');
                }
            },
            text: function (node, text) {
                var dataItem = this.dataItem(node), fieldBindings = this.options[bindings.text], level = dataItem.level(), length = fieldBindings.length, field = fieldBindings[Math.min(level, length - 1)];
                if (text) {
                    dataItem.set(field, text);
                } else {
                    return dataItem[field];
                }
            },
            _objectOrSelf: function (node) {
                return $(node).closest('[data-role=treeview]').data('kendoTreeView') || this;
            },
            _dataSourceMove: function (nodeData, group, parentNode, callback) {
                var referenceDataItem, destTreeview = this._objectOrSelf(parentNode || group), destDataSource = destTreeview.dataSource;
                var loadPromise = $.Deferred().resolve().promise();
                if (parentNode && parentNode[0] != destTreeview.element[0]) {
                    referenceDataItem = destTreeview.dataItem(parentNode);
                    if (!referenceDataItem.loaded()) {
                        destTreeview._progress(parentNode, true);
                        loadPromise = referenceDataItem.load();
                    }
                    if (parentNode != this.root) {
                        destDataSource = referenceDataItem.children;
                        if (!destDataSource || !(destDataSource instanceof HierarchicalDataSource)) {
                            referenceDataItem._initChildren();
                            referenceDataItem.loaded(true);
                            destDataSource = referenceDataItem.children;
                        }
                    }
                }
                nodeData = this._toObservableData(nodeData);
                return callback.call(destTreeview, destDataSource, nodeData, loadPromise);
            },
            _toObservableData: function (node) {
                var dataItem = node, dataSource, uid;
                if (isJQueryInstance(node) || isDomElement(node)) {
                    dataSource = this._objectOrSelf(node).dataSource;
                    uid = $(node).attr(kendo.attr('uid'));
                    dataItem = dataSource.getByUid(uid);
                    if (dataItem) {
                        dataItem = dataSource.remove(dataItem);
                    }
                }
                return dataItem;
            },
            _insert: function (data, model, index) {
                if (!(model instanceof kendo.data.ObservableArray)) {
                    if (!isArray(model)) {
                        model = [model];
                    }
                } else {
                    model = model.toJSON();
                }
                var parentNode = data.parent();
                if (parentNode && parentNode._initChildren) {
                    parentNode.hasChildren = true;
                    parentNode._initChildren();
                }
                data.splice.apply(data, [
                    index,
                    0
                ].concat(model));
                return this.findByUid(data[index].uid);
            },
            insertAfter: insertAction(1),
            insertBefore: insertAction(0),
            append: function (nodeData, parentNode, success) {
                var group = this.root;
                if (parentNode && nodeData instanceof jQuery && parentNode[0] === nodeData[0]) {
                    return;
                }
                parentNode = parentNode && parentNode.length ? parentNode : null;
                if (parentNode) {
                    group = subGroup(parentNode);
                }
                return this._dataSourceMove(nodeData, group, parentNode, function (dataSource, model, loadModel) {
                    var inserted;
                    var that = this;
                    function add() {
                        if (parentNode) {
                            that._expanded(parentNode, true, true);
                        }
                        var data = dataSource.data(), index = Math.max(data.length, 0);
                        return that._insert(data, model, index);
                    }
                    loadModel.done(function () {
                        inserted = add();
                        success = success || $.noop;
                        success(inserted);
                    });
                    return inserted || null;
                });
            },
            _remove: function (node, keepData) {
                var that = this, parentNode, prevSibling, nextSibling;
                node = $(node, that.element);
                this.angular('cleanup', function () {
                    return { elements: node.get() };
                });
                parentNode = node.parent().parent();
                prevSibling = node.prev();
                nextSibling = node.next();
                node[keepData ? 'detach' : 'remove']();
                if (parentNode.hasClass('k-item')) {
                    updateNodeHtml(parentNode);
                    that._updateNodeClasses(parentNode);
                }
                that._updateNodeClasses(prevSibling);
                that._updateNodeClasses(nextSibling);
                return node;
            },
            remove: function (node) {
                var dataItem = this.dataItem(node);
                if (dataItem) {
                    this.dataSource.remove(dataItem);
                }
            },
            detach: function (node) {
                return this._remove(node, true);
            },
            findByText: function (text) {
                return $(this.element).find('.k-in').filter(function (i, element) {
                    return $(element).text() == text;
                }).closest(NODE);
            },
            findByUid: function (uid) {
                var items = this.element.find('.k-item');
                var uidAttr = kendo.attr('uid');
                var result;
                for (var i = 0; i < items.length; i++) {
                    if (items[i].getAttribute(uidAttr) == uid) {
                        result = items[i];
                        break;
                    }
                }
                return $(result);
            },
            expandPath: function (path, complete) {
                var treeview = this;
                var nodeIds = path.slice(0);
                var callback = complete || $.noop;
                function proceed() {
                    nodeIds.shift();
                    if (nodeIds.length) {
                        expand(nodeIds[0]).then(proceed);
                    } else {
                        callback.call(treeview);
                    }
                }
                function expand(id) {
                    var result = $.Deferred();
                    var node = treeview.dataSource.get(id);
                    if (node) {
                        if (node.loaded()) {
                            node.set('expanded', true);
                            result.resolve();
                        } else {
                            treeview._progress(treeview.findByUid(node.uid), true);
                            node.load().then(function () {
                                node.set('expanded', true);
                                result.resolve();
                            });
                        }
                    } else {
                        result.resolve();
                    }
                    return result.promise();
                }
                expand(nodeIds[0]).then(proceed);
            },
            _parentIds: function (node) {
                var parent = node && node.parentNode();
                var parents = [];
                while (parent && parent.parentNode) {
                    parents.unshift(parent.id);
                    parent = parent.parentNode();
                }
                return parents;
            },
            expandTo: function (node) {
                if (!(node instanceof kendo.data.Node)) {
                    node = this.dataSource.get(node);
                }
                var parents = this._parentIds(node);
                this.expandPath(parents);
            },
            _renderItem: function (options) {
                if (!options.group) {
                    options.group = {};
                }
                options.treeview = this.options;
                options.r = this.templates;
                return this.templates.item(options);
            },
            _renderGroup: function (options) {
                var that = this;
                options.renderItems = function (options) {
                    var html = '', i = 0, items = options.items, len = items ? items.length : 0, group = options.group;
                    group.length = len;
                    for (; i < len; i++) {
                        options.group = group;
                        options.item = items[i];
                        options.item.index = i;
                        html += that._renderItem(options);
                    }
                    return html;
                };
                options.r = that.templates;
                return that.templates.group(options);
            }
        });
        ui.plugin(TreeView);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dropdowntree/treeview', ['kendo.treeview'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, keys = kendo.keys, DISABLED = 'k-state-disabled', SELECT = 'select', CHECKED = 'checked', proxy = $.proxy, DATABOUND = 'dataBound', CLICK = 'click', NS = '.kendoTreeView', INDETERMINATE = 'indeterminate', NAVIGATE = 'navigate', subGroup, TreeView = ui.TreeView;
        function contentChild(filter) {
            return function (node) {
                var result = node.children('.k-animation-container');
                if (!result.length) {
                    result = node;
                }
                return result.children(filter);
            };
        }
        subGroup = contentChild('.k-group');
        var Tree = TreeView.extend({
            init: function (element, options, dropdowntree) {
                var that = this;
                that.dropdowntree = dropdowntree;
                TreeView.fn.init.call(that, element, options);
                if (that.dropdowntree._isMultipleSelection()) {
                    that.wrapper.on(CLICK + NS, '.k-in.k-state-selected', proxy(that._clickSelectedItem, that));
                }
            },
            _checkOnSelect: function (e) {
                if (!e.isDefaultPrevented()) {
                    var dataItem = this.dataItem(e.node);
                    dataItem.set('checked', !dataItem.checked);
                }
            },
            _setCheckedValue: function (node, value) {
                node.set(CHECKED, value);
            },
            _click: function (e) {
                var that = this;
                if (that.dropdowntree._isMultipleSelection()) {
                    that.one('select', that._checkOnSelect);
                }
                TreeView.fn._click.call(that, e);
            },
            _clickSelectedItem: function (e) {
                var that = this, node = $(e.currentTarget);
                that.one('select', that._checkOnSelect);
                if (!that._trigger(SELECT, node)) {
                    that.dataItem(node).set('selected', false);
                }
            },
            defaultrefresh: function (e) {
                var node = e.node;
                var action = e.action;
                var items = e.items;
                var parentNode = this.wrapper;
                var options = this.options;
                var loadOnDemand = options.loadOnDemand;
                var checkChildren = options.checkboxes && options.checkboxes.checkChildren;
                var i;
                if (this._skip) {
                    return;
                }
                if (e.field) {
                    if (!items[0] || !items[0].level) {
                        return;
                    }
                    return this._updateNodes(items, e.field);
                }
                if (node) {
                    parentNode = this.findByUid(node.uid);
                    this._progress(parentNode, false);
                }
                if (checkChildren && action != 'remove') {
                    var bubble = false;
                    for (i = 0; i < items.length; i++) {
                        if ('checked' in items[i]) {
                            bubble = true;
                            break;
                        }
                    }
                    if (!bubble && node && node.checked) {
                        for (i = 0; i < items.length; i++) {
                            items[i].checked = true;
                        }
                    }
                }
                if (action == 'add') {
                    this._appendItems(e.index, items, parentNode);
                } else if (action == 'remove') {
                    this._remove(this.findByUid(items[0].uid), false);
                } else if (action == 'itemchange') {
                    this._updateNodes(items);
                } else if (action == 'itemloaded') {
                    this._refreshChildren(parentNode, items, e.index);
                } else {
                    this._refreshRoot(items);
                }
                if (action != 'remove') {
                    for (i = 0; i < items.length; i++) {
                        if (!loadOnDemand || items[i].expanded) {
                            items[i].load();
                        }
                    }
                }
                this.trigger(DATABOUND, { node: node ? parentNode : undefined });
                this.dropdowntree._treeViewDataBound({
                    node: node ? parentNode : undefined,
                    sender: this
                });
                if (this.options.checkboxes.checkChildren) {
                    this.updateIndeterminate();
                }
            },
            _previousVisible: function (node) {
                var that = this, lastChild, result;
                if (!node.length || node.prev().length) {
                    if (node.length) {
                        result = node.prev();
                    } else {
                        result = that.root.children().last();
                    }
                    while (that._expanded(result)) {
                        lastChild = subGroup(result).children().last();
                        if (!lastChild.length) {
                            break;
                        }
                        result = lastChild;
                    }
                } else {
                    result = that.parent(node) || node;
                    if (!result.length) {
                        if (that.dropdowntree.checkAll && that.dropdowntree.checkAll.is(':visible')) {
                            that.dropdowntree.checkAll.find('.k-checkbox').focus();
                        } else if (that.dropdowntree.filterInput) {
                            that.dropdowntree.filterInput.focus();
                        } else {
                            that.dropdowntree.wrapper.focus();
                        }
                    }
                }
                return result;
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, target, focused = that.current(), expanded = that._expanded(focused), checkbox = focused.find('.k-checkbox-wrapper:first :checkbox'), rtl = kendo.support.isRtl(that.element);
                if (e.target != e.currentTarget) {
                    return;
                }
                if (!rtl && key == keys.RIGHT || rtl && key == keys.LEFT) {
                    if (expanded) {
                        target = that._nextVisible(focused);
                    } else if (!focused.find('.k-in:first').hasClass(DISABLED)) {
                        that.expand(focused);
                    }
                } else if (!rtl && key == keys.LEFT || rtl && key == keys.RIGHT) {
                    if (expanded && !focused.find('.k-in:first').hasClass(DISABLED)) {
                        that.collapse(focused);
                    } else {
                        target = that.parent(focused);
                        if (!that._enabled(target)) {
                            target = undefined;
                        }
                    }
                } else if (key == keys.DOWN) {
                    target = that._nextVisible(focused);
                } else if (key == keys.UP && !e.altKey) {
                    target = that._previousVisible(focused);
                } else if (key == keys.HOME) {
                    target = that._nextVisible($());
                } else if (key == keys.END) {
                    target = that._previousVisible($());
                } else if (key == keys.ENTER && !focused.find('.k-in:first').hasClass(DISABLED)) {
                    if (!focused.find('.k-in:first').hasClass('k-state-selected')) {
                        if (!that._trigger(SELECT, focused)) {
                            that.select(focused);
                        }
                    }
                } else if (key == keys.SPACEBAR && checkbox.length && !focused.find('.k-in:first').hasClass(DISABLED)) {
                    checkbox.prop(CHECKED, !checkbox.prop(CHECKED)).data(INDETERMINATE, false).prop(INDETERMINATE, false);
                    that._checkboxChange({ target: checkbox });
                    target = focused;
                } else if (e.altKey && key === keys.UP || key === keys.ESC) {
                    that._closePopup();
                }
                if (target) {
                    e.preventDefault();
                    if (focused[0] != target[0]) {
                        that._trigger(NAVIGATE, target);
                        that.current(target);
                    }
                }
            },
            _closePopup: function () {
                this.dropdowntree.close();
                this.dropdowntree.wrapper.focus();
            },
            refresh: function (e) {
                this.defaultrefresh(e);
                if (this.dropdowntree.options.skipUpdateOnBind) {
                    return;
                }
                if (e.action === 'itemchange') {
                    if (this.dropdowntree._isMultipleSelection()) {
                        if (e.field === 'checked') {
                            this.dropdowntree._checkValue(e.items[0]);
                        }
                    } else {
                        if (e.field !== 'checked' && e.field !== 'expanded' && e.items[0].selected) {
                            this.dropdowntree._selectValue(e.items[0]);
                        }
                    }
                } else {
                    this.dropdowntree.refresh(e);
                }
            }
        });
        kendo.ui._dropdowntree = Tree;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dropdowntree', [
        'dropdowntree/treeview',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dropdowntree',
        name: 'DropDownTree',
        category: 'web',
        description: 'The DropDownTree widget displays a hierarchy of items and allows the selection of single or multiple items.',
        depends: [
            'treeview',
            'popup'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, TreeView = ui._dropdowntree, ObservableArray = kendo.data.ObservableArray, ObservableObject = kendo.data.ObservableObject, extend = $.extend, activeElement = kendo._activeElement, ns = '.kendoDropDownTree', keys = kendo.keys, support = kendo.support, HIDDENCLASS = 'k-hidden', WIDTH = 'width', browser = support.browser, outerWidth = kendo._outerWidth, DOT = '.', DISABLED = 'disabled', READONLY = 'readonly', STATEDISABLED = 'k-state-disabled', ARIA_DISABLED = 'aria-disabled', HOVER = 'k-state-hover', FOCUSED = 'k-state-focused', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, TABINDEX = 'tabindex', CLICK = 'click', OPEN = 'open', CLOSE = 'close', CHANGE = 'change', quotRegExp = /"/g, proxy = $.proxy;
        var DropDownTree = kendo.ui.Widget.extend({
            init: function (element, options) {
                this.ns = ns;
                kendo.ui.Widget.fn.init.call(this, element, options);
                this._selection = this._getSelection();
                this._focusInputHandler = $.proxy(this._focusInput, this);
                this._initial = this.element.val();
                this._values = [];
                var value = this.options.value;
                if (value === null || !value.length) {
                    this._noInitialValue = true;
                }
                if (!this._isNullorUndefined(value)) {
                    this._valueMethodCalled = true;
                    this._values = $.isArray(value) ? value.slice(0) : [value];
                }
                this._inputTemplate();
                this._accessors();
                this._setTreeViewOptions(this.options);
                this._dataSource();
                this._selection._initWrapper();
                this._placeholder(true);
                this._tabindex();
                this.wrapper.data(TABINDEX, this.wrapper.attr(TABINDEX));
                this.tree = $('<div/>').attr({
                    tabIndex: -1,
                    'aria-hidden': true
                });
                this.list = $('<div class=\'k-list-container\'/>').append(this.tree);
                this._header();
                this._noData();
                this._footer();
                this._reset();
                this._popup();
                this.popup.one('open', proxy(this._popupOpen, this));
                this._clearButton();
                this._filterHeader();
                this._treeview();
                this._renderFooter();
                this._checkAll();
                this._enable();
                this._toggleCloseVisibility();
                if (!this.options.autoBind) {
                    var text = options.text || '';
                    if (!this._isNullorUndefined(options.value)) {
                        this._preselect(options.value);
                    } else if (text) {
                        this._textAccessor(text);
                    } else if (options.placeholder) {
                        this._placeholder(true);
                    }
                }
                var disabled = $(this.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    this.enable(false);
                }
                this._valueMethodCalled = false;
                kendo.notify(this);
            },
            _preselect: function (data, value) {
                this._selection._preselect(data, value);
            },
            _setTreeViewOptions: function (options) {
                var treeviewOptions = {
                    autoBind: options.autoBind,
                    checkboxes: options.checkboxes,
                    dataImageUrlField: options.dataImageUrlField,
                    dataSpriteCssClassField: options.dataSpriteCssClassField,
                    dataTextField: options.dataTextField,
                    dataUrlField: options.dataUrlField,
                    loadOnDemand: options.loadOnDemand
                };
                this.options.treeview = $.extend({}, treeviewOptions, this.options.treeview);
                if (options.template) {
                    this.options.treeview.template = options.template;
                }
            },
            _dataSource: function () {
                var rootDataSource = this.options.dataSource;
                this.dataSource = kendo.data.HierarchicalDataSource.create(rootDataSource);
                if (rootDataSource) {
                    $.extend(this.options.treeview, { dataSource: this.dataSource });
                }
            },
            _popupOpen: function () {
                var popup = this.popup;
                popup.wrapper = kendo.wrap(popup.element);
            },
            _getSelection: function () {
                if (this._isMultipleSelection()) {
                    return new ui.DropDownTree.MultipleSelection(this);
                } else {
                    return new ui.DropDownTree.SingleSelection(this);
                }
            },
            setDataSource: function (dataSource) {
                this.dataSource = dataSource;
                this.treeview.setDataSource(dataSource);
            },
            _isMultipleSelection: function () {
                return this.options && (this.options.treeview.checkboxes || this.options.checkboxes);
            },
            options: {
                name: 'DropDownTree',
                animation: {},
                autoBind: true,
                autoClose: true,
                autoWidth: false,
                clearButton: true,
                dataTextField: '',
                dataValueField: '',
                dataImageUrlField: '',
                dataSpriteCssClassField: '',
                dataUrlField: '',
                delay: 500,
                enabled: true,
                enforceMinLength: false,
                filter: 'none',
                height: 200,
                ignoreCase: true,
                index: 0,
                loadOnDemand: false,
                messages: {
                    'singleTag': 'item(s) selected',
                    'clear': 'clear',
                    'deleteTag': 'delete'
                },
                minLength: 1,
                checkboxes: false,
                noDataTemplate: 'No data found.',
                placeholder: '',
                checkAll: false,
                checkAllTemplate: 'Check all',
                tagMode: 'multiple',
                template: null,
                text: null,
                treeview: {},
                valuePrimitive: false,
                footerTemplate: '',
                headerTemplate: '',
                value: null,
                valueTemplate: null,
                popup: null
            },
            events: [
                'open',
                'close',
                'dataBound',
                CHANGE,
                'select',
                'filtering'
            ],
            focus: function () {
                this.wrapper.focus();
            },
            dataItem: function (node) {
                return this.treeview.dataItem(node);
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
                this._toggleCloseVisibility();
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
                this._toggleCloseVisibility();
            },
            toggle: function (open) {
                this._toggle(open);
            },
            open: function () {
                var popup = this.popup;
                if (!this.options.autoBind && !this.dataSource.data().length) {
                    this.treeview._progress(true);
                    if (this._isFilterEnabled()) {
                        this._search();
                    } else {
                        this.dataSource.fetch();
                    }
                }
                if (popup.visible() || !this._allowOpening()) {
                    return;
                }
                if (this._isMultipleSelection()) {
                    popup.element.addClass('k-multiple-selection');
                }
                popup.element.addClass('k-popup-dropdowntree');
                popup.one('activate', this._focusInputHandler);
                popup._hovered = true;
                popup.open();
            },
            close: function () {
                this.popup.close();
            },
            search: function (word) {
                var options = this.options;
                var filter;
                clearTimeout(this._typingTimeout);
                if (!options.enforceMinLength && !word.length || word.length >= options.minLength) {
                    filter = this._getFilter(word);
                    if (this.trigger('filtering', { filter: filter }) || $.isArray(this.options.dataTextField)) {
                        return;
                    }
                    this._filtering = true;
                    this.treeview.dataSource.filter(filter);
                }
            },
            _getFilter: function (word) {
                return {
                    field: this.options.dataTextField,
                    operator: this.options.filter,
                    value: word,
                    ignoreCase: this.options.ignoreCase
                };
            },
            refresh: function () {
                var data = this.treeview.dataSource.flatView();
                this._renderFooter();
                this._renderNoData();
                if (this.filterInput && this.checkAll) {
                    this.checkAll.toggle(!this.filterInput.val().length);
                }
                this.tree.toggle(!!data.length);
                $(this.noData).toggle(!data.length);
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._setTreeViewOptions(options);
                this._dataSource();
                if (this.options.treeview) {
                    this.treeview.setOptions(this.options.treeview);
                }
                if (options.height && this.tree) {
                    this.tree.css('max-height', options.height);
                }
                this._header();
                this._noData();
                this._footer();
                this._renderFooter();
                this._renderNoData();
                if (this.span && (this._isMultipleSelection() || this.span.hasClass('k-readonly'))) {
                    this._placeholder(true);
                }
                this._inputTemplate();
                this._accessors();
                this._filterHeader();
                this._checkAll();
                this._enable();
                if (options && (options.enable || options.enabled)) {
                    this.enable(true);
                }
                this._clearButton();
            },
            destroy: function () {
                kendo.ui.Widget.fn.destroy.call(this);
                if (this.treeview) {
                    this.treeview.destroy();
                }
                this.popup.destroy();
                this.wrapper.off(ns);
                this._clear.off(ns);
                this._inputWrapper.off(ns);
                if (this.filterInput) {
                    this.filterInput.off(ns);
                }
                if (this.tagList) {
                    this.tagList.off(ns);
                }
                kendo.unbind(this.tagList);
                if (this.options.checkAll && this.checkAll) {
                    this.checkAll.off(ns);
                }
                if (this._form) {
                    this._form.off('reset', this._resetHandler);
                }
            },
            setValue: function (value) {
                value = $.isArray(value) || value instanceof ObservableArray ? value.slice(0) : [value];
                this._values = value;
            },
            items: function () {
                this.treeview.dataItems();
            },
            value: function (value) {
                var that = this;
                if (value) {
                    if (that.filterInput && that.dataSource._filter) {
                        that._filtering = true;
                        that.dataSource.filter({});
                    } else if (!that.dataSource.data().length) {
                        that.dataSource.fetch(function () {
                            that._selection._setValue(value);
                        });
                        return;
                    }
                }
                return that._selection._setValue(value);
            },
            text: function (text) {
                var loweredText;
                var ignoreCase = this.options.ignoreCase;
                text = text === null ? '' : text;
                if (text !== undefined && !this._isMultipleSelection()) {
                    if (typeof text !== 'string') {
                        this._textAccessor(text);
                        return;
                    }
                    loweredText = ignoreCase ? text : text.toLowerCase();
                    this._selectItemByText(loweredText);
                    this._textAccessor(loweredText);
                } else {
                    return this._textAccessor();
                }
            },
            _header: function () {
                var list = this;
                var header = $(list.header);
                var template = list.options.headerTemplate;
                this._angularElement(header, 'cleanup');
                kendo.destroy(header);
                header.remove();
                if (!template) {
                    list.header = null;
                    return;
                }
                var headerTemplate = typeof template !== 'function' ? kendo.template(template) : template;
                header = $(headerTemplate({}));
                list.header = header[0] ? header : null;
                list.list.prepend(header);
                this._angularElement(list.header, 'compile');
            },
            _noData: function () {
                var list = this;
                var noData = $(list.noData);
                var template = list.options.noDataTemplate;
                list.angular('cleanup', function () {
                    return { elements: noData };
                });
                kendo.destroy(noData);
                noData.remove();
                if (!template) {
                    list.noData = null;
                    return;
                }
                list.noData = $('<div class="k-nodata" style="display:none"><div></div></div>').appendTo(list.list);
                list.noDataTemplate = typeof template !== 'function' ? kendo.template(template) : template;
            },
            _renderNoData: function () {
                var list = this;
                var noData = list.noData;
                if (!noData) {
                    return;
                }
                this._angularElement(noData, 'cleanup');
                noData.children(':first').html(list.noDataTemplate({ instance: list }));
                this._angularElement(noData, 'compile');
            },
            _footer: function () {
                var list = this;
                var footer = $(list.footer);
                var template = list.options.footerTemplate;
                this._angularElement(footer, 'cleanup');
                kendo.destroy(footer);
                footer.remove();
                if (!template) {
                    list.footer = null;
                    return;
                }
                list.footer = $('<div class="k-footer"></div>').appendTo(list.list);
                list.footerTemplate = typeof template !== 'function' ? kendo.template(template) : template;
            },
            _renderFooter: function () {
                var list = this;
                var footer = list.footer;
                if (!footer) {
                    return;
                }
                this._angularElement(footer, 'cleanup');
                footer.html(list.footerTemplate({ instance: list }));
                this._angularElement(footer, 'compile');
            },
            _enable: function () {
                var that = this, options = that.options, disabled = that.element.is('[disabled]');
                if (options.enable !== undefined) {
                    options.enabled = options.enable;
                }
                if (!options.enabled || disabled) {
                    that.enable(false);
                } else {
                    that.readonly(that.element.is('[readonly]'));
                }
            },
            _adjustListWidth: function () {
                var that = this, list = that.list, width = list[0].style.width, wrapper = that.wrapper, computedStyle, computedWidth;
                if (!list.data(WIDTH) && width) {
                    return;
                }
                computedStyle = window.getComputedStyle ? window.getComputedStyle(wrapper[0], null) : 0;
                computedWidth = parseFloat(computedStyle && computedStyle.width) || outerWidth(wrapper);
                if (computedStyle && browser.msie) {
                    computedWidth += parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) + parseFloat(computedStyle.borderLeftWidth) + parseFloat(computedStyle.borderRightWidth);
                }
                if (list.css('box-sizing') !== 'border-box') {
                    width = computedWidth - (outerWidth(list) - list.width());
                } else {
                    width = computedWidth;
                }
                list.css({
                    fontFamily: wrapper.css('font-family'),
                    width: that.options.autoWidth ? 'auto' : width,
                    minWidth: width,
                    whiteSpace: that.options.autoWidth ? 'nowrap' : 'normal'
                }).data(WIDTH, width);
                return true;
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(that._initial);
                        });
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            },
            _popup: function () {
                var list = this;
                list.popup = new ui.Popup(list.list, extend({}, list.options.popup, {
                    anchor: list.wrapper,
                    open: proxy(list._openHandler, list),
                    close: proxy(list._closeHandler, list),
                    animation: list.options.animation,
                    isRtl: support.isRtl(list.wrapper),
                    autosize: list.options.autoWidth
                }));
            },
            _angularElement: function (element, action) {
                if (!element) {
                    return;
                }
                this.angular(action, function () {
                    return { elements: element };
                });
            },
            _allowOpening: function () {
                return this.options.noDataTemplate || this.treeview.dataSource.flatView().length;
            },
            _placeholder: function (show) {
                if (this.span) {
                    this.span.toggleClass('k-readonly', show).text(show ? this.options.placeholder : '');
                }
            },
            _currentValue: function (dataItem) {
                var currentValue = this._value(dataItem);
                if (!currentValue && currentValue !== 0) {
                    currentValue = dataItem;
                }
                return currentValue;
            },
            _checkValue: function (dataItem) {
                var value = '';
                var indexOfValue = -1;
                var currentValue = this.value();
                var isMultiple = this.options.tagMode === 'multiple';
                if (dataItem || dataItem === 0) {
                    if (dataItem.level) {
                        dataItem._level = dataItem.level();
                    }
                    value = this._currentValue(dataItem);
                    indexOfValue = currentValue.indexOf(value);
                }
                if (dataItem.checked) {
                    var alreadyAddedTag = $.grep(this._tags, function (item) {
                        return item.uid === dataItem._tagUid;
                    });
                    if (alreadyAddedTag.length) {
                        return;
                    }
                    var itemToAdd = new ObservableObject(dataItem.toJSON());
                    dataItem._tagUid = itemToAdd.uid;
                    this._tags.push(itemToAdd);
                    if (this._tags.length === 1) {
                        this.span.hide();
                        if (!isMultiple) {
                            this._multipleTags.push(itemToAdd);
                        }
                    }
                    if (indexOfValue === -1) {
                        currentValue.push(value);
                        this.setValue(currentValue);
                    }
                } else {
                    var itemToRemove = this._tags.find(function (item) {
                        return item.uid === dataItem._tagUid;
                    });
                    var idx = this._tags.indexOf(itemToRemove);
                    if (idx !== -1) {
                        this._tags.splice(idx, 1);
                    } else {
                        this._treeViewCheckAllCheck(dataItem);
                        return;
                    }
                    if (this._tags.length === 0) {
                        this.span.show();
                        if (!isMultiple) {
                            this._multipleTags.splice(0, 1);
                        }
                    }
                    if (indexOfValue !== -1) {
                        currentValue.splice(indexOfValue, 1);
                        this.setValue(currentValue);
                    }
                }
                this._treeViewCheckAllCheck(dataItem);
                if (!this._preventChangeTrigger && !this._valueMethodCalled && !this._noInitialValue) {
                    this.trigger(CHANGE);
                }
                if (this.options.autoClose && this.popup.visible()) {
                    this.close();
                    this.wrapper.focus();
                }
                this.popup.position();
                this._toggleCloseVisibility();
                this._updateSelectedOptions();
            },
            _updateSelectedOptions: function () {
                if (this.element[0].tagName.toLowerCase() !== 'select') {
                    return;
                }
                var selectedItems = this._tags;
                var options = '';
                var dataItem = null;
                var value = null;
                if (selectedItems.length) {
                    for (var idx = 0; idx < selectedItems.length; idx++) {
                        dataItem = selectedItems[idx];
                        value = this._value(dataItem);
                        options += this._option(value, this._text(dataItem), true);
                    }
                }
                this.element.html(options);
            },
            _option: function (dataValue, dataText, selected) {
                var option = '<option';
                if (dataValue !== undefined) {
                    dataValue += '';
                    if (dataValue.indexOf('"') !== -1) {
                        dataValue = dataValue.replace(quotRegExp, '&quot;');
                    }
                    option += ' value="' + dataValue + '"';
                }
                if (selected) {
                    option += ' selected';
                }
                option += '>';
                if (dataText !== undefined) {
                    option += kendo.htmlEncode(dataText);
                }
                return option += '</option>';
            },
            _selectValue: function (dataItem) {
                var value = '';
                var text = '';
                if (dataItem || dataItem === 0) {
                    if (dataItem.level) {
                        dataItem._level = dataItem.level();
                    }
                    text = this._text(dataItem) || dataItem;
                    value = this._currentValue(dataItem);
                }
                if (value === null) {
                    value = '';
                }
                this.setValue(value);
                this._textAccessor(text, dataItem);
                this._accessor(value);
                if (!this._valueMethodCalled) {
                    this.trigger(CHANGE);
                }
                this._valueMethodCalled = false;
                if (this.options.autoClose && this.popup.visible()) {
                    this.close();
                    this.wrapper.focus();
                }
                this.popup.position();
                this._toggleCloseVisibility();
            },
            _clearClick: function (e) {
                e.stopPropagation();
                this._clearTextAndValue();
            },
            _clearTextAndValue: function () {
                this.setValue([]);
                this._clearInput();
                this._clearText();
                this._selection._clearValue();
                this.popup.position();
                this._toggleCloseVisibility();
            },
            _clearText: function () {
                if (this.options.placeholder) {
                    this._placeholder(true);
                } else {
                    if (this.span) {
                        this.span.html('');
                    }
                }
            },
            _inputTemplate: function () {
                var template = this.options.valueTemplate;
                if (!template) {
                    template = $.proxy(kendo.template('#:this._text(data)#', { useWithBlock: false }), this);
                } else {
                    template = kendo.template(template);
                }
                this.valueTemplate = template;
            },
            _assignInstance: function (text, value) {
                var dataTextField = this.options.dataTextField;
                var dataItem = {};
                if (dataTextField) {
                    assign(dataItem, dataTextField.split(DOT), text);
                    assign(dataItem, this.options.dataValueField.split(DOT), value);
                    dataItem = new ObservableObject(dataItem);
                } else {
                    dataItem = text;
                }
                return dataItem;
            },
            _textAccessor: function (text, dataItem) {
                var valueTemplate = this.valueTemplate;
                var span = this.span;
                if (text === undefined) {
                    return span.text();
                }
                span.removeClass('k-readonly');
                if (!dataItem && ($.isPlainObject(text) || text instanceof ObservableObject)) {
                    dataItem = text;
                }
                if (!dataItem) {
                    dataItem = this._assignInstance(text, this._accessor());
                }
                var getElements = function () {
                    return {
                        elements: span.get(),
                        data: [{ dataItem: dataItem }]
                    };
                };
                this.angular('cleanup', getElements);
                try {
                    span.html(valueTemplate(dataItem));
                } catch (e) {
                    if (span) {
                        span.html('');
                    }
                }
                this.angular('compile', getElements);
            },
            _accessors: function () {
                var element = this.element;
                var options = this.options;
                var getter = kendo.getter;
                var textField = element.attr(kendo.attr('text-field'));
                var valueField = element.attr(kendo.attr('value-field'));
                var getterFunction = function (field) {
                    if ($.isArray(field)) {
                        var count = field.length;
                        var levels = $.map(field, function (x) {
                            return function (d) {
                                return d[x];
                            };
                        });
                        return function (dataItem) {
                            var level = dataItem._level;
                            if (!level && level !== 0) {
                                return;
                            }
                            return levels[Math.min(level, count - 1)](dataItem);
                        };
                    } else {
                        return getter(field);
                    }
                };
                if (!options.dataTextField && textField) {
                    options.dataTextField = textField;
                }
                if (!options.dataValueField && valueField) {
                    options.dataValueField = valueField;
                }
                options.dataTextField = options.dataTextField || 'text';
                options.dataValueField = options.dataValueField || 'value';
                this._text = getterFunction(options.dataTextField);
                this._value = getterFunction(options.dataValueField);
            },
            _accessor: function (value, idx) {
                return this._accessorInput(value, idx);
            },
            _accessorInput: function (value) {
                var element = this.element[0];
                if (value === undefined) {
                    return element.value;
                } else {
                    if (value === null) {
                        value = '';
                    }
                    element.value = value;
                }
            },
            _clearInput: function () {
                var element = this.element[0];
                element.value = '';
            },
            _clearButton: function () {
                var clearTitle = this.options.messages && this.options.messages.clear ? this.options.messages.clear : 'clear';
                if (!this._clear) {
                    this._clear = $('<span unselectable="on" class="k-icon k-clear-value k-i-close" title="' + clearTitle + '"></span>').attr({
                        'role': 'button',
                        'tabIndex': -1
                    });
                }
                if (this.options.clearButton) {
                    this._clear.insertAfter(this.span);
                    this.wrapper.addClass('k-dropdowntree-clearable');
                } else {
                    if (!this.options.clearButton) {
                        this._clear.remove();
                    }
                }
            },
            _toggleCloseVisibility: function () {
                var isReadOnly = this.element.attr(READONLY);
                var hasValue = this.value() && !this._isMultipleSelection() || this.value().length;
                var valueDoesNotEqualPlaceHolder = this.element.val() && this.element.val() !== this.options.placeholder;
                if (!isReadOnly && (hasValue || valueDoesNotEqualPlaceHolder)) {
                    this._showClear();
                } else {
                    this._hideClear();
                }
            },
            _showClear: function () {
                if (this._clear) {
                    this._clear.removeClass(HIDDENCLASS);
                }
            },
            _hideClear: function () {
                if (this._clear) {
                    this._clear.addClass(HIDDENCLASS);
                }
            },
            _openHandler: function (e) {
                this._adjustListWidth();
                if (this.trigger(OPEN)) {
                    e.preventDefault();
                } else {
                    this.wrapper.attr('aria-expanded', true);
                    this.tree.attr('aria-hidden', false).attr('role', 'tree');
                }
            },
            _closeHandler: function (e) {
                if (this.trigger(CLOSE)) {
                    e.preventDefault();
                } else {
                    this.wrapper.attr('aria-expanded', false);
                    this.tree.attr('aria-hidden', true);
                }
            },
            _treeview: function () {
                var that = this;
                if (that.options.height) {
                    that.tree.css('max-height', that.options.height);
                }
                that.tree.attr('id', kendo.guid());
                that.treeview = new TreeView(that.tree, extend({ select: that.options.select }, that.options.treeview), that);
                that.dataSource = that.treeview.dataSource;
            },
            _treeViewDataBound: function (e) {
                if (e.node && this._prev && this._prev.length) {
                    e.sender.expand(e.node);
                }
                if (this._filtering) {
                    if (!e.node) {
                        this._filtering = false;
                    }
                    if (!this._isMultipleSelection()) {
                        this._deselectItem(e);
                    }
                    return;
                }
                if (!this.treeview) {
                    this.treeview = e.sender;
                }
                if (!e.node) {
                    var rootItems = e.sender.dataSource.data();
                    this._checkLoadedItems(rootItems);
                    if (this._noInitialValue) {
                        this._noInitialValue = false;
                    }
                } else {
                    var rootItem = e.sender.dataItem(e.node);
                    if (rootItem) {
                        var subItems = rootItem.children.data();
                        this._checkLoadedItems(subItems);
                    }
                }
                this.trigger('dataBound', e);
            },
            _deselectItem: function (e) {
                var items = [];
                if (!e.node) {
                    items = e.sender.dataSource.data();
                } else {
                    var rootItem = e.sender.dataItem(e.node);
                    if (rootItem) {
                        items = rootItem.children.data();
                    }
                }
                for (var i = 0; i < items.length; i++) {
                    if (items[i].selected && !this._valueComparer(items[i], this.value())) {
                        items[i].set('selected', false);
                    }
                }
            },
            _checkLoadedItems: function (items) {
                var value = this.value();
                if (!items) {
                    return;
                }
                for (var idx = 0; idx < items.length; idx++) {
                    this._selection._checkLoadedItem(items[idx], value);
                }
            },
            _treeViewCheckAllCheck: function (dataItem) {
                if (this.options.checkAll && this.checkAll) {
                    this._getAllChecked();
                    if (dataItem.checked) {
                        this._checkCheckAll();
                    } else {
                        this._uncheckCheckAll();
                    }
                }
            },
            _checkCheckAll: function () {
                var checkAllCheckbox = this.checkAll.find('.k-checkbox');
                if (this._allItemsAreChecked) {
                    checkAllCheckbox.prop('checked', true).prop('indeterminate', false);
                } else {
                    checkAllCheckbox.prop('indeterminate', true);
                }
            },
            _uncheckCheckAll: function () {
                var checkAllCheckbox = this.checkAll.find('.k-checkbox');
                if (this._allItemsAreUnchecked) {
                    checkAllCheckbox.prop('checked', false).prop('indeterminate', false);
                } else {
                    checkAllCheckbox.prop('indeterminate', true);
                }
            },
            _filterHeader: function () {
                var icon;
                if (this.filterInput) {
                    this.filterInput.off(ns).parent().remove();
                    this.filterInput = null;
                }
                if (this._isFilterEnabled()) {
                    this._disableCheckChildren();
                    icon = '<span class="k-icon k-i-zoom"></span>';
                    this.filterInput = $('<input class="k-textbox"/>').attr({
                        placeholder: this.element.attr('placeholder'),
                        title: this.element.attr('title'),
                        role: 'listbox',
                        'aria-haspopup': true,
                        'aria-expanded': false
                    });
                    this.filterInput.on('input', proxy(this._filterChange, this));
                    $('<span class="k-list-filter" />').insertBefore(this.tree).append(this.filterInput.add(icon));
                }
            },
            _filterChange: function () {
                if (this.filterInput) {
                    this._search();
                }
            },
            _disableCheckChildren: function () {
                if (this._isMultipleSelection() && this.options.treeview.checkboxes && this.options.treeview.checkboxes.checkChildren) {
                    this.options.treeview.checkboxes.checkChildren = false;
                }
            },
            _checkAll: function () {
                if (this.checkAll) {
                    this.checkAll.find('.k-checkbox-label, .k-checkbox').off(ns);
                    this.checkAll.remove();
                    this.checkAll = null;
                }
                if (this._isMultipleSelection() && this.options.checkAll) {
                    this.checkAll = $('<div class="k-check-all"><input type="checkbox" class="k-checkbox"/><span class="k-checkbox-label">Check All</span></div>').insertBefore(this.tree);
                    this.checkAll.find('.k-checkbox-label').html(kendo.template(this.options.checkAllTemplate)({ instance: this }));
                    this.checkAll.find('.k-checkbox-label').on(CLICK + ns, proxy(this._clickCheckAll, this));
                    this.checkAll.find('.k-checkbox').on('change' + ns, proxy(this._changeCheckAll, this)).on('keydown' + ns, proxy(this._keydownCheckAll, this));
                    this._disabledCheckedItems = [];
                    this._disabledUnCheckedItems = [];
                    this._getAllChecked();
                    if (!this._allItemsAreUnchecked) {
                        this._checkCheckAll();
                    }
                }
            },
            _changeCheckAll: function () {
                var checkAllCheckbox = this.checkAll.find('.k-checkbox');
                var isChecked = checkAllCheckbox.prop('checked');
                if (!browser.msie && !browser.edge) {
                    this._updateCheckAll(isChecked);
                }
            },
            _updateCheckAll: function (isChecked) {
                var checkAllCheckbox = this.checkAll.find('.k-checkbox');
                this._toggleCheckAllItems(isChecked);
                checkAllCheckbox.prop('checked', isChecked);
                if (this._disabledCheckedItems.length && this._disabledUnCheckedItems.length) {
                    checkAllCheckbox.prop('indeterminate', true);
                } else if (this._disabledCheckedItems.length) {
                    checkAllCheckbox.prop('indeterminate', !isChecked);
                } else if (this._disabledUnCheckedItems.length) {
                    checkAllCheckbox.prop('indeterminate', isChecked);
                } else {
                    checkAllCheckbox.prop('indeterminate', false);
                }
                this._disabledCheckedItems = [];
                this._disabledUnCheckedItems = [];
            },
            _keydownCheckAll: function (e) {
                var key = e.keyCode;
                var altKey = e.altKey;
                if (altKey && key === keys.UP || key === keys.ESC) {
                    this.close();
                    this.wrapper.focus();
                    e.preventDefault();
                    return;
                }
                if (key === keys.UP) {
                    if (this.filterInput) {
                        this.filterInput.focus();
                    } else {
                        this.wrapper.focus();
                    }
                    e.preventDefault();
                }
                if (key === keys.DOWN) {
                    if (this.tree && this.tree.is(':visible')) {
                        this.tree.focus();
                    }
                    e.preventDefault();
                }
                if (key === keys.SPACEBAR && (browser.msie || browser.edge)) {
                    this._clickCheckAll();
                    e.preventDefault();
                }
            },
            _clickCheckAll: function () {
                var checkAllCheckbox = this.checkAll.find('.k-checkbox');
                var isChecked = checkAllCheckbox.prop('checked');
                this._updateCheckAll(!isChecked);
                checkAllCheckbox.focus();
            },
            _dfs: function (items, action, prop) {
                for (var idx = 0; idx < items.length; idx++) {
                    if (!this[action](items[idx], prop)) {
                        break;
                    }
                    this._traverceChildren(items[idx], action, prop);
                }
            },
            _uncheckItemByUid: function (uid) {
                this._dfs(this.dataSource.data(), '_uncheckItemEqualsUid', uid);
            },
            _uncheckItemEqualsUid: function (item, uid) {
                if (item.enabled !== false && item._tagUid == uid) {
                    item.set('checked', false);
                    return false;
                }
                return true;
            },
            _selectItemByText: function (text) {
                this._dfs(this.dataSource.data(), '_itemEqualsText', text);
            },
            _itemEqualsText: function (item, text) {
                if (item.enabled !== false && this._text(item) === text) {
                    this.treeview.select(this.treeview.findByUid(item.uid));
                    this._selectValue(item);
                    return false;
                }
                return true;
            },
            _selectItemByValue: function (value) {
                this._dfs(this.dataSource.data(), '_itemEqualsValue', value);
            },
            _itemEqualsValue: function (item, value) {
                if (item.enabled !== false && this._valueComparer(item, value)) {
                    this.treeview.select(this.treeview.findByUid(item.uid));
                    return false;
                }
                return true;
            },
            _checkItemByValue: function (value) {
                var items = this.treeview.dataItems();
                for (var idx = 0; idx < value.length; idx++) {
                    this._dfs(items, '_checkItemEqualsValue', value[idx]);
                }
            },
            _checkItemEqualsValue: function (item, value) {
                if (item.enabled !== false && this._valueComparer(item, value)) {
                    item.set('checked', true);
                    return false;
                }
                return true;
            },
            _valueComparer: function (item, value) {
                var itemValue = this._value(item);
                var itemText;
                if (!this._isNullorUndefined(itemValue)) {
                    if (this._isNullorUndefined(value)) {
                        return false;
                    }
                    var newValue = this._value(value);
                    if (newValue) {
                        return itemValue == newValue;
                    } else {
                        return itemValue == value;
                    }
                }
                itemText = this._text(item);
                if (itemText) {
                    if (this._text(value)) {
                        return itemText == this._text(value);
                    } else {
                        return itemText == value;
                    }
                }
                return false;
            },
            _isNullorUndefined: function (value) {
                return value === undefined || value === null;
            },
            _getAllChecked: function () {
                this._allCheckedItems = [];
                this._allItemsAreChecked = true;
                this._allItemsAreUnchecked = true;
                this._dfs(this.dataSource.data(), '_getAllCheckedItems');
                return this._allCheckedItems;
            },
            _getAllCheckedItems: function (item) {
                if (this._allItemsAreChecked) {
                    this._allItemsAreChecked = item.checked;
                }
                if (this._allItemsAreUnchecked) {
                    this._allItemsAreUnchecked = !item.checked;
                }
                if (item.checked) {
                    this._allCheckedItems.push(item);
                }
                return true;
            },
            _traverceChildren: function (item, action, prop) {
                var childrenField = item._childrenOptions && item._childrenOptions.schema ? item._childrenOptions.schema.data : null;
                var subItems = item[childrenField] || item.items || item.children;
                if (!subItems) {
                    return;
                }
                this._dfs(subItems, action, prop);
            },
            _toggleCheckAllItems: function (checked) {
                this._dfs(this.dataSource.data(), '_checkAllCheckItem', checked);
            },
            _checkAllCheckItem: function (item, checked) {
                if (item.enabled === false) {
                    if (item.checked) {
                        this._disabledCheckedItems.push(item);
                    } else {
                        this._disabledUnCheckedItems.push(item);
                    }
                } else {
                    item.set('checked', checked);
                }
                return true;
            },
            _isFilterEnabled: function () {
                var filter = this.options.filter;
                return filter && filter !== 'none';
            },
            _editable: function (options) {
                var that = this;
                var element = that.element;
                var disable = options.disable;
                var readonly = options.readonly;
                var wrapper = that.wrapper.add(that.filterInput).off(ns);
                var dropDownWrapper = that._inputWrapper.off(HOVEREVENTS);
                if (that._isMultipleSelection()) {
                    that.tagList.off(CLICK + ns);
                }
                if (!readonly && !disable) {
                    element.removeAttr(DISABLED).removeAttr(READONLY);
                    dropDownWrapper.removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    that._clear.on('click' + ns, proxy(that._clearClick, that));
                    wrapper.attr(TABINDEX, wrapper.data(TABINDEX)).attr(ARIA_DISABLED, false).on('keydown' + ns, proxy(that._keydown, that)).on('focusin' + ns, proxy(that._focusinHandler, that)).on('focusout' + ns, proxy(that._focusoutHandler, that));
                    that.wrapper.on(CLICK + ns, proxy(that._wrapperClick, that));
                    if (this._isMultipleSelection()) {
                        that.tagList.on(CLICK + ns, 'li.k-button', function (e) {
                            $(e.currentTarget).addClass(FOCUSED);
                        });
                        that.tagList.on(CLICK + ns, '.k-select', function (e) {
                            that._removeTagClick(e);
                        });
                    }
                } else if (disable) {
                    wrapper.removeAttr(TABINDEX);
                    dropDownWrapper.addClass(STATEDISABLED);
                } else {
                    wrapper.attr(TABINDEX, wrapper.data(TABINDEX));
                    dropDownWrapper.removeClass(STATEDISABLED);
                    wrapper.on('focusin' + ns, proxy(that._focusinHandler, that)).on('focusout' + ns, proxy(that._focusoutHandler, that));
                }
                element.attr(DISABLED, disable).attr(READONLY, readonly);
                wrapper.attr(ARIA_DISABLED, disable);
            },
            _focusinHandler: function () {
                this._inputWrapper.addClass(FOCUSED);
                this._prevent = false;
            },
            _focusoutHandler: function () {
                var that = this;
                if (this._isMultipleSelection()) {
                    this.tagList.find(DOT + FOCUSED).removeClass(FOCUSED);
                }
                if (!that._prevent) {
                    this._inputWrapper.removeClass(FOCUSED);
                    that._prevent = true;
                    that.element.blur();
                }
            },
            _toggle: function (open) {
                open = open !== undefined ? open : !this.popup.visible();
                this[open ? OPEN : CLOSE]();
            },
            _wrapperClick: function (e) {
                e.preventDefault();
                this.popup.unbind('activate', this._focusInputHandler);
                this._focused = this.wrapper;
                this._prevent = false;
                this._toggle();
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _focusInput: function () {
                if (this.filterInput) {
                    this.filterInput.focus();
                } else if (this.checkAll) {
                    this.checkAll.find('.k-checkbox').focus();
                } else if (this.tree.is(':visible')) {
                    this.tree.focus();
                }
            },
            _keydown: function (e) {
                var key = e.keyCode;
                var altKey = e.altKey;
                var isFilterInputActive;
                var isWrapperActive;
                var focused, tagItem;
                var isPopupVisible = this.popup.visible();
                if (this.filterInput) {
                    isFilterInputActive = this.filterInput[0] === activeElement();
                }
                if (this.wrapper) {
                    isWrapperActive = this.wrapper[0] === activeElement();
                }
                if (isWrapperActive) {
                    if (key === keys.ESC) {
                        this._clearTextAndValue();
                        e.preventDefault();
                        return;
                    }
                    if (this._isMultipleSelection()) {
                        if (key === keys.LEFT) {
                            this._focusPrevTag();
                            e.preventDefault();
                            return;
                        }
                        if (key === keys.RIGHT) {
                            this._focusNextTag();
                            e.preventDefault();
                            return;
                        }
                        if (key === keys.HOME) {
                            this._focusFirstTag();
                            e.preventDefault();
                            return;
                        }
                        if (key === keys.END) {
                            this._focusLastTag();
                            e.preventDefault();
                            return;
                        }
                        if (key === keys.DELETE) {
                            focused = this.tagList.find(DOT + FOCUSED).first();
                            if (focused.length) {
                                tagItem = this._tags[focused.index()];
                                this._removeTag(tagItem);
                            }
                            e.preventDefault();
                            return;
                        }
                        if (key === keys.BACKSPACE) {
                            focused = this.tagList.find(DOT + FOCUSED).first();
                            if (focused.length) {
                                tagItem = this._tags[focused.index()];
                                this._removeTag(tagItem);
                            } else {
                                focused = this._focusLastTag();
                                if (focused.length) {
                                    tagItem = this._tags[focused.index()];
                                    this._removeTag(tagItem);
                                }
                            }
                            e.preventDefault();
                            return;
                        }
                    }
                }
                if (isFilterInputActive) {
                    if (key === keys.ESC) {
                        this._clearFilter();
                    }
                    if (key === keys.UP && !altKey) {
                        this.wrapper.focus();
                        e.preventDefault();
                    }
                    if (browser.msie && browser.version < 10) {
                        if (key === keys.BACKSPACE || key === keys.DELETE) {
                            this._search();
                        }
                    }
                }
                if (altKey && key === keys.UP || key === keys.ESC) {
                    this.wrapper.focus();
                    this.close();
                    e.preventDefault();
                    return;
                }
                if (key === keys.ENTER && this._typingTimeout && this.filterInput && isPopupVisible) {
                    e.preventDefault();
                    return;
                }
                if (key === keys.SPACEBAR && !isFilterInputActive) {
                    this._toggle(!isPopupVisible);
                    e.preventDefault();
                }
                if (altKey && key === keys.DOWN && !isPopupVisible) {
                    this.open();
                    e.preventDefault();
                }
                if (key === keys.DOWN && isPopupVisible) {
                    if (this.filterInput && !isFilterInputActive) {
                        this.filterInput.focus();
                    } else if (this.checkAll && this.checkAll.is(':visible')) {
                        this.checkAll.find('input').focus();
                    } else if (this.tree.is(':visible')) {
                        this.tree.focus();
                    }
                    e.preventDefault();
                }
            },
            _focusPrevTag: function () {
                var focused = this.tagList.find(DOT + FOCUSED);
                if (focused.length) {
                    var activedescendant = this.wrapper.attr('aria-activedescendant');
                    focused.first().removeClass(FOCUSED).removeAttr('id').prev().addClass(FOCUSED).attr('id', activedescendant);
                    this.wrapper.attr('aria-activedescendant', activedescendant);
                } else {
                    this._focusLastTag();
                }
            },
            _focusNextTag: function () {
                var focused = this.tagList.find(DOT + FOCUSED);
                if (focused.length) {
                    var activedescendant = this.wrapper.attr('aria-activedescendant');
                    focused.first().removeClass(FOCUSED).removeAttr('id').next().addClass(FOCUSED).attr('id', activedescendant);
                    this.wrapper.attr('aria-activedescendant', activedescendant);
                } else {
                    this._focusFirstTag();
                }
            },
            _focusFirstTag: function () {
                var activedescendant = this.wrapper.attr('aria-activedescendant');
                this._clearDisabledTag();
                var firstTag = this.tagList.children('li').first().addClass(FOCUSED).attr('id', activedescendant);
                this.wrapper.attr('aria-activedescendant', activedescendant);
                return firstTag;
            },
            _focusLastTag: function () {
                var activedescendant = this.wrapper.attr('aria-activedescendant');
                this._clearDisabledTag();
                var lastTag = this.tagList.children('li').last().addClass(FOCUSED).attr('id', activedescendant);
                this.wrapper.attr('aria-activedescendant', activedescendant);
                return lastTag;
            },
            _clearDisabledTag: function () {
                this.tagList.find(DOT + FOCUSED).removeClass(FOCUSED).removeAttr('id');
            },
            _search: function () {
                var that = this;
                clearTimeout(that._typingTimeout);
                that._typingTimeout = setTimeout(function () {
                    var value = that.filterInput.val();
                    if (that._prev !== value) {
                        that._prev = value;
                        that.search(value);
                    }
                    that._typingTimeout = null;
                }, that.options.delay);
            },
            _clearFilter: function () {
                if (this.filterInput.val().length) {
                    this.filterInput.val('');
                    this._prev = '';
                    this._filtering = true;
                    this.treeview.dataSource.filter({});
                }
            },
            _removeTagClick: function (e) {
                e.stopPropagation();
                var tagItem = this._tags[$(e.currentTarget.parentElement).index()];
                this._removeTag(tagItem);
            },
            _removeTag: function (tagItem) {
                if (!tagItem) {
                    return;
                }
                var uid = tagItem.uid;
                this._uncheckItemByUid(uid);
            }
        });
        function assign(instance, fields, value) {
            var idx = 0, lastIndex = fields.length - 1, field;
            for (; idx < lastIndex; ++idx) {
                field = fields[idx];
                if (!(field in instance)) {
                    instance[field] = {};
                }
                instance = instance[field];
            }
            instance[fields[lastIndex]] = value;
        }
        ui.plugin(DropDownTree);
        var SingleSelection = kendo.Class.extend({
            init: function (view) {
                this._dropdowntree = view;
            },
            _initWrapper: function () {
                this._wrapper();
                this._span();
            },
            _preselect: function (data) {
                var dropdowntree = this._dropdowntree;
                dropdowntree._selectValue(data);
            },
            _wrapper: function () {
                var dropdowntree = this._dropdowntree, element = dropdowntree.element, DOMelement = element[0], wrapper;
                wrapper = element.parent();
                if (!wrapper.is('span.k-widget')) {
                    wrapper = element.wrap('<span />').parent();
                    wrapper[0].style.cssText = DOMelement.style.cssText;
                    wrapper[0].title = DOMelement.title;
                }
                dropdowntree._focused = dropdowntree.wrapper = wrapper.addClass('k-widget k-dropdowntree').addClass(DOMelement.className).css('display', '').attr({
                    accesskey: element.attr('accesskey'),
                    unselectable: 'on',
                    role: 'listbox',
                    'aria-haspopup': true,
                    'aria-expanded': false
                });
                element.hide().removeAttr('accesskey');
            },
            _span: function () {
                var dropdowntree = this._dropdowntree, wrapper = dropdowntree.wrapper, SELECTOR = 'span.k-input', span;
                span = wrapper.find(SELECTOR);
                if (!span[0]) {
                    wrapper.append('<span unselectable="on" class="k-dropdown-wrap k-state-default"><span unselectable="on" class="k-input">&nbsp;</span><span unselectable="on" class="k-select" aria-label="select"><span class="k-icon k-i-arrow-60-down"></span></span></span>').append(dropdowntree.element);
                    span = wrapper.find(SELECTOR);
                }
                dropdowntree.span = span;
                dropdowntree._inputWrapper = $(wrapper[0].firstChild);
                dropdowntree._arrow = wrapper.find('.k-select');
                dropdowntree._arrowIcon = dropdowntree._arrow.find('.k-icon');
            },
            _setValue: function (value) {
                var dropdowntree = this._dropdowntree;
                var currentValue;
                if (value === undefined || value === null) {
                    currentValue = dropdowntree._values.slice()[0];
                    value = typeof currentValue === 'object' ? currentValue : dropdowntree._accessor() || currentValue;
                    return value === undefined || value === null ? '' : value;
                }
                dropdowntree._valueMethodCalled = true;
                if (value.length === 0) {
                    dropdowntree._clearTextAndValue();
                    dropdowntree._valueMethodCalled = false;
                    return;
                }
                dropdowntree._selectItemByValue(value);
                dropdowntree._toggleCloseVisibility();
            },
            _clearValue: function () {
                var dropdowntree = this._dropdowntree;
                var selectedNode = dropdowntree.treeview.select();
                if (dropdowntree.treeview.dataItem(selectedNode)) {
                    dropdowntree.treeview.dataItem(selectedNode).set('selected', false);
                    if (!dropdowntree._valueMethodCalled) {
                        dropdowntree.trigger(CHANGE);
                    }
                }
            },
            _checkLoadedItem: function (tempItem, value) {
                var dropdowntree = this._dropdowntree;
                if (!dropdowntree._isNullorUndefined(value) && value !== '' && dropdowntree._valueComparer(tempItem, value) || !value && tempItem.selected) {
                    dropdowntree.treeview.select(dropdowntree.treeview.findByUid(tempItem.uid));
                }
            }
        });
        var MultipleSelection = kendo.Class.extend({
            init: function (view) {
                this._dropdowntree = view;
            },
            _initWrapper: function () {
                var dropdowntree = this._dropdowntree;
                this._tagTemplate();
                dropdowntree.element.attr('multiple', 'multiple').hide();
                this._wrapper();
                dropdowntree._tags = new ObservableArray([]);
                dropdowntree._multipleTags = new ObservableArray([]);
                this._tagList();
                dropdowntree.span = $('<span unselectable="on" class="k-input">&nbsp;</span>').insertAfter(dropdowntree.tagList);
                dropdowntree._inputWrapper = $(dropdowntree.wrapper[0].firstChild);
            },
            _preselect: function (data, value) {
                var dropdowntree = this._dropdowntree;
                var valueToSelect = value || dropdowntree.options.value;
                if (!$.isArray(data) && !(data instanceof kendo.data.ObservableArray)) {
                    data = [data];
                }
                if ($.isPlainObject(data[0]) || data[0] instanceof kendo.data.ObservableObject || !dropdowntree.options.dataValueField) {
                    dropdowntree.dataSource.data(data);
                    dropdowntree.value(valueToSelect);
                }
            },
            _tagTemplate: function () {
                var dropdowntree = this._dropdowntree;
                var options = dropdowntree.options;
                var tagTemplate = options.valueTemplate;
                var isMultiple = options.tagMode === 'multiple';
                var singleTag = options.messages.singleTag;
                tagTemplate = tagTemplate ? kendo.template(tagTemplate) : dropdowntree.valueTemplate;
                dropdowntree.valueTemplate = function (data) {
                    if (isMultiple) {
                        return '<li class="k-button ' + (data.enabled === false ? 'k-state-disabled' : '') + '" unselectable="on" role="option" ' + (data.enabled === false ? 'aria-disabled="true"' : '') + '>' + '<span unselectable="on">' + tagTemplate(data) + '</span>' + '<span title="' + dropdowntree.options.messages.deleteTag + '" aria-label="' + dropdowntree.options.messages.deleteTag + '" class="k-select">' + '<span class="k-icon k-i-close"></span>' + '</span>' + '</li>';
                    }
                    return '<li class="k-button" unselectable="on" role="option">' + '<span unselectable="on" data-bind="text: tags.length"></span>' + '<span unselectable="on">&nbsp;' + singleTag + '</span>' + '</li>';
                };
            },
            _wrapper: function () {
                var dropdowntree = this._dropdowntree, element = dropdowntree.element, wrapper = element.parent('span.k-dropdowntree');
                if (!wrapper[0]) {
                    wrapper = element.wrap('<div class="k-widget k-dropdowntree" unselectable="on" />').parent();
                    wrapper[0].style.cssText = element[0].style.cssText;
                    wrapper[0].title = element[0].title;
                    $('<div class="k-multiselect-wrap k-floatwrap" unselectable="on" />').insertBefore(element);
                }
                dropdowntree.wrapper = wrapper.addClass(element[0].className).css('display', '').attr({
                    role: 'listbox',
                    'aria-activedescendant': kendo.guid(),
                    'aria-haspopup': true,
                    'aria-expanded': false
                });
                dropdowntree._innerWrapper = $(wrapper[0].firstChild);
            },
            _tagList: function () {
                var dropdowntree = this._dropdowntree, tagList = dropdowntree._innerWrapper.children('ul');
                if (!tagList[0]) {
                    var isMultiple = dropdowntree.options.tagMode === 'multiple';
                    var tagCollection = isMultiple ? 'tags' : 'multipleTag';
                    tagList = $('<ul role="listbox" unselectable="on" data-template="tagTemplate" data-bind="source: ' + tagCollection + '" class="k-reset"/>').appendTo(dropdowntree._innerWrapper);
                }
                dropdowntree.tagList = tagList;
                dropdowntree.tagList.attr('id', kendo.guid() + '_tagList');
                dropdowntree.wrapper.attr('aria-owns', dropdowntree.tagList.attr('id'));
                var viewModel = kendo.observable({
                    multipleTag: dropdowntree._multipleTags,
                    tags: dropdowntree._tags,
                    tagTemplate: dropdowntree.valueTemplate
                });
                kendo.bind(dropdowntree.tagList, viewModel);
                dropdowntree.tagList.attr('data-stop', true);
            },
            _setValue: function (value) {
                var dropdowntree = this._dropdowntree;
                var oldValues = dropdowntree._values;
                if (value === undefined || value === null) {
                    return dropdowntree._values.slice();
                }
                dropdowntree.setValue(value);
                dropdowntree._valueMethodCalled = true;
                if (value.length) {
                    this._removeValues(oldValues, value);
                    dropdowntree._checkItemByValue(value);
                } else {
                    dropdowntree._clearTextAndValue();
                }
                dropdowntree._valueMethodCalled = false;
                dropdowntree._toggleCloseVisibility();
            },
            _removeValues: function (oldValues, value) {
                var dropdowntree = this._dropdowntree;
                var removedValues = this._getNewValues(oldValues, value);
                for (var idx = 0; idx < removedValues.length; idx++) {
                    for (var j = 0; j < dropdowntree._tags.length; j++) {
                        if (dropdowntree._valueComparer(dropdowntree._tags[j], removedValues[idx])) {
                            dropdowntree._uncheckItemByUid(dropdowntree._tags[j].uid);
                        }
                    }
                }
            },
            _getNewValues: function (oldValues, value) {
                var removedValues = [];
                for (var idx = 0; idx < oldValues.length; idx++) {
                    if (value.indexOf(oldValues[idx]) === -1) {
                        removedValues.push(oldValues[idx]);
                    }
                }
                return removedValues;
            },
            _clearValue: function () {
                var dropdowntree = this._dropdowntree;
                var tagsArray = dropdowntree._tags.slice();
                for (var idx = 0; idx < tagsArray.length; idx++) {
                    var uid = tagsArray[idx].uid;
                    dropdowntree._preventChangeTrigger = true;
                    dropdowntree._uncheckItemByUid(uid);
                }
                if (tagsArray.length) {
                    dropdowntree._preventChangeTrigger = false;
                    if (!dropdowntree._valueMethodCalled) {
                        dropdowntree.trigger(CHANGE);
                    }
                }
            },
            _checkLoadedItem: function (tempItem, value) {
                var dropdowntree = this._dropdowntree;
                if (dropdowntree._noInitialValue && tempItem.checked) {
                    dropdowntree._checkValue(tempItem);
                    return;
                }
                if (value.length && (value.indexOf(dropdowntree._currentValue(tempItem)) !== -1 || value.indexOf(tempItem)) !== -1 && !this._findTag(dropdowntree._currentValue(tempItem))) {
                    if (tempItem.checked) {
                        dropdowntree._checkValue(tempItem);
                    } else {
                        tempItem.set('checked', true);
                    }
                }
            },
            _findTag: function (tempItemValue) {
                var dropdowntree = this._dropdowntree;
                return dropdowntree._tags.find(function (item) {
                    return dropdowntree._valueComparer(item, tempItemValue);
                });
            }
        });
        kendo.ui.DropDownTree.SingleSelection = SingleSelection;
        kendo.ui.DropDownTree.MultipleSelection = MultipleSelection;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.combobox', [
        'kendo.list',
        'kendo.mobile.scroller',
        'kendo.virtuallist'
    ], f);
}(function () {
    var __meta__ = {
        id: 'combobox',
        name: 'ComboBox',
        category: 'web',
        description: 'The ComboBox widget allows the selection from pre-defined values or entering a new value.',
        depends: ['list'],
        features: [
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            },
            {
                id: 'virtualization',
                name: 'VirtualList',
                description: 'Support for virtualization',
                depends: ['virtuallist']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, List = ui.List, Select = ui.Select, caret = kendo.caret, support = kendo.support, placeholderSupported = support.placeholder, activeElement = kendo._activeElement, keys = kendo.keys, ns = '.kendoComboBox', nsFocusEvent = ns + 'FocusEvent', CLICK = 'click' + ns, MOUSEDOWN = 'mousedown' + ns, DISABLED = 'disabled', READONLY = 'readonly', CHANGE = 'change', LOADING = 'k-i-loading', DEFAULT = 'k-state-default', FOCUSED = 'k-state-focused', STATEDISABLED = 'k-state-disabled', ARIA_DISABLED = 'aria-disabled', AUTOCOMPLETEVALUE = support.browser.chrome ? 'disabled' : 'off', STATE_FILTER = 'filter', STATE_ACCEPT = 'accept', STATE_REBIND = 'rebind', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, proxy = $.proxy, newLineRegEx = /(\r\n|\n|\r)/gm;
        var ComboBox = Select.extend({
            init: function (element, options) {
                var that = this, text, disabled;
                that.ns = ns;
                options = $.isArray(options) ? { dataSource: options } : options;
                Select.fn.init.call(that, element, options);
                options = that.options;
                element = that.element.on('focus' + ns, proxy(that._focusHandler, that));
                options.placeholder = options.placeholder || element.attr('placeholder');
                that._reset();
                that._wrapper();
                that._input();
                that._clearButton();
                that._tabindex(that.input);
                that._popup();
                that._dataSource();
                that._ignoreCase();
                that._enable();
                that._attachFocusEvents();
                that._oldIndex = that.selectedIndex = -1;
                that._aria();
                that._initialIndex = options.index;
                that.requireValueMapper(that.options);
                that._initList();
                that._cascade();
                if (options.autoBind) {
                    that._filterSource();
                } else {
                    text = options.text;
                    if (!text && that._isSelect) {
                        text = element.children(':selected').text();
                    }
                    if (text) {
                        that._setText(text);
                    }
                }
                if (!text) {
                    that._placeholder();
                }
                disabled = $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                }
                kendo.notify(that);
                that._toggleCloseVisibility();
            },
            options: {
                name: 'ComboBox',
                enabled: true,
                index: -1,
                text: null,
                value: null,
                autoBind: true,
                delay: 200,
                dataTextField: '',
                dataValueField: '',
                minLength: 1,
                enforceMinLength: false,
                height: 200,
                highlightFirst: true,
                filter: 'none',
                placeholder: '',
                suggest: false,
                cascadeFrom: '',
                cascadeFromField: '',
                cascadeFromParentField: '',
                ignoreCase: true,
                animation: {},
                virtual: false,
                template: null,
                groupTemplate: '#:data#',
                fixedGroupTemplate: '#:data#',
                clearButton: true,
                syncValueAndText: true,
                autoWidth: false,
                popup: null
            },
            events: [
                'open',
                'close',
                CHANGE,
                'select',
                'filtering',
                'dataBinding',
                'dataBound',
                'cascade',
                'set'
            ],
            setOptions: function (options) {
                var listOptions = this._listOptions(options);
                Select.fn.setOptions.call(this, options);
                this.listView.setOptions(listOptions);
                this._accessors();
                this._aria();
                this._clearButton();
            },
            destroy: function () {
                var that = this;
                that.input.off(ns);
                that.input.off(nsFocusEvent);
                that.element.off(ns);
                that._inputWrapper.off(ns);
                clearTimeout(that._pasteTimeout);
                that._arrow.off(CLICK + ' ' + MOUSEDOWN);
                that._clear.off(CLICK + ' ' + MOUSEDOWN);
                Select.fn.destroy.call(that);
            },
            _change: function () {
                var that = this;
                var text = that.text();
                var hasText = text && text !== that._oldText && text !== that.options.placeholder;
                var index = that.selectedIndex;
                var isCustom = index === -1;
                if (!that.options.syncValueAndText && !that.value() && isCustom && hasText) {
                    that._old = '';
                    that._oldIndex = index;
                    that._oldText = text;
                    if (!that._typing) {
                        that.element.trigger(CHANGE);
                    }
                    that.trigger(CHANGE);
                    that._typing = false;
                    return;
                }
                Select.fn._change.call(that);
                that._toggleCloseVisibility();
            },
            _attachFocusEvents: function () {
                var that = this;
                that.input.on('focus' + nsFocusEvent, proxy(that._inputFocus, that)).on('focusout' + nsFocusEvent, proxy(that._inputFocusout, that));
            },
            _focusHandler: function () {
                this.input.focus();
            },
            _arrowClick: function () {
                this._toggle();
            },
            _inputFocus: function () {
                this._inputWrapper.addClass(FOCUSED);
                this._placeholder(false);
            },
            _inputFocusout: function () {
                var that = this;
                var value = that.value();
                that._userTriggered = true;
                that._inputWrapper.removeClass(FOCUSED);
                clearTimeout(that._typingTimeout);
                that._typingTimeout = null;
                that.text(that.text());
                var item = that._focus();
                var dataItem = this.listView.dataItemByIndex(this.listView.getElementIndex(item));
                if (value !== that.value() && that.trigger('select', {
                        dataItem: dataItem,
                        item: item
                    })) {
                    that.value(value);
                    return;
                }
                that._placeholder();
                that._blur();
                that.element.blur();
            },
            _inputPaste: function () {
                var that = this;
                clearTimeout(that._pasteTimeout);
                that._pasteTimeout = null;
                that._pasteTimeout = setTimeout(function () {
                    that.search();
                });
            },
            _editable: function (options) {
                var that = this, disable = options.disable, readonly = options.readonly, wrapper = that._inputWrapper.off(ns), input = that.element.add(that.input.off(ns)), arrow = that._arrow.off(CLICK + ' ' + MOUSEDOWN), clear = that._clear;
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    input.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false);
                    arrow.on(CLICK, proxy(that._arrowClick, that)).on(MOUSEDOWN, function (e) {
                        e.preventDefault();
                    });
                    clear.on(CLICK + ' touchend' + ns, proxy(that._clearValue, that)).on(MOUSEDOWN, function (e) {
                        e.preventDefault();
                    });
                    that.input.on('keydown' + ns, proxy(that._keydown, that)).on('input' + ns, proxy(that._search, that)).on('paste' + ns, proxy(that._inputPaste, that));
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    input.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
                that._toggleCloseVisibility();
            },
            open: function () {
                var that = this;
                var state = that._state;
                var isFiltered = that.dataSource.filter() ? that.dataSource.filter().filters.length > 0 : false;
                var reinitialized = !that.ul.find(that.listView.focus()).length;
                if (that.popup.visible()) {
                    return;
                }
                if (!that.listView.bound() && state !== STATE_FILTER || state === STATE_ACCEPT) {
                    that._open = true;
                    that._state = STATE_REBIND;
                    if (that.options.minLength !== 1 && !isFiltered || isFiltered && that.value() && that.selectedIndex === -1) {
                        that.refresh();
                        that._openPopup();
                        if (!this.options.virtual) {
                            that.listView.bound(false);
                        }
                    } else {
                        that._filterSource();
                    }
                } else if (that._allowOpening()) {
                    that.popup._hovered = true;
                    that._openPopup();
                    if (that.options.virtual) {
                        that._focusItem();
                    } else if (reinitialized && that.options.highlightFirst) {
                        that.listView.focus(0);
                    }
                }
            },
            _scrollToFocusedItem: function () {
                var listView = this.listView;
                listView.scrollToIndex(listView.getElementIndex(listView.focus()));
            },
            _openPopup: function () {
                this.popup.one('activate', proxy(this._scrollToFocusedItem, this));
                this.popup.open();
            },
            _updateSelectionState: function () {
                var that = this;
                var text = that.options.text;
                var value = that.options.value;
                if (that.listView.isFiltered()) {
                    return;
                }
                if (that.selectedIndex === -1) {
                    if (text === undefined || text === null) {
                        text = value;
                    }
                    that._accessor(value);
                    that.input.val(text || that.input.val());
                    that._placeholder();
                } else if (that._oldIndex === -1) {
                    that._oldIndex = that.selectedIndex;
                }
            },
            _buildOptions: function (data) {
                var that = this;
                if (!that._isSelect) {
                    return;
                }
                var custom = that._customOption;
                if (that._state === STATE_REBIND) {
                    that._state = '';
                }
                that._customOption = undefined;
                that._options(data, '', that.value());
                if (custom && custom[0].selected && !that.listView._emptySearch) {
                    that._custom(custom.val());
                }
            },
            _updateSelection: function () {
                var that = this;
                var listView = that.listView;
                var initialIndex = that._initialIndex;
                var hasInitialIndex = initialIndex !== null && initialIndex > -1;
                var filtered = that._state === STATE_FILTER;
                if (filtered) {
                    $(listView.focus()).removeClass('k-state-selected');
                    return;
                }
                if (that._fetch) {
                    return;
                }
                if (!listView.value().length) {
                    if (hasInitialIndex) {
                        that.select(initialIndex);
                    } else if (that._accessor()) {
                        listView.value(that._accessor());
                    }
                }
                that._initialIndex = null;
                var dataItem = listView.selectedDataItems()[0];
                if (!dataItem) {
                    return;
                }
                if (that._value(dataItem) !== that.value()) {
                    that._custom(that._value(dataItem));
                } else if (that._value(dataItem) !== that.element[0].value) {
                    that._accessor(that._value(dataItem));
                }
                if (that.text() && that.text() !== that._text(dataItem)) {
                    that._selectValue(dataItem);
                }
            },
            _updateItemFocus: function () {
                var listView = this.listView;
                if (!this.options.highlightFirst) {
                    listView.focus(-1);
                } else if (!listView.focus() && !listView.focusIndex()) {
                    listView.focus(0);
                }
            },
            _listBound: function () {
                var that = this;
                var isActive = that.input[0] === activeElement();
                var data = that.dataSource.flatView();
                var skip = that.listView.skip();
                var length = data.length;
                var groupsLength = that.dataSource._group ? that.dataSource._group.length : 0;
                var isFirstPage = skip === undefined || skip === 0;
                that._presetValue = false;
                that._renderFooter();
                that._renderNoData();
                that._toggleNoData(!length);
                that._toggleHeader(!!groupsLength && !!length);
                that._resizePopup();
                that.popup.position();
                that._buildOptions(data);
                that._makeUnselectable();
                that._updateSelection();
                if (data.length && isFirstPage) {
                    that._updateItemFocus();
                    if (that.options.suggest && isActive && that.input.val()) {
                        that.suggest(data[0]);
                    }
                }
                if (that._open) {
                    that._open = false;
                    if (that._typingTimeout && !isActive) {
                        that.popup.close();
                    } else {
                        that.toggle(that._allowOpening());
                    }
                    that._typingTimeout = null;
                }
                that._hideBusy();
                that.trigger('dataBound');
            },
            _listChange: function () {
                this._selectValue(this.listView.selectedDataItems()[0]);
                if (this._presetValue) {
                    this._oldIndex = this.selectedIndex;
                }
            },
            _get: function (candidate) {
                var data, found, idx;
                if (typeof candidate === 'function') {
                    data = this.dataSource.flatView();
                    for (idx = 0; idx < data.length; idx++) {
                        if (candidate(data[idx])) {
                            candidate = idx;
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        candidate = -1;
                    }
                }
                return candidate;
            },
            _select: function (candidate, keepState) {
                var that = this;
                candidate = that._get(candidate);
                if (candidate === -1) {
                    that.input[0].value = '';
                    that._accessor('');
                }
                return that.listView.select(candidate).done(function () {
                    if (!keepState && that._state === STATE_FILTER) {
                        that._state = STATE_ACCEPT;
                    }
                    that._toggleCloseVisibility();
                });
            },
            _selectValue: function (dataItem) {
                var idx = this.listView.select();
                var value = '';
                var text = '';
                idx = idx[idx.length - 1];
                if (idx === undefined) {
                    idx = -1;
                }
                this.selectedIndex = idx;
                if (this.listView.isFiltered() && idx !== -1) {
                    this._valueBeforeCascade = this._old;
                }
                if (idx === -1 && !dataItem) {
                    if (this.options.syncValueAndText) {
                        if (this.options.dataTextField === this.options.dataValueField) {
                            text = this._accessor();
                        } else {
                            text = this.input[0].value;
                        }
                        value = text;
                    } else {
                        text = this.text();
                    }
                    this.listView.focus(-1);
                } else {
                    if (dataItem || dataItem === 0) {
                        value = this._dataValue(dataItem);
                        text = this._text(dataItem);
                    }
                    if (value === null) {
                        value = '';
                    }
                }
                this._setDomInputValue(text);
                this._accessor(value !== undefined ? value : text, idx);
                this._placeholder();
                this._triggerCascade();
            },
            _setDomInputValue: function (text) {
                var that = this;
                var currentCaret = caret(this.input);
                var caretStart;
                if (currentCaret && currentCaret.length) {
                    caretStart = currentCaret[0];
                }
                this._prev = this.input[0].value = text;
                if (caretStart && this.selectedIndex === -1) {
                    var mobile = support.mobileOS;
                    if (mobile.wp || mobile.android) {
                        setTimeout(function () {
                            that.input[0].setSelectionRange(caretStart, caretStart);
                        }, 0);
                    } else {
                        this.input[0].setSelectionRange(caretStart, caretStart);
                    }
                }
            },
            refresh: function () {
                this.listView.refresh();
            },
            _toggleCloseVisibility: function () {
                var preventShow = this.element.is(':disabled') || this.element.is('[readonly]');
                if (this.text() && !preventShow) {
                    this._showClear();
                } else {
                    this._hideClear();
                }
            },
            suggest: function (word) {
                var that = this;
                var element = that.input[0];
                var value = that.text();
                var caretIdx = caret(element)[0];
                var key = that._last;
                var idx;
                var accentFoldingFiltering = that.dataSource.options.accentFoldingFiltering;
                if (key == keys.BACKSPACE || key == keys.DELETE) {
                    that._last = undefined;
                    return;
                }
                word = word || '';
                if (typeof word !== 'string') {
                    if (word[0]) {
                        word = that.dataSource.view()[List.inArray(word[0], that.ul[0])];
                    }
                    word = word ? that._text(word) : '';
                }
                if (caretIdx <= 0) {
                    caretIdx = (accentFoldingFiltering ? value.toLocaleLowerCase(accentFoldingFiltering) : value.toLowerCase()).indexOf(accentFoldingFiltering ? word.toLocaleLowerCase(accentFoldingFiltering) : word.toLowerCase()) + 1;
                }
                if (word) {
                    word = word.toString();
                    idx = (accentFoldingFiltering ? word.toLocaleLowerCase(accentFoldingFiltering) : word.toLowerCase()).indexOf(accentFoldingFiltering ? value.toLocaleLowerCase(accentFoldingFiltering) : value.toLowerCase());
                    if (idx > -1) {
                        value += word.substring(idx + value.length);
                    }
                } else {
                    value = value.substring(0, caretIdx);
                }
                if (value.length !== caretIdx || !word) {
                    element.value = value;
                    if (element === activeElement()) {
                        caret(element, caretIdx, value.length);
                    }
                }
            },
            text: function (text) {
                text = text === null ? '' : text;
                var that = this;
                var input = that.input[0];
                var ignoreCase = that.options.ignoreCase;
                var loweredText = text;
                var dataItem;
                var value;
                if (text === undefined) {
                    return input.value;
                }
                if (that.options.autoBind === false && !that.listView.bound()) {
                    that._setText(text);
                    return;
                }
                dataItem = that.dataItem();
                if (dataItem && that._text(dataItem).replace && that._text(dataItem).replace(newLineRegEx, '') === text) {
                    value = that._value(dataItem);
                    if (value === List.unifyType(that._old, typeof value)) {
                        that._triggerCascade();
                        return;
                    }
                }
                if (ignoreCase) {
                    loweredText = loweredText.toLowerCase();
                }
                if (that.dataItem() && that._text(that.dataItem()) === text) {
                    return;
                }
                that._select(function (data) {
                    data = that._text(data);
                    if (ignoreCase) {
                        data = (data + '').toLowerCase();
                    }
                    return data === loweredText;
                }).done(function () {
                    if (that.selectedIndex < 0) {
                        input.value = text;
                        if (that.options.syncValueAndText) {
                            that._accessor(text);
                        }
                        that._cascadeTriggered = true;
                        that._triggerCascade();
                    }
                    that._prev = input.value;
                });
                that._toggleCloseVisibility();
            },
            toggle: function (toggle) {
                this._toggle(toggle, true);
            },
            value: function (value) {
                var that = this;
                var options = that.options;
                var listView = that.listView;
                if (value === undefined) {
                    value = that._accessor() || that.listView.value()[0];
                    return value === undefined || value === null ? '' : value;
                }
                that.requireValueMapper(that.options, value);
                that.trigger('set', { value: value });
                if (value === options.value && that.input.val() === options.text) {
                    return;
                }
                that._accessor(value);
                if (that._isFilterEnabled() && listView.bound() && listView.isFiltered()) {
                    that._clearFilter();
                } else {
                    that._fetchData();
                }
                listView.value(value).done(function () {
                    if (that.selectedIndex === -1 && (!listView._selectedDataItems || !listView._selectedDataItems.length)) {
                        that._accessor(value);
                        that.input.val(value);
                        that._placeholder(true);
                    }
                    that._old = that._valueBeforeCascade = that._accessor();
                    that._oldIndex = that.selectedIndex;
                    that._prev = that.input.val();
                    if (that._state === STATE_FILTER) {
                        that._state = STATE_ACCEPT;
                    }
                    that._toggleCloseVisibility();
                });
            },
            _hideBusy: function () {
                var that = this;
                clearTimeout(that._busy);
                that._arrowIcon.removeClass(LOADING);
                that._focused.attr('aria-busy', false);
                that._busy = null;
                that._toggleCloseVisibility();
            },
            _click: function (e) {
                var that = this;
                var item = e.item;
                var dataItem = that.listView.dataItemByIndex(that.listView.getElementIndex(item));
                var shouldTrigger = true;
                e.preventDefault();
                if (dataItem) {
                    shouldTrigger = that._value(dataItem) !== List.unifyType(that.value(), typeof that._value(dataItem));
                    if (!shouldTrigger) {
                        that.input.val(that._text(dataItem));
                    }
                }
                if (shouldTrigger && that.trigger('select', {
                        dataItem: dataItem,
                        item: item
                    })) {
                    that.close();
                    return;
                }
                that._userTriggered = true;
                that._select(item).done(function () {
                    that._blur();
                });
            },
            _syncValueAndText: function () {
                return this.options.syncValueAndText;
            },
            _inputValue: function () {
                return this.text();
            },
            _searchByWord: function (word) {
                var that = this;
                var options = that.options;
                var dataSource = that.dataSource;
                var ignoreCase = options.ignoreCase;
                var predicate = function (dataItem) {
                    var text = that._text(dataItem);
                    if (text !== undefined) {
                        text = text + '';
                        if (text !== '' && word === '') {
                            return false;
                        }
                        if (ignoreCase) {
                            text = text.toLowerCase();
                        }
                        return text.indexOf(word) === 0;
                    }
                };
                if (ignoreCase) {
                    word = word.toLowerCase();
                }
                if (!that.ul[0].firstChild) {
                    dataSource.one(CHANGE, function () {
                        if (dataSource.view()[0]) {
                            that.search(word);
                        }
                    }).fetch();
                    return;
                }
                this.listView.focus(this._get(predicate));
                var current = this.listView.focus();
                if (current) {
                    if (options.suggest) {
                        that.suggest(current);
                    }
                    this.open();
                }
                if (this.options.highlightFirst && !word) {
                    this.listView.focusFirst();
                }
            },
            _input: function () {
                var that = this, element = that.element.removeClass('k-input')[0], accessKey = element.accessKey, wrapper = that.wrapper, SELECTOR = 'input.k-input', name = element.name || '', input, maxLength;
                if (name) {
                    name = 'name="' + name + '_input" ';
                }
                input = wrapper.find(SELECTOR);
                if (!input[0]) {
                    wrapper.append('<span tabindex="-1" unselectable="on" class="k-dropdown-wrap k-state-default"><input ' + name + 'class="k-input" type="text" autocomplete="' + AUTOCOMPLETEVALUE + '"/><span unselectable="on" class="k-select" aria-label="select"><span class="k-icon k-i-arrow-60-down"></span></span></span>').append(that.element);
                    input = wrapper.find(SELECTOR);
                }
                input[0].style.cssText = element.style.cssText;
                input[0].title = element.title;
                maxLength = parseInt(this.element.prop('maxlength') || this.element.attr('maxlength'), 10);
                if (maxLength > -1) {
                    input[0].maxLength = maxLength;
                }
                input.addClass(element.className).css({
                    width: '',
                    height: element.style.height
                }).attr({
                    'role': 'combobox',
                    'aria-expanded': false
                }).show();
                if (placeholderSupported) {
                    input.attr('placeholder', that.options.placeholder);
                }
                if (accessKey) {
                    element.accessKey = '';
                    input[0].accessKey = accessKey;
                }
                that._focused = that.input = input;
                that._inputWrapper = $(wrapper[0].firstChild);
                that._arrow = wrapper.find('.k-select').attr({
                    'role': 'button',
                    'tabIndex': -1
                });
                that._arrowIcon = that._arrow.find('.k-icon');
                if (element.id) {
                    that._arrow.attr('aria-controls', that.ul[0].id);
                }
            },
            _clearButton: function () {
                List.fn._clearButton.call(this);
                if (this.options.clearButton) {
                    this._clear.insertAfter(this.input);
                    this.wrapper.addClass('k-combobox-clearable');
                }
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode;
                that._last = key;
                clearTimeout(that._typingTimeout);
                that._typingTimeout = null;
                if (key === keys.HOME) {
                    that._firstItem();
                } else if (key === keys.END) {
                    that._lastItem();
                } else if (key === keys.ENTER || key === keys.TAB && that.popup.visible()) {
                    var current = that.listView.focus();
                    var dataItem = that.dataItem();
                    var shouldTrigger = true;
                    if (!that.popup.visible() && (!dataItem || that.text() !== that._text(dataItem))) {
                        current = null;
                    }
                    if (current) {
                        if (that.popup.visible()) {
                            e.preventDefault();
                        }
                        dataItem = that.listView.dataItemByIndex(that.listView.getElementIndex(current));
                        if (dataItem) {
                            shouldTrigger = that._value(dataItem) !== List.unifyType(that.value(), typeof that._value(dataItem));
                        }
                        if (shouldTrigger && that.trigger('select', {
                                dataItem: dataItem,
                                item: current
                            })) {
                            return;
                        }
                        that._userTriggered = true;
                        that._select(current).done(function () {
                            that._blur();
                            that._valueBeforeCascade = that._old = that.value();
                        });
                    } else {
                        if (that._syncValueAndText() || that._isSelect) {
                            that._accessor(that.input.val());
                        }
                        that.listView.value(that.input.val());
                        that._blur();
                    }
                } else if (key != keys.TAB && !that._move(e)) {
                    that._search();
                } else if (key === keys.ESC && !that.popup.visible() && that.text()) {
                    that._clearValue();
                }
            },
            _placeholder: function (show) {
                if (placeholderSupported) {
                    return;
                }
                var that = this, input = that.input, placeholder = that.options.placeholder, value;
                if (placeholder) {
                    value = that.value();
                    if (show === undefined) {
                        show = !value;
                    }
                    input.toggleClass('k-readonly', show);
                    if (!show) {
                        if (!value) {
                            placeholder = '';
                        } else {
                            return;
                        }
                    }
                    input.val(placeholder);
                    if (!placeholder && input[0] === activeElement()) {
                        caret(input[0], 0, 0);
                    }
                }
            },
            _search: function () {
                var that = this;
                clearTimeout(that._typingTimeout);
                that._typingTimeout = setTimeout(function () {
                    var value = that.text();
                    if (that._prev !== value) {
                        that._prev = value;
                        if (that.options.filter === 'none' && that.options.virtual) {
                            that.listView.select(-1);
                        }
                        that.search(value);
                        that._toggleCloseVisibility();
                    }
                    that._typingTimeout = null;
                }, that.options.delay);
            },
            _setText: function (text) {
                this.input.val(text);
                this._prev = text;
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper = element.parent();
                if (!wrapper.is('span.k-widget')) {
                    wrapper = element.hide().wrap('<span />').parent();
                    wrapper[0].style.cssText = element[0].style.cssText;
                }
                that.wrapper = wrapper.addClass('k-widget k-combobox').addClass(element[0].className).css('display', '');
            },
            _clearSelection: function (parent, isFiltered) {
                var that = this;
                var hasValue = parent.value();
                var custom = hasValue && parent.selectedIndex === -1;
                if (this.selectedIndex == -1 && this.value()) {
                    return;
                }
                if (isFiltered || !hasValue || custom) {
                    that.options.value = '';
                    that.value('');
                    that._selectedValue = null;
                }
            },
            _preselect: function (value, text) {
                this.input.val(text);
                this._accessor(value);
                this._old = this._accessor();
                this._oldIndex = this.selectedIndex;
                this.listView.setValue(value);
                this._placeholder();
                this._initialIndex = null;
                this._presetValue = true;
                this._toggleCloseVisibility();
            }
        });
        ui.plugin(ComboBox);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.multiselect', [
        'kendo.list',
        'kendo.mobile.scroller',
        'kendo.virtuallist'
    ], f);
}(function () {
    var __meta__ = {
        id: 'multiselect',
        name: 'MultiSelect',
        category: 'web',
        description: 'The MultiSelect widget allows the selection from pre-defined values.',
        depends: ['list'],
        features: [
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            },
            {
                id: 'virtualization',
                name: 'VirtualList',
                description: 'Support for virtualization',
                depends: ['virtuallist']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, List = ui.List, keys = $.extend({ A: 65 }, kendo.keys), activeElement = kendo._activeElement, ObservableArray = kendo.data.ObservableArray, proxy = $.proxy, ID = 'id', LI = 'li', ACCEPT = 'accept', FILTER = 'filter', REBIND = 'rebind', OPEN = 'open', CLOSE = 'close', CHANGE = 'change', PROGRESS = 'progress', SELECT = 'select', DESELECT = 'deselect', ARIA_DISABLED = 'aria-disabled', FOCUSEDCLASS = 'k-state-focused', SELECTEDCLASS = 'k-state-selected', HIDDENCLASS = 'k-hidden', HOVERCLASS = 'k-state-hover', STATEDISABLED = 'k-state-disabled', DISABLED = 'disabled', READONLY = 'readonly', AUTOCOMPLETEVALUE = kendo.support.browser.chrome ? 'disabled' : 'off', ns = '.kendoMultiSelect', CLICK = 'click' + ns, KEYDOWN = 'keydown' + ns, MOUSEENTER = 'mouseenter' + ns, MOUSELEAVE = 'mouseleave' + ns, HOVEREVENTS = MOUSEENTER + ' ' + MOUSELEAVE, quotRegExp = /"/g, isArray = $.isArray, styles = [
                'font-family',
                'font-size',
                'font-stretch',
                'font-style',
                'font-weight',
                'letter-spacing',
                'text-transform',
                'line-height'
            ];
        var MultiSelect = List.extend({
            init: function (element, options) {
                var that = this, id, disabled;
                that.ns = ns;
                List.fn.init.call(that, element, options);
                that._optionsMap = {};
                that._customOptions = {};
                that._wrapper();
                that._tagList();
                that._input();
                that._textContainer();
                that._loader();
                that._clearButton();
                that._tabindex(that.input);
                element = that.element.attr('multiple', 'multiple').hide();
                options = that.options;
                if (!options.placeholder) {
                    options.placeholder = element.data('placeholder');
                }
                id = element.attr(ID);
                if (id) {
                    that._tagID = id + '_tag_active';
                    id = id + '_taglist';
                    that.tagList.attr(ID, id);
                    that.input.attr('aria-describedby', id);
                }
                that._initialOpen = true;
                that._ariaLabel();
                that._ariaSetLive();
                that._dataSource();
                that._ignoreCase();
                that._popup();
                that._tagTemplate();
                that.requireValueMapper(that.options);
                that._initList();
                that._reset();
                that._enable();
                that._placeholder();
                if (options.autoBind) {
                    that.dataSource.fetch();
                } else if (options.value) {
                    that._preselect(options.value);
                }
                disabled = $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                }
                that._ariaSetSize(that.value().length);
                kendo.notify(that);
                that._toggleCloseVisibility();
            },
            options: {
                name: 'MultiSelect',
                tagMode: 'multiple',
                enabled: true,
                autoBind: true,
                autoClose: true,
                highlightFirst: true,
                dataTextField: '',
                dataValueField: '',
                filter: 'startswith',
                ignoreCase: true,
                minLength: 1,
                enforceMinLength: false,
                delay: 100,
                value: null,
                maxSelectedItems: null,
                placeholder: '',
                height: 200,
                animation: {},
                virtual: false,
                itemTemplate: '',
                tagTemplate: '',
                groupTemplate: '#:data#',
                fixedGroupTemplate: '#:data#',
                clearButton: true,
                autoWidth: false,
                popup: null
            },
            events: [
                OPEN,
                CLOSE,
                CHANGE,
                SELECT,
                DESELECT,
                'filtering',
                'dataBinding',
                'dataBound'
            ],
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._state = '';
                this._dataSource();
                this.persistTagList = false;
                this.listView.setDataSource(this.dataSource);
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
            },
            setOptions: function (options) {
                var listOptions = this._listOptions(options);
                List.fn.setOptions.call(this, options);
                this.listView.setOptions(listOptions);
                this._accessors();
                this._aria(this.tagList.attr(ID));
                this._tagTemplate();
                this._placeholder();
                this._clearButton();
            },
            currentTag: function (candidate) {
                var that = this;
                if (candidate !== undefined) {
                    if (that._currentTag) {
                        that._currentTag.removeClass(FOCUSEDCLASS).removeAttr(ID);
                        that._currentTag.find('.k-select').attr('aria-hidden', true);
                        that.input.removeAttr('aria-activedescendant');
                    }
                    if (candidate) {
                        candidate.addClass(FOCUSEDCLASS).attr(ID, that._tagID);
                        candidate.find('.k-select').removeAttr('aria-hidden');
                        that.input.attr('aria-activedescendant', that._tagID);
                    }
                    that._currentTag = candidate;
                } else {
                    return that._currentTag;
                }
            },
            dataItems: function () {
                return this.listView.selectedDataItems();
            },
            destroy: function () {
                var that = this, ns = that.ns;
                clearTimeout(that._busy);
                clearTimeout(that._typingTimeout);
                that.wrapper.off(ns);
                that.tagList.off(ns);
                that.input.off(ns);
                that._clear.off(ns);
                List.fn.destroy.call(that);
            },
            _activateItem: function () {
                if (this.popup.visible()) {
                    List.fn._activateItem.call(this);
                }
                this.currentTag(null);
            },
            _listOptions: function (options) {
                var that = this;
                var listOptions = List.fn._listOptions.call(that, $.extend(options, {
                    selectedItemChange: proxy(that._selectedItemChange, that),
                    selectable: 'multiple'
                }));
                var itemTemplate = this.options.itemTemplate || this.options.template;
                var template = listOptions.itemTemplate || itemTemplate || listOptions.template;
                if (!template) {
                    template = '#:' + kendo.expr(listOptions.dataTextField, 'data') + '#';
                }
                listOptions.template = template;
                return listOptions;
            },
            _setListValue: function () {
                List.fn._setListValue.call(this, this._initialValues.slice(0));
            },
            _listChange: function (e) {
                var data = this.dataSource.flatView();
                var optionsMap = this._optionsMap;
                var valueGetter = this._value;
                if (this._state === REBIND) {
                    this._state = '';
                }
                for (var i = 0; i < e.added.length; i++) {
                    if (optionsMap[valueGetter(e.added[i].dataItem)] === undefined) {
                        this._render(data);
                        break;
                    }
                }
                this._selectValue(e.added, e.removed);
            },
            _selectedItemChange: function (e) {
                var items = e.items;
                var context;
                var idx;
                for (idx = 0; idx < items.length; idx++) {
                    context = items[idx];
                    this.tagList.children().eq(context.index).children('span:first').html(this.tagTextTemplate(context.item));
                }
            },
            _wrapperMousedown: function (e) {
                var that = this;
                var notInput = e.target.nodeName.toLowerCase() !== 'input';
                var target = $(e.target);
                var closeButton = target.hasClass('k-select') || target.hasClass('k-icon');
                if (closeButton) {
                    closeButton = !target.closest('.k-select').children('.k-i-arrow-60-down').length;
                }
                if (notInput && !(closeButton && kendo.support.mobileOS) && e.cancelable) {
                    e.preventDefault();
                }
                if (!closeButton) {
                    if (that.input[0] !== activeElement() && notInput) {
                        that.input.focus();
                    }
                    if (that.options.minLength === 1) {
                        that.open();
                    }
                }
            },
            _inputFocus: function () {
                this._placeholder(false);
                this.wrapper.addClass(FOCUSEDCLASS);
            },
            _inputFocusout: function () {
                var that = this;
                clearTimeout(that._typingTimeout);
                that.wrapper.removeClass(FOCUSEDCLASS);
                that._placeholder(!that.listView.selectedDataItems()[0], true);
                that.close();
                if (that._state === FILTER) {
                    that._state = ACCEPT;
                    that.listView.skipUpdate(true);
                }
                if (that.listView.bound() && that.listView.isFiltered()) {
                    that.persistTagList = true;
                    that._clearFilter();
                }
                that.element.blur();
            },
            _removeTag: function (tag, shouldTrigger) {
                var that = this;
                var state = that._state;
                var position = tag.index();
                var listView = that.listView;
                var value = listView.value()[position];
                var dataItem = that.listView.selectedDataItems()[position];
                var customIndex = that._customOptions[value];
                var listViewChildren = listView.element[0].children;
                var option;
                var listViewChild;
                if (that.trigger(DESELECT, {
                        dataItem: dataItem,
                        item: tag
                    })) {
                    that._close();
                    return;
                }
                if (customIndex === undefined && (state === ACCEPT || state === FILTER)) {
                    customIndex = that._optionsMap[value];
                }
                var done = function () {
                    that.currentTag(null);
                    if (shouldTrigger) {
                        that._change();
                    }
                    that._close();
                };
                if (customIndex === undefined && listView.select().length) {
                    that.persistTagList = false;
                    listView.select(listView.select()[position]).done(done);
                } else {
                    option = that.element[0].children[customIndex];
                    if (option) {
                        option.selected = false;
                    }
                    listView.removeAt(position);
                    listViewChild = listViewChildren[customIndex];
                    if (listViewChild) {
                        listViewChildren[customIndex].classList.remove('k-state-selected');
                    }
                    if (that.options.tagMode !== 'single') {
                        tag.remove();
                    } else {
                        that._updateTagListHTML();
                    }
                    done();
                }
            },
            _tagListClick: function (e) {
                var target = $(e.currentTarget);
                if (!target.children('.k-i-arrow-60-down').length) {
                    this._removeTag(target.closest(LI), true);
                }
            },
            _clearClick: function () {
                var that = this;
                if (that.options.tagMode === 'single') {
                    that._clearSingleTagValue();
                } else {
                    that.tagList.children().each(function (index, tag) {
                        that._removeTag($(tag), false);
                    });
                }
                that.input.val('');
                that._search();
                that._change();
                that.focus();
                that._hideClear();
                if (that._state === FILTER) {
                    that._state = ACCEPT;
                }
            },
            _clearSingleTagValue: function () {
                var that = this;
                var persistTagList = that.persistTagList;
                if (persistTagList) {
                    that.persistTagList = false;
                }
                that.listView.value([]);
                that.persistTagList = persistTagList;
            },
            _editable: function (options) {
                var that = this, disable = options.disable, readonly = options.readonly, wrapper = that.wrapper.off(ns), tagList = that.tagList.off(ns), input = that.element.add(that.input.off(ns));
                if (!readonly && !disable) {
                    wrapper.removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover).on('mousedown' + ns + ' touchend' + ns, proxy(that._wrapperMousedown, that));
                    that.input.on(KEYDOWN, proxy(that._keydown, that)).on('paste' + ns, proxy(that._search, that)).on('input' + ns, proxy(that._search, that)).on('focus' + ns, proxy(that._inputFocus, that)).on('focusout' + ns, proxy(that._inputFocusout, that));
                    that._clear.on(CLICK + ns + ' touchend' + ns, proxy(that._clearClick, that));
                    input.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false);
                    tagList.on(MOUSEENTER, LI, function () {
                        $(this).addClass(HOVERCLASS);
                    }).on(MOUSELEAVE, LI, function () {
                        $(this).removeClass(HOVERCLASS);
                    }).on(CLICK, 'li.k-button .k-select', proxy(that._tagListClick, that));
                } else {
                    if (disable) {
                        wrapper.addClass(STATEDISABLED);
                    } else {
                        wrapper.removeClass(STATEDISABLED);
                    }
                    input.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
            },
            _close: function () {
                var that = this;
                if (that.options.autoClose) {
                    that.close();
                } else {
                    that.popup.position();
                }
            },
            _filterSource: function (filter, force) {
                if (!force) {
                    force = this._retrieveData;
                }
                this._retrieveData = false;
                List.fn._filterSource.call(this, filter, force);
            },
            close: function () {
                this._activeItem = null;
                this.input.removeAttr('aria-activedescendant');
                this.popup.close();
            },
            open: function () {
                var that = this;
                if (that._request) {
                    that._retrieveData = false;
                }
                if (that._retrieveData || !that.listView.bound() || that._state === ACCEPT) {
                    that._open = true;
                    that._state = REBIND;
                    that.listView.skipUpdate(true);
                    that.persistTagList = that._initialOpen && !that.listView.bound() ? false : true;
                    that._filterSource();
                    that._focusItem();
                } else if (that._allowOpening()) {
                    if (that._initialOpen && !that.options.autoBind && !that.options.virtual && that.options.value && !$.isPlainObject(that.options.value[0])) {
                        that.value(that._initialValues);
                    }
                    that.popup._hovered = true;
                    that._initialOpen = false;
                    that.popup.open();
                    that._focusItem();
                }
            },
            toggle: function (toggle) {
                toggle = toggle !== undefined ? toggle : !this.popup.visible();
                this[toggle ? OPEN : CLOSE]();
            },
            refresh: function () {
                this.listView.refresh();
            },
            _listBound: function () {
                var that = this;
                var data = that.dataSource.flatView();
                var skip = that.listView.skip();
                that._render(data);
                that._renderFooter();
                that._renderNoData();
                that._toggleNoData(!data.length);
                that._resizePopup();
                if (that._open) {
                    that._open = false;
                    that.toggle(that._allowOpening());
                }
                that.popup.position();
                if (that.options.highlightFirst && (skip === undefined || skip === 0)) {
                    that.listView.focusFirst();
                }
                if (that._touchScroller) {
                    that._touchScroller.reset();
                }
                that._hideBusy();
                that._makeUnselectable();
                that.trigger('dataBound');
            },
            _inputValue: function () {
                var that = this;
                var inputValue = that.input.val();
                if (that.options.placeholder === inputValue) {
                    inputValue = '';
                }
                return inputValue;
            },
            value: function (value) {
                var that = this;
                var listView = that.listView;
                var oldValue = listView.value().slice();
                var maxSelectedItems = that.options.maxSelectedItems;
                var clearFilters = listView.bound() && listView.isFiltered();
                if (value === undefined) {
                    return oldValue;
                }
                that.persistTagList = false;
                that.requireValueMapper(that.options, value);
                value = that._normalizeValues(value);
                if (maxSelectedItems !== null && value.length > maxSelectedItems) {
                    value = value.slice(0, maxSelectedItems);
                }
                if (clearFilters) {
                    that._clearFilter();
                }
                listView.value(value);
                that._old = that._valueBeforeCascade = value.slice();
                if (!clearFilters) {
                    that._fetchData();
                }
                that._ariaSetSize(that.value().length);
                that._toggleCloseVisibility();
            },
            _preselect: function (data, value) {
                var that = this;
                if (!isArray(data) && !(data instanceof kendo.data.ObservableArray)) {
                    data = [data];
                }
                if ($.isPlainObject(data[0]) || data[0] instanceof kendo.data.ObservableObject || !that.options.dataValueField) {
                    that.dataSource.data(data);
                    that.value(value || that._initialValues);
                    that._retrieveData = true;
                }
            },
            _setOption: function (value, selected) {
                var option = this.element[0].children[this._optionsMap[value]];
                if (option) {
                    option.selected = selected;
                }
            },
            _fetchData: function () {
                var that = this;
                var hasItems = !!that.dataSource.view().length;
                var isEmptyArray = that.listView.value().length === 0;
                if (isEmptyArray || that._request) {
                    return;
                }
                if (that._retrieveData || !that._fetch && !hasItems) {
                    that._fetch = true;
                    that._retrieveData = false;
                    that.dataSource.read().done(function () {
                        that._fetch = false;
                    });
                }
            },
            _isBound: function () {
                return this.listView.bound() && !this._retrieveData;
            },
            _dataSource: function () {
                var that = this, element = that.element, options = that.options, dataSource = options.dataSource || {};
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                dataSource.select = element;
                dataSource.fields = [
                    { field: options.dataTextField },
                    { field: options.dataValueField }
                ];
                if (that.dataSource && that._refreshHandler) {
                    that._unbindDataSource();
                } else {
                    that._progressHandler = proxy(that._showBusy, that);
                    that._errorHandler = proxy(that._hideBusy, that);
                }
                that.dataSource = kendo.data.DataSource.create(dataSource).bind(PROGRESS, that._progressHandler).bind('error', that._errorHandler);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(that._initialValues);
                            that._placeholder();
                        });
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            },
            _initValue: function () {
                var value = this.options.value || this.element.val();
                this._old = this._initialValues = this._normalizeValues(value);
            },
            _normalizeValues: function (value) {
                var that = this;
                if (value === null) {
                    value = [];
                } else if (value && $.isPlainObject(value)) {
                    value = [that._value(value)];
                } else if (value && $.isPlainObject(value[0])) {
                    value = $.map(value, function (dataItem) {
                        return that._value(dataItem);
                    });
                } else if (!isArray(value) && !(value instanceof ObservableArray)) {
                    value = [value];
                } else if (isArray(value)) {
                    value = value.slice();
                }
                return value;
            },
            _change: function () {
                var that = this, value = that.value();
                if (!compare(value, that._old)) {
                    that._old = value.slice();
                    that.trigger(CHANGE);
                    that.element.trigger(CHANGE);
                }
                that.popup.position();
                that._ariaSetSize(value.length);
                that._toggleCloseVisibility();
            },
            _click: function (e) {
                var that = this;
                var item = e.item;
                e.preventDefault();
                that._select(item).done(function () {
                    that._activeItem = item;
                    that._change();
                    that._close();
                });
            },
            _getActiveItem: function () {
                return this._activeItem || $(this.listView.items()[this._getSelectedIndices().length - 1]) || this.listView.focus();
            },
            _getSelectedIndices: function () {
                return this.listView._selectedIndices || this.listView._selectedIndexes;
            },
            _keydown: function (e) {
                var that = this;
                var key = e.keyCode;
                var tag = that._currentTag;
                var listView = that.listView;
                var hasValue = that.input.val();
                var isRtl = kendo.support.isRtl(that.wrapper);
                var visible = that.popup.visible();
                var dir = 0;
                var activeItemIdx;
                if (key !== keys.ENTER) {
                    this._multipleSelection = false;
                }
                if (key === keys.DOWN) {
                    e.preventDefault();
                    if (!visible) {
                        that.open();
                        if (!listView.focus()) {
                            listView.focusFirst();
                        }
                        return;
                    }
                    if (listView.focus()) {
                        if (!that._activeItem && e.shiftKey) {
                            that._activeItem = listView.focus();
                            dir = -1;
                        }
                        activeItemIdx = listView.getElementIndex(that._getActiveItem().first());
                        listView.focusNext();
                        if (!listView.focus()) {
                            listView.focusLast();
                        } else {
                            if (e.shiftKey) {
                                this._multipleSelection = true;
                                that._selectRange(activeItemIdx, listView.getElementIndex(listView.focus().first()) + dir);
                            }
                        }
                    } else {
                        listView.focusFirst();
                    }
                } else if (key === keys.UP) {
                    if (visible) {
                        if (!that._activeItem && e.shiftKey) {
                            that._activeItem = listView.focus();
                            dir = 1;
                        }
                        activeItemIdx = listView.getElementIndex(that._getActiveItem().first());
                        listView.focusPrev();
                        if (!listView.focus()) {
                            that.close();
                        } else {
                            if (e.shiftKey) {
                                this._multipleSelection = true;
                                that._selectRange(activeItemIdx, listView.getElementIndex(listView.focus().first()) + dir);
                            }
                        }
                    }
                    e.preventDefault();
                } else if (key === keys.LEFT && !isRtl || key === keys.RIGHT && isRtl) {
                    if (!hasValue) {
                        tag = tag ? tag.prev() : $(that.tagList[0].lastChild);
                        if (tag[0]) {
                            that.currentTag(tag);
                        }
                    }
                } else if (key === keys.RIGHT && !isRtl || key === keys.LEFT && isRtl) {
                    if (!hasValue && tag) {
                        tag = tag.next();
                        that.currentTag(tag[0] ? tag : null);
                    }
                } else if (e.ctrlKey && !e.altKey && key === keys.A && visible && !that.options.virtual) {
                    this._multipleSelection = true;
                    if (this._getSelectedIndices().length === listView.items().length) {
                        that._activeItem = null;
                    }
                    if (listView.items().length) {
                        that._selectRange(0, listView.items().length - 1);
                    }
                } else if (key === keys.ENTER && visible) {
                    if (!listView.focus()) {
                        return;
                    }
                    e.preventDefault();
                    if (this._multipleSelection) {
                        this._multipleSelection = false;
                        if (listView.focus().hasClass(SELECTEDCLASS)) {
                            that._close();
                            return;
                        }
                    }
                    that._select(listView.focus()).done(function () {
                        that._change();
                        that._close();
                    });
                } else if (key === keys.SPACEBAR && e.ctrlKey && visible) {
                    if (that._activeItem && listView.focus() && listView.focus()[0] === that._activeItem[0]) {
                        that._activeItem = null;
                    }
                    if (!$(listView.focus()).hasClass(SELECTEDCLASS)) {
                        that._activeItem = listView.focus();
                    }
                    that._select(listView.focus()).done(function () {
                        that._change();
                    });
                    e.preventDefault();
                } else if (key === keys.SPACEBAR && e.shiftKey && visible) {
                    var activeIndex = listView.getElementIndex(that._getActiveItem());
                    var currentIndex = listView.getElementIndex(listView.focus());
                    if (activeIndex !== undefined && currentIndex !== undefined) {
                        that._selectRange(activeIndex, currentIndex);
                    }
                    e.preventDefault();
                } else if (key === keys.ESC) {
                    if (visible) {
                        e.preventDefault();
                    } else {
                        that.tagList.children().each(function (index, tag) {
                            that._removeTag($(tag), false);
                        });
                        that._change();
                    }
                    that.close();
                } else if (key === keys.HOME) {
                    if (visible) {
                        if (!listView.focus()) {
                            that.close();
                        } else {
                            if (e.ctrlKey && e.shiftKey && !that.options.virtual) {
                                that._selectRange(listView.getElementIndex(listView.focus()[0]), 0);
                            }
                            listView.focusFirst();
                        }
                    } else if (!hasValue) {
                        tag = that.tagList[0].firstChild;
                        if (tag) {
                            that.currentTag($(tag));
                        }
                    }
                } else if (key === keys.END) {
                    if (visible) {
                        if (!listView.focus()) {
                            that.close();
                        } else {
                            if (e.ctrlKey && e.shiftKey && !that.options.virtual) {
                                that._selectRange(listView.getElementIndex(listView.focus()[0]), listView.element.children().length - 1);
                            }
                            listView.focusLast();
                        }
                    } else if (!hasValue) {
                        tag = that.tagList[0].lastChild;
                        if (tag) {
                            that.currentTag($(tag));
                        }
                    }
                } else if ((key === keys.DELETE || key === keys.BACKSPACE) && !hasValue) {
                    that._state = ACCEPT;
                    if (that.options.tagMode === 'single') {
                        that._clearSingleTagValue();
                        that._change();
                        that._close();
                        return;
                    }
                    if (key === keys.BACKSPACE && !tag) {
                        tag = $(that.tagList[0].lastChild);
                    }
                    if (tag && tag[0]) {
                        that._removeTag(tag, true);
                    }
                } else if (that.popup.visible() && (key === keys.PAGEDOWN || key === keys.PAGEUP)) {
                    e.preventDefault();
                    var direction = key === keys.PAGEDOWN ? 1 : -1;
                    listView.scrollWith(direction * listView.screenHeight());
                } else {
                    clearTimeout(that._typingTimeout);
                    setTimeout(function () {
                        that._scale();
                    });
                    that._search();
                }
            },
            _hideBusy: function () {
                var that = this;
                clearTimeout(that._busy);
                that.input.attr('aria-busy', false);
                that._loading.addClass(HIDDENCLASS);
                that._request = false;
                that._busy = null;
                that._toggleCloseVisibility();
            },
            _showBusyHandler: function () {
                this.input.attr('aria-busy', true);
                this._loading.removeClass(HIDDENCLASS);
                this._hideClear();
            },
            _showBusy: function () {
                var that = this;
                that._request = true;
                if (that._busy) {
                    return;
                }
                that._busy = setTimeout(proxy(that._showBusyHandler, that), 100);
            },
            _placeholder: function (show, skipCaret) {
                var that = this;
                var input = that.input;
                var active = activeElement();
                var placeholder = that.options.placeholder;
                var inputValue = input.val();
                var isActive = input[0] === active;
                var caretPos = inputValue.length;
                if (!isActive || that.options.autoClose || inputValue === placeholder) {
                    caretPos = 0;
                    inputValue = '';
                }
                if (show === undefined) {
                    show = false;
                    if (input[0] !== active) {
                        show = !that.listView.selectedDataItems()[0];
                    }
                }
                that._prev = inputValue;
                input.toggleClass('k-readonly', show).val(show ? placeholder : inputValue);
                if (isActive && !skipCaret) {
                    kendo.caret(input[0], caretPos, caretPos);
                }
                that._scale();
            },
            _scale: function () {
                var that = this, wrapper = that.wrapper.find('.k-multiselect-wrap'), wrapperWidth = wrapper.width(), span = that._span.text(that.input.val()), textWidth;
                if (!wrapper.is(':visible')) {
                    span.appendTo(document.documentElement);
                    wrapperWidth = textWidth = span.width() + 25;
                    span.appendTo(wrapper);
                } else {
                    textWidth = span.width() + 25;
                }
                that.input.width(textWidth > wrapperWidth ? wrapperWidth : textWidth);
            },
            _option: function (dataValue, dataText, selected) {
                var option = '<option';
                if (dataValue !== undefined) {
                    dataValue += '';
                    if (dataValue.indexOf('"') !== -1) {
                        dataValue = dataValue.replace(quotRegExp, '&quot;');
                    }
                    option += ' value="' + dataValue + '"';
                }
                if (selected) {
                    option += ' selected';
                }
                option += '>';
                if (dataText !== undefined) {
                    option += kendo.htmlEncode(dataText);
                }
                return option += '</option>';
            },
            _render: function (data) {
                var selectedItems = this.listView.selectedDataItems();
                var values = this.listView.value();
                var length = data.length;
                var selectedIndex;
                var options = '';
                var dataItem;
                var value;
                var idx;
                if (values.length !== selectedItems.length) {
                    selectedItems = this._buildSelectedItems(values);
                }
                var custom = {};
                var optionsMap = {};
                for (idx = 0; idx < length; idx++) {
                    dataItem = data[idx];
                    value = this._value(dataItem);
                    selectedIndex = this._selectedItemIndex(value, selectedItems);
                    if (selectedIndex !== -1) {
                        selectedItems.splice(selectedIndex, 1);
                    }
                    optionsMap[value] = idx;
                    options += this._option(value, this._text(dataItem), selectedIndex !== -1);
                }
                if (selectedItems.length) {
                    for (idx = 0; idx < selectedItems.length; idx++) {
                        dataItem = selectedItems[idx];
                        value = this._value(dataItem);
                        custom[value] = length;
                        optionsMap[value] = length;
                        length += 1;
                        options += this._option(value, this._text(dataItem), true);
                    }
                }
                this._customOptions = custom;
                this._optionsMap = optionsMap;
                this.element.html(options);
            },
            _buildSelectedItems: function (values) {
                var valueField = this.options.dataValueField;
                var textField = this.options.dataTextField;
                var result = [];
                var item;
                for (var idx = 0; idx < values.length; idx++) {
                    item = {};
                    item[valueField] = values[idx];
                    item[textField] = values[idx];
                    result.push(item);
                }
                return result;
            },
            _selectedItemIndex: function (value, selectedItems) {
                var valueGetter = this._value;
                var idx = 0;
                for (; idx < selectedItems.length; idx++) {
                    if (value === valueGetter(selectedItems[idx])) {
                        return idx;
                    }
                }
                return -1;
            },
            _search: function () {
                var that = this;
                clearTimeout(that._typingTimeout);
                that._typingTimeout = setTimeout(function () {
                    var value = that._inputValue();
                    if (that._prev !== value) {
                        that._prev = value;
                        that.search(value);
                        that._toggleCloseVisibility();
                    }
                }, that.options.delay);
            },
            _toggleCloseVisibility: function () {
                if (this.value().length || this.input.val() && this.input.val() !== this.options.placeholder) {
                    this._showClear();
                } else {
                    this._hideClear();
                }
            },
            _allowOpening: function () {
                return this._allowSelection() && List.fn._allowOpening.call(this);
            },
            _allowSelection: function () {
                var max = this.options.maxSelectedItems;
                return max === null || max > this.listView.value().length;
            },
            _angularTagItems: function (cmd) {
                var that = this;
                that.angular(cmd, function () {
                    return {
                        elements: that.tagList[0].children,
                        data: $.map(that.dataItems(), function (dataItem) {
                            return { dataItem: dataItem };
                        })
                    };
                });
            },
            updatePersistTagList: function (added, removed) {
                if (this.persistTagList.added && this.persistTagList.added.length === removed.length && this.persistTagList.removed && this.persistTagList.removed.length === added.length) {
                    this.persistTagList = false;
                } else {
                    this.listView._removedAddedIndexes = this._old.slice();
                    this.persistTagList = {
                        added: added,
                        removed: removed
                    };
                }
            },
            _selectValue: function (added, removed) {
                var that = this;
                var total = that.dataSource.total();
                var tagList = that.tagList;
                var getter = that._value;
                var removedItem;
                var addedItem;
                var idx;
                if (this.persistTagList) {
                    this.updatePersistTagList(added, removed);
                    return;
                }
                that._angularTagItems('cleanup');
                if (that.options.tagMode === 'multiple') {
                    for (idx = removed.length - 1; idx > -1; idx--) {
                        removedItem = removed[idx];
                        if (tagList.children().length) {
                            tagList[0].removeChild(tagList[0].children[removedItem.position]);
                            that._setOption(getter(removedItem.dataItem), false);
                        }
                    }
                    for (idx = 0; idx < added.length; idx++) {
                        addedItem = added[idx];
                        tagList.append(that.tagTemplate(addedItem.dataItem));
                        that._setOption(getter(addedItem.dataItem), true);
                    }
                } else {
                    if (!that._maxTotal || that._maxTotal < total) {
                        that._maxTotal = total;
                    }
                    this._updateTagListHTML();
                    for (idx = removed.length - 1; idx > -1; idx--) {
                        that._setOption(getter(removed[idx].dataItem), false);
                    }
                    for (idx = 0; idx < added.length; idx++) {
                        that._setOption(getter(added[idx].dataItem), true);
                    }
                }
                that._angularTagItems('compile');
                that._placeholder();
            },
            _updateTagListHTML: function () {
                var that = this;
                var values = that.value();
                var total = that.dataSource.total();
                var tagList = that.tagList;
                tagList.html('');
                if (values.length) {
                    tagList.append(that.tagTemplate({
                        values: values,
                        dataItems: that.dataItems(),
                        maxTotal: that._maxTotal,
                        currentTotal: total
                    }));
                }
            },
            _select: function (candidate) {
                var resolved = $.Deferred().resolve();
                if (!candidate) {
                    return resolved;
                }
                var that = this;
                var listView = that.listView;
                var dataItem = listView.dataItemByIndex(listView.getElementIndex(candidate));
                var isSelected = candidate.hasClass('k-state-selected');
                if (that._state === REBIND) {
                    that._state = '';
                }
                if (!that._allowSelection() && !isSelected) {
                    return resolved;
                }
                if (that.trigger(isSelected ? DESELECT : SELECT, {
                        dataItem: dataItem,
                        item: candidate
                    })) {
                    that._close();
                    return resolved;
                }
                that.persistTagList = false;
                return listView.select(candidate).done(function () {
                    that._placeholder();
                    if (that._state === FILTER) {
                        that._state = ACCEPT;
                        listView.skipUpdate(true);
                    }
                });
            },
            _selectRange: function (startIndex, endIndex) {
                var that = this;
                var listView = this.listView;
                var maxSelectedItems = this.options.maxSelectedItems;
                var indices = this._getSelectedIndices().slice();
                var indicesToSelect = [];
                var i;
                var selectIndices = function (indices) {
                    listView.select(indices).done(function () {
                        indices.forEach(function (index) {
                            var dataItem = listView.dataItemByIndex(index);
                            var candidate = listView.element.children()[index];
                            var isSelected = $(candidate).hasClass('k-state-selected');
                            that.trigger(isSelected ? SELECT : DESELECT, {
                                dataItem: dataItem,
                                item: $(candidate)
                            });
                        });
                        that._change();
                    });
                };
                if (indices.length - 1 === endIndex - startIndex) {
                    return selectIndices(indices);
                }
                if (startIndex < endIndex) {
                    for (i = startIndex; i <= endIndex; i++) {
                        indicesToSelect.push(i);
                    }
                } else {
                    for (i = startIndex; i >= endIndex; i--) {
                        indicesToSelect.push(i);
                    }
                }
                if (maxSelectedItems !== null && indicesToSelect.length > maxSelectedItems) {
                    indicesToSelect = indicesToSelect.slice(0, maxSelectedItems);
                }
                for (i = 0; i < indicesToSelect.length; i++) {
                    var index = indicesToSelect[i];
                    if (this._getSelectedIndices().indexOf(index) == -1) {
                        indices.push(index);
                    } else {
                        indices.splice(indices.indexOf(index), 1);
                    }
                }
                if (!indices.length) {
                    return;
                }
                that.persistTagList = false;
                return selectIndices(indices);
            },
            _input: function () {
                var that = this;
                var element = that.element;
                var accessKey = element[0].accessKey;
                var input = that._innerWrapper.children('input.k-input');
                if (!input[0]) {
                    input = $('<input class="k-input" style="width: 25px" />').appendTo(that._innerWrapper);
                }
                element.removeAttr('accesskey');
                that._focused = that.input = input.attr({
                    'accesskey': accessKey,
                    'autocomplete': AUTOCOMPLETEVALUE,
                    'role': 'listbox',
                    'title': element[0].title,
                    'aria-expanded': false,
                    'aria-haspopup': 'listbox',
                    'aria-autocomplete': 'list'
                });
            },
            _tagList: function () {
                var that = this, tagList = that._innerWrapper.children('ul');
                if (!tagList[0]) {
                    tagList = $('<ul unselectable="on" class="k-reset"/>').appendTo(that._innerWrapper);
                }
                that.tagList = tagList;
            },
            _tagTemplate: function () {
                var that = this;
                var options = that.options;
                var tagTemplate = options.tagTemplate;
                var hasDataSource = options.dataSource;
                var isMultiple = options.tagMode === 'multiple';
                var defaultTemplate;
                if (that.element[0].length && !hasDataSource) {
                    options.dataTextField = options.dataTextField || 'text';
                    options.dataValueField = options.dataValueField || 'value';
                }
                defaultTemplate = isMultiple ? kendo.template('#:' + kendo.expr(options.dataTextField, 'data') + '#', { useWithBlock: false }) : kendo.template('#:values.length# item(s) selected');
                that.tagTextTemplate = tagTemplate = tagTemplate ? kendo.template(tagTemplate) : defaultTemplate;
                that.tagTemplate = function (data) {
                    return '<li role="option" aria-selected="true" class="k-button" unselectable="on"><span unselectable="on">' + tagTemplate(data) + '</span><span aria-hidden="true" unselectable="on" aria-label="' + (isMultiple ? 'delete' : 'open') + '" class="k-select"><span class="k-icon ' + (isMultiple ? 'k-i-close' : 'k-i-arrow-60-down') + '">' + '</span></span></li>';
                };
            },
            _loader: function () {
                this._loading = $('<span class="k-icon k-i-loading ' + HIDDENCLASS + '"></span>').insertAfter(this.input);
            },
            _clearButton: function () {
                List.fn._clearButton.call(this);
                if (this.options.clearButton) {
                    this._clear.insertAfter(this.input);
                    this.wrapper.addClass('k-multiselect-clearable');
                }
            },
            _textContainer: function () {
                var computedStyles = kendo.getComputedStyles(this.input[0], styles);
                computedStyles.position = 'absolute';
                computedStyles.visibility = 'hidden';
                computedStyles.top = -3333;
                computedStyles.left = -3333;
                this._span = $('<span/>').css(computedStyles).appendTo(this.wrapper);
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper = element.parent('span.k-multiselect');
                if (!wrapper[0]) {
                    wrapper = element.wrap('<div class="k-widget k-multiselect" unselectable="on" />').parent();
                    wrapper[0].style.cssText = element[0].style.cssText;
                    wrapper[0].title = element[0].title;
                    $('<div class="k-multiselect-wrap k-floatwrap" role="listbox" unselectable="on" />').insertBefore(element);
                }
                that.wrapper = wrapper.addClass(element[0].className).css('display', '');
                that._innerWrapper = $(wrapper[0].firstChild);
            },
            _ariaSetSize: function (value) {
                var that = this;
                var selectedItems = that.tagList.children();
                if (value && selectedItems.length) {
                    selectedItems.attr('aria-setsize', value);
                }
            },
            _ariaSetLive: function () {
                var that = this;
                that.ul.attr('aria-live', !that._isFilterEnabled() ? 'off' : 'polite');
            }
        });
        function compare(a, b) {
            var length;
            if (a === null && b !== null || a !== null && b === null) {
                return false;
            }
            length = a.length;
            if (length !== b.length) {
                return false;
            }
            while (length--) {
                if (a[length] !== b[length]) {
                    return false;
                }
            }
            return true;
        }
        ui.plugin(MultiSelect);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.multicolumncombobox', ['kendo.combobox'], f);
}(function () {
    var __meta__ = {
        id: 'multicolumncombobox',
        name: 'MultiColumnComboBox',
        category: 'web',
        description: 'The MultiColumnComboBox widget allows the selection from pre-defined values or entering a new value where the list popup is rendered in table layout.',
        depends: ['combobox'],
        features: [
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            },
            {
                id: 'virtualization',
                name: 'VirtualList',
                description: 'Support for virtualization',
                depends: ['virtuallist']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, ComboBox = ui.ComboBox, percentageUnitsRegex = /^\d+(\.\d+)?%$/i, MCCOMBOBOX = 'k-dropdowngrid', POPUPCLASS = 'k-dropdowngrid-popup k-popup-flush';
        var MultiColumnComboBox = ComboBox.extend({
            init: function (element, options) {
                ComboBox.fn.init.call(this, element, options);
                this.list.addClass(POPUPCLASS);
                if (this._allColumnsWidthsAreSet(this.options)) {
                    this.list.width(this._calculateDropDownWidth(this.options));
                } else if (this.options.dropDownWidth) {
                    this.list.width(this.options.dropDownWidth);
                }
            },
            options: {
                name: 'MultiColumnComboBox',
                ns: '.kendoMultiColumnComboBox',
                columns: [],
                dropDownWidth: null,
                filterFields: []
            },
            setOptions: function (options) {
                ComboBox.fn.setOptions.call(this, options);
                if (this._allColumnsWidthsAreSet(options)) {
                    this.list.width(this._calculateDropDownWidth(options));
                } else if (this.options.dropDownWidth) {
                    this.list.width(this.options.dropDownWidth);
                }
            },
            _allColumnsWidthsAreSet: function (options) {
                var columns = options.columns;
                if (!columns || !columns.length) {
                    return false;
                }
                for (var i = 0; i < columns.length; i++) {
                    var currentWidth = columns[i].width;
                    if (!currentWidth || isNaN(parseInt(currentWidth, 10)) || percentageUnitsRegex.test(currentWidth)) {
                        return false;
                    }
                }
                return true;
            },
            _calculateDropDownWidth: function (options) {
                var columns = options.columns;
                var totalWidth = kendo.support.scrollbar();
                for (var i = 0; i < columns.length; i++) {
                    var currentWidth = columns[i].width;
                    totalWidth = totalWidth + parseInt(currentWidth, 10);
                }
                return totalWidth;
            },
            _wrapper: function () {
                ComboBox.fn._wrapper.call(this);
                this.wrapper.addClass(MCCOMBOBOX);
            }
        });
        ui.plugin(MultiColumnComboBox);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.slider', ['kendo.draganddrop'], f);
}(function () {
    var __meta__ = {
        id: 'slider',
        name: 'Slider',
        category: 'web',
        description: 'The Slider widget provides a rich input for selecting values or ranges of values.',
        depends: ['draganddrop']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, Draggable = kendo.ui.Draggable, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, extend = $.extend, format = kendo.format, parse = kendo.parseFloat, proxy = $.proxy, isArray = $.isArray, math = Math, support = kendo.support, pointers = support.pointers, msPointers = support.msPointers, CHANGE = 'change', SLIDE = 'slide', NS = '.slider', MOUSE_DOWN = 'touchstart' + NS + ' mousedown' + NS, TRACK_MOUSE_DOWN = pointers ? 'pointerdown' + NS : msPointers ? 'MSPointerDown' + NS : MOUSE_DOWN, MOUSE_UP = 'touchend' + NS + ' mouseup' + NS, TRACK_MOUSE_UP = pointers ? 'pointerup' : msPointers ? 'MSPointerUp' + NS : MOUSE_UP, MOVE_SELECTION = 'moveSelection', KEY_DOWN = 'keydown' + NS, CLICK = 'click' + NS, MOUSE_OVER = 'mouseover' + NS, FOCUS = 'focus' + NS, BLUR = 'blur' + NS, DRAG_HANDLE = '.k-draghandle', TRACK_SELECTOR = '.k-slider-track', TICK_SELECTOR = '.k-tick', STATE_SELECTED = 'k-state-selected', STATE_FOCUSED = 'k-state-focused', STATE_DEFAULT = 'k-state-default', STATE_DISABLED = 'k-state-disabled', DISABLED = 'disabled', UNDEFINED = 'undefined', TABINDEX = 'tabindex', getTouches = kendo.getTouches;
        var SliderBase = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                that._isHorizontal = options.orientation == 'horizontal';
                that._isRtl = that._isHorizontal && kendo.support.isRtl(element);
                that._position = that._isHorizontal ? 'left' : 'bottom';
                that._sizeFn = that._isHorizontal ? 'width' : 'height';
                that._outerSize = that._isHorizontal ? outerWidth : outerHeight;
                options.tooltip.format = options.tooltip.enabled ? options.tooltip.format || '{0}' : '{0}';
                if (options.smallStep <= 0) {
                    throw new Error('Kendo UI Slider smallStep must be a positive number.');
                }
                that._createHtml();
                that.wrapper = that.element.closest('.k-slider');
                that._trackDiv = that.wrapper.find(TRACK_SELECTOR);
                that._setTrackDivWidth();
                that._maxSelection = that._trackDiv[that._sizeFn]();
                that._sliderItemsInit();
                that._reset();
                that._tabindex(that.wrapper.find(DRAG_HANDLE));
                that[options.enabled ? 'enable' : 'disable']();
                var rtlDirectionSign = kendo.support.isRtl(that.wrapper) ? -1 : 1;
                that._keyMap = {
                    37: step(-1 * rtlDirectionSign * options.smallStep),
                    40: step(-options.smallStep),
                    39: step(+1 * rtlDirectionSign * options.smallStep),
                    38: step(+options.smallStep),
                    35: setValue(options.max),
                    36: setValue(options.min),
                    33: step(+options.largeStep),
                    34: step(-options.largeStep)
                };
                kendo.notify(that);
            },
            events: [
                CHANGE,
                SLIDE
            ],
            options: {
                enabled: true,
                min: 0,
                max: 10,
                smallStep: 1,
                largeStep: 5,
                orientation: 'horizontal',
                tickPlacement: 'both',
                tooltip: {
                    enabled: true,
                    format: '{0}'
                }
            },
            _distance: function () {
                return round(this.options.max - this.options.min);
            },
            _resize: function () {
                this._setTrackDivWidth();
                this.wrapper.find('.k-slider-items').remove();
                this._maxSelection = this._trackDiv[this._sizeFn]();
                this._sliderItemsInit();
                this._refresh();
                if (this.options.enabled) {
                    this.enable(true);
                }
            },
            _sliderItemsInit: function () {
                var that = this, options = that.options;
                var sizeBetweenTicks = that._maxSelection / ((options.max - options.min) / options.smallStep);
                var pixelWidths = that._calculateItemsWidth(math.floor(that._distance() / options.smallStep));
                if (options.tickPlacement != 'none' && sizeBetweenTicks >= 2) {
                    $(this.element).parent().find('.k-slider-items').remove();
                    that._trackDiv.before(createSliderItems(options, that._distance()));
                    that._setItemsWidth(pixelWidths);
                    that._setItemsTitle();
                }
                that._calculateSteps(pixelWidths);
                if (options.tickPlacement != 'none' && sizeBetweenTicks >= 2 && options.largeStep >= options.smallStep) {
                    that._setItemsLargeTick();
                }
            },
            getSize: function () {
                return kendo.dimensions(this.wrapper);
            },
            _setTrackDivWidth: function () {
                var that = this, trackDivPosition = parseFloat(that._trackDiv.css(that._isRtl ? 'right' : that._position), 10) * 2;
                that._trackDiv[that._sizeFn](that.wrapper[that._sizeFn]() - 2 - trackDivPosition);
            },
            _setItemsWidth: function (pixelWidths) {
                var that = this, options = that.options, first = 0, last = pixelWidths.length - 1, items = that.wrapper.find(TICK_SELECTOR), i, paddingTop = 0, bordersWidth = 2, count = items.length, selection = 0;
                for (i = 0; i < count - 2; i++) {
                    $(items[i + 1])[that._sizeFn](pixelWidths[i]);
                }
                if (that._isHorizontal) {
                    $(items[first]).addClass('k-first')[that._sizeFn](pixelWidths[last - 1]);
                    $(items[last]).addClass('k-last')[that._sizeFn](pixelWidths[last]);
                } else {
                    $(items[last]).addClass('k-first')[that._sizeFn](pixelWidths[last]);
                    $(items[first]).addClass('k-last')[that._sizeFn](pixelWidths[last - 1]);
                }
                if (that._distance() % options.smallStep !== 0 && !that._isHorizontal) {
                    for (i = 0; i < pixelWidths.length; i++) {
                        selection += pixelWidths[i];
                    }
                    paddingTop = that._maxSelection - selection;
                    paddingTop += parseFloat(that._trackDiv.css(that._position), 10) + bordersWidth;
                    that.wrapper.find('.k-slider-items').css('padding-top', paddingTop);
                }
            },
            _setItemsTitle: function () {
                var that = this, options = that.options, items = that.wrapper.find(TICK_SELECTOR), titleNumber = options.min, count = items.length, i = that._isHorizontal && !that._isRtl ? 0 : count - 1, limit = that._isHorizontal && !that._isRtl ? count : -1, increment = that._isHorizontal && !that._isRtl ? 1 : -1;
                for (; i - limit !== 0; i += increment) {
                    $(items[i]).attr('title', format(options.tooltip.format, round(titleNumber)));
                    titleNumber += options.smallStep;
                }
            },
            _setItemsLargeTick: function () {
                var that = this, options = that.options, items = that.wrapper.find(TICK_SELECTOR), i = 0, item, value;
                if (removeFraction(options.largeStep) % removeFraction(options.smallStep) === 0 || that._distance() / options.largeStep >= 3) {
                    if (!that._isHorizontal && !that._isRtl) {
                        items = $.makeArray(items).reverse();
                    }
                    for (i = 0; i < items.length; i++) {
                        item = $(items[i]);
                        value = that._values[i];
                        var valueWithoutFraction = round(removeFraction(value - this.options.min));
                        if (valueWithoutFraction % removeFraction(options.smallStep) === 0 && valueWithoutFraction % removeFraction(options.largeStep) === 0) {
                            item.addClass('k-tick-large').html('<span class=\'k-label\'>' + item.attr('title') + '</span>');
                            if (i !== 0 && i !== items.length - 1) {
                                item.css('line-height', item[that._sizeFn]() + 'px');
                            }
                        }
                    }
                }
            },
            _calculateItemsWidth: function (itemsCount) {
                var that = this, options = that.options, trackDivSize = parseFloat(that._trackDiv.css(that._sizeFn)) + 1, distance = that._distance(), pixelStep = trackDivSize / distance, itemWidth, pixelWidths, i;
                if (distance / options.smallStep - math.floor(distance / options.smallStep) > 0) {
                    trackDivSize -= distance % options.smallStep * pixelStep;
                }
                itemWidth = trackDivSize / itemsCount;
                pixelWidths = [];
                for (i = 0; i < itemsCount - 1; i++) {
                    pixelWidths[i] = itemWidth;
                }
                pixelWidths[itemsCount - 1] = pixelWidths[itemsCount] = itemWidth / 2;
                return that._roundWidths(pixelWidths);
            },
            _roundWidths: function (pixelWidthsArray) {
                var balance = 0, count = pixelWidthsArray.length, i;
                for (i = 0; i < count; i++) {
                    balance += pixelWidthsArray[i] - math.floor(pixelWidthsArray[i]);
                    pixelWidthsArray[i] = math.floor(pixelWidthsArray[i]);
                }
                balance = math.round(balance);
                return this._addAdditionalSize(balance, pixelWidthsArray);
            },
            _addAdditionalSize: function (additionalSize, pixelWidthsArray) {
                if (additionalSize === 0) {
                    return pixelWidthsArray;
                }
                var step = parseFloat(pixelWidthsArray.length - 1) / parseFloat(additionalSize == 1 ? additionalSize : additionalSize - 1), i;
                for (i = 0; i < additionalSize; i++) {
                    pixelWidthsArray[parseInt(math.round(step * i), 10)] += 1;
                }
                return pixelWidthsArray;
            },
            _calculateSteps: function (pixelWidths) {
                var that = this, options = that.options, val = options.min, selection = 0, distance = that._distance(), itemsCount = math.ceil(distance / options.smallStep), i = 1, lastItem;
                itemsCount += distance / options.smallStep % 1 === 0 ? 1 : 0;
                pixelWidths.splice(0, 0, pixelWidths[itemsCount - 2] * 2);
                pixelWidths.splice(itemsCount - 1, 1, pixelWidths.pop() * 2);
                that._pixelSteps = [selection];
                that._values = [val];
                if (itemsCount === 0) {
                    return;
                }
                while (i < itemsCount) {
                    selection += (pixelWidths[i - 1] + pixelWidths[i]) / 2;
                    that._pixelSteps[i] = selection;
                    val += options.smallStep;
                    that._values[i] = round(val);
                    i++;
                }
                lastItem = distance % options.smallStep === 0 ? itemsCount - 1 : itemsCount;
                that._pixelSteps[lastItem] = that._maxSelection;
                that._values[lastItem] = options.max;
                if (that._isRtl) {
                    that._pixelSteps.reverse();
                    that._values.reverse();
                }
            },
            _getValueFromPosition: function (mousePosition, dragableArea) {
                var that = this, options = that.options, step = math.max(options.smallStep * (that._maxSelection / that._distance()), 0), position = 0, halfStep = step / 2, i;
                if (that._isHorizontal) {
                    position = mousePosition - dragableArea.startPoint;
                    if (that._isRtl) {
                        position = that._maxSelection - position;
                    }
                } else {
                    position = dragableArea.startPoint - mousePosition;
                }
                if (that._maxSelection - (parseInt(that._maxSelection % step, 10) - 3) / 2 < position) {
                    return options.max;
                }
                for (i = 0; i < that._pixelSteps.length; i++) {
                    if (math.abs(that._pixelSteps[i] - position) - 1 <= halfStep) {
                        return round(that._values[i]);
                    }
                }
            },
            _getFormattedValue: function (val, drag) {
                var that = this, html = '', tooltip = that.options.tooltip, tooltipTemplate, selectionStart, selectionEnd;
                if (isArray(val)) {
                    selectionStart = val[0];
                    selectionEnd = val[1];
                } else if (drag && drag.type) {
                    selectionStart = drag.selectionStart;
                    selectionEnd = drag.selectionEnd;
                }
                if (drag) {
                    tooltipTemplate = drag.tooltipTemplate;
                }
                if (!tooltipTemplate && tooltip.template) {
                    tooltipTemplate = kendo.template(tooltip.template);
                }
                if (isArray(val) || drag && drag.type) {
                    if (tooltipTemplate) {
                        html = tooltipTemplate({
                            selectionStart: selectionStart,
                            selectionEnd: selectionEnd
                        });
                    } else {
                        selectionStart = format(tooltip.format, selectionStart);
                        selectionEnd = format(tooltip.format, selectionEnd);
                        html = selectionStart + ' - ' + selectionEnd;
                    }
                } else {
                    if (drag) {
                        drag.val = val;
                    }
                    if (tooltipTemplate) {
                        html = tooltipTemplate({ value: val });
                    } else {
                        html = format(tooltip.format, val);
                    }
                }
                return html;
            },
            _getDraggableArea: function () {
                var that = this, offset = kendo.getOffset(that._trackDiv);
                return {
                    startPoint: that._isHorizontal ? offset.left : offset.top + that._maxSelection,
                    endPoint: that._isHorizontal ? offset.left + that._maxSelection : offset.top
                };
            },
            _createHtml: function () {
                var that = this, element = that.element, options = that.options, inputs = element.find('input');
                if (inputs.length == 2) {
                    inputs.eq(0).prop('value', formatValue(options.selectionStart));
                    inputs.eq(1).prop('value', formatValue(options.selectionEnd));
                } else {
                    element.prop('value', formatValue(options.value));
                }
                element.wrap(createWrapper(options, element, that._isHorizontal)).hide();
                if (options.showButtons) {
                    element.before(createButton(options, 'increase', that._isHorizontal, that._isRtl)).before(createButton(options, 'decrease', that._isHorizontal, that._isRtl));
                }
                element.before(createTrack(options, element));
            },
            _focus: function (e) {
                var that = this, target = e.target, val = that.value(), drag = that._drag;
                if (!drag) {
                    if (target == that.wrapper.find(DRAG_HANDLE).eq(0)[0]) {
                        drag = that._firstHandleDrag;
                        that._activeHandle = 0;
                    } else {
                        drag = that._lastHandleDrag;
                        that._activeHandle = 1;
                    }
                    val = val[that._activeHandle];
                }
                $(target).addClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                if (drag) {
                    that._activeHandleDrag = drag;
                    drag.selectionStart = that.options.selectionStart;
                    drag.selectionEnd = that.options.selectionEnd;
                    drag._updateTooltip(val);
                }
            },
            _focusWithMouse: function (target) {
                target = $(target);
                var that = this, idx = target.is(DRAG_HANDLE) ? target.index() : 0;
                window.setTimeout(function () {
                    that.wrapper.find(DRAG_HANDLE)[idx == 2 ? 1 : 0].focus();
                }, 1);
                that._setTooltipTimeout();
            },
            _blur: function (e) {
                var that = this, drag = that._activeHandleDrag;
                $(e.target).removeClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                if (drag) {
                    drag._removeTooltip();
                    delete that._activeHandleDrag;
                    delete that._activeHandle;
                }
            },
            _setTooltipTimeout: function () {
                var that = this;
                that._tooltipTimeout = window.setTimeout(function () {
                    var drag = that._drag || that._activeHandleDrag;
                    if (drag) {
                        drag._removeTooltip();
                    }
                }, 300);
            },
            _clearTooltipTimeout: function () {
                var that = this;
                window.clearTimeout(this._tooltipTimeout);
                var drag = that._drag || that._activeHandleDrag;
                if (drag && drag.tooltipDiv) {
                    drag.tooltipDiv.stop(true, false).css('opacity', 1);
                }
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._form = form.on('reset', proxy(that._formResetHandler, that));
                }
            },
            min: function (value) {
                if (!value) {
                    return this.options.min;
                }
                this.setOptions({ 'min': value });
            },
            max: function (value) {
                if (!value) {
                    return this.options.max;
                }
                this.setOptions({ 'max': value });
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._sliderItemsInit();
                this._refresh();
            },
            destroy: function () {
                if (this._form) {
                    this._form.off('reset', this._formResetHandler);
                }
                Widget.fn.destroy.call(this);
            }
        });
        function createWrapper(options, element, isHorizontal) {
            var orientationCssClass = isHorizontal ? ' k-slider-horizontal' : ' k-slider-vertical', style = options.style ? options.style : element.attr('style'), cssClasses = element.attr('class') ? ' ' + element.attr('class') : '', tickPlacementCssClass = '';
            if (options.tickPlacement == 'bottomRight') {
                tickPlacementCssClass = ' k-slider-bottomright';
            } else if (options.tickPlacement == 'topLeft') {
                tickPlacementCssClass = ' k-slider-topleft';
            }
            style = style ? ' style=\'' + style + '\'' : '';
            return '<div class=\'k-widget k-slider' + orientationCssClass + cssClasses + '\'' + style + '>' + '<div class=\'k-slider-wrap' + (options.showButtons ? ' k-slider-buttons' : '') + tickPlacementCssClass + '\'></div></div>';
        }
        function createButton(options, type, isHorizontal, isRtl) {
            var buttonCssClass = '';
            if (isHorizontal) {
                if (!isRtl && type == 'increase' || isRtl && type != 'increase') {
                    buttonCssClass = 'k-i-arrow-60-right';
                } else {
                    buttonCssClass = 'k-i-arrow-60-left';
                }
            } else {
                if (type == 'increase') {
                    buttonCssClass = 'k-i-arrow-60-up';
                } else {
                    buttonCssClass = 'k-i-arrow-60-down';
                }
            }
            return '<a class=\'k-button k-button-' + type + '\' ' + 'title=\'' + options[type + 'ButtonTitle'] + '\' ' + 'aria-label=\'' + options[type + 'ButtonTitle'] + '\'>' + '<span class=\'k-icon ' + buttonCssClass + '\'></span></a>';
        }
        function createSliderItems(options, distance) {
            var result = '<ul class=\'k-reset k-slider-items\'>', count = math.floor(round(distance / options.smallStep)) + 1, i;
            for (i = 0; i < count; i++) {
                result += '<li class=\'k-tick\' role=\'presentation\'>&nbsp;</li>';
            }
            result += '</ul>';
            return result;
        }
        function createTrack(options, element) {
            var dragHandleCount = element.is('input') ? 1 : 2, firstDragHandleTitle = dragHandleCount == 2 ? options.leftDragHandleTitle : options.dragHandleTitle;
            return '<div class=\'k-slider-track\'><div class=\'k-slider-selection\'><!-- --></div>' + '<a href=\'#\' class=\'k-draghandle\' title=\'' + firstDragHandleTitle + '\' role=\'slider\' aria-valuemin=\'' + options.min + '\' aria-valuemax=\'' + options.max + '\' aria-valuenow=\'' + (dragHandleCount > 1 ? options.selectionStart || options.min : options.value || options.min) + '\'>Drag</a>' + (dragHandleCount > 1 ? '<a href=\'#\' class=\'k-draghandle\' title=\'' + options.rightDragHandleTitle + '\'role=\'slider\' aria-valuemin=\'' + options.min + '\' aria-valuemax=\'' + options.max + '\' aria-valuenow=\'' + (options.selectionEnd || options.max) + '\'>Drag</a>' : '') + '</div>';
        }
        function step(stepValue) {
            return function (value) {
                return value + stepValue;
            };
        }
        function setValue(value) {
            return function () {
                return value;
            };
        }
        function formatValue(value) {
            return (value + '').replace('.', kendo.cultures.current.numberFormat['.']);
        }
        function calculatePrecision(value) {
            var number = value.toString();
            var precision = 0;
            number = number.split('.');
            if (number[1]) {
                precision = number[1].length;
            }
            precision = precision > 10 ? 10 : precision;
            return precision;
        }
        function round(value) {
            var precision, power;
            value = parseFloat(value, 10);
            precision = calculatePrecision(value);
            power = math.pow(10, precision || 0);
            return math.round(value * power) / power;
        }
        function parseAttr(element, name) {
            var value = parse(element.getAttribute(name));
            if (value === null) {
                value = undefined;
            }
            return value;
        }
        function defined(value) {
            return typeof value !== UNDEFINED;
        }
        function removeFraction(value) {
            return value * 10000;
        }
        var Slider = SliderBase.extend({
            init: function (element, options) {
                var that = this, dragHandle;
                element.type = 'text';
                options = extend({}, {
                    value: parseAttr(element, 'value'),
                    min: parseAttr(element, 'min'),
                    max: parseAttr(element, 'max'),
                    smallStep: parseAttr(element, 'step')
                }, options);
                element = $(element);
                if (options && options.enabled === undefined) {
                    options.enabled = !element.is('[disabled]');
                }
                SliderBase.fn.init.call(that, element, options);
                options = that.options;
                if (!defined(options.value) || options.value === null) {
                    options.value = options.min;
                    element.prop('value', formatValue(options.min));
                }
                options.value = math.max(math.min(options.value, options.max), options.min);
                dragHandle = that.wrapper.find(DRAG_HANDLE);
                this._selection = new Slider.Selection(dragHandle, that, options);
                that._drag = new Slider.Drag(dragHandle, '', that, options);
            },
            options: {
                name: 'Slider',
                showButtons: true,
                increaseButtonTitle: 'Increase',
                decreaseButtonTitle: 'Decrease',
                dragHandleTitle: 'drag',
                tooltip: { format: '{0:#,#.##}' },
                value: null
            },
            enable: function (enable) {
                var that = this, options = that.options, clickHandler, move;
                that.disable();
                if (enable === false) {
                    return;
                }
                that.wrapper.removeClass(STATE_DISABLED).addClass(STATE_DEFAULT);
                that.wrapper.find('input').removeAttr(DISABLED);
                clickHandler = function (e) {
                    var touch = getTouches(e)[0];
                    if (!touch) {
                        return;
                    }
                    var mousePosition = that._isHorizontal ? touch.location.pageX : touch.location.pageY, dragableArea = that._getDraggableArea(), target = $(e.target);
                    if (target.hasClass('k-draghandle')) {
                        target.addClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                        return;
                    }
                    that._update(that._getValueFromPosition(mousePosition, dragableArea));
                    that._focusWithMouse(e.target);
                    that._drag.dragstart(e);
                    e.preventDefault();
                };
                that.wrapper.find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).on(TRACK_MOUSE_DOWN, clickHandler).end().on(TRACK_MOUSE_DOWN, function () {
                    $(document.documentElement).one('selectstart', kendo.preventDefault);
                }).on(TRACK_MOUSE_UP, function () {
                    that._drag._end();
                });
                that.wrapper.find(DRAG_HANDLE).attr(TABINDEX, 0).on(MOUSE_UP, function () {
                    that._setTooltipTimeout();
                }).on(CLICK, function (e) {
                    that._focusWithMouse(e.target);
                    e.preventDefault();
                }).on(FOCUS, proxy(that._focus, that)).on(BLUR, proxy(that._blur, that));
                move = proxy(function (sign) {
                    var newVal = that._nextValueByIndex(that._valueIndex + sign * 1);
                    that._setValueInRange(newVal);
                    that._drag._updateTooltip(newVal);
                }, that);
                if (options.showButtons) {
                    var mouseDownHandler = proxy(function (e, sign) {
                        this._clearTooltipTimeout();
                        if (e.which === 1 || support.touch && e.which === 0) {
                            move(sign);
                            this.timeout = setTimeout(proxy(function () {
                                this.timer = setInterval(function () {
                                    move(sign);
                                }, 60);
                            }, this), 200);
                        }
                    }, that);
                    that.wrapper.find('.k-button').on(MOUSE_UP, proxy(function (e) {
                        this._clearTimer();
                        that._focusWithMouse(e.target);
                    }, that)).on(MOUSE_OVER, function (e) {
                        $(e.currentTarget).addClass('k-state-hover');
                    }).on('mouseout' + NS, proxy(function (e) {
                        $(e.currentTarget).removeClass('k-state-hover');
                        this._clearTimer();
                    }, that)).eq(0).on(MOUSE_DOWN, proxy(function (e) {
                        mouseDownHandler(e, 1);
                    }, that)).click(false).end().eq(1).on(MOUSE_DOWN, proxy(function (e) {
                        mouseDownHandler(e, -1);
                    }, that)).click(kendo.preventDefault);
                }
                that.wrapper.find(DRAG_HANDLE).off(KEY_DOWN, false).on(KEY_DOWN, proxy(this._keydown, that));
                options.enabled = true;
            },
            disable: function () {
                var that = this;
                that.wrapper.removeClass(STATE_DEFAULT).addClass(STATE_DISABLED);
                $(that.element).prop(DISABLED, DISABLED);
                that.wrapper.find('.k-button').off(MOUSE_DOWN).on(MOUSE_DOWN, function (e) {
                    e.preventDefault();
                    $(this).addClass('k-state-active');
                }).off(MOUSE_UP).on(MOUSE_UP, function (e) {
                    e.preventDefault();
                    $(this).removeClass('k-state-active');
                }).off('mouseleave' + NS).on('mouseleave' + NS, kendo.preventDefault).off(MOUSE_OVER).on(MOUSE_OVER, kendo.preventDefault);
                that.wrapper.find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).off(TRACK_MOUSE_DOWN).off(TRACK_MOUSE_UP);
                that.wrapper.find(DRAG_HANDLE).attr(TABINDEX, -1).off(MOUSE_UP).off(KEY_DOWN).off(CLICK).off(FOCUS).off(BLUR);
                that.options.enabled = false;
            },
            _update: function (val) {
                var that = this, change = that.value() != val;
                that.value(val);
                if (change) {
                    that.trigger(CHANGE, { value: that.options.value });
                }
            },
            value: function (value) {
                var that = this, options = that.options;
                value = round(value);
                if (isNaN(value)) {
                    return options.value;
                }
                if (value >= options.min && value <= options.max) {
                    if (options.value != value) {
                        that.element.prop('value', formatValue(value));
                        options.value = value;
                        that._refreshAriaAttr(value);
                        that._refresh();
                    }
                }
            },
            _refresh: function () {
                this.trigger(MOVE_SELECTION, { value: this.options.value });
            },
            _refreshAriaAttr: function (value) {
                var that = this, drag = that._drag, formattedValue;
                if (drag && drag._tooltipDiv) {
                    formattedValue = drag._tooltipDiv.text();
                } else {
                    formattedValue = that._getFormattedValue(value, null);
                }
                this.wrapper.find(DRAG_HANDLE).attr('aria-valuenow', value).attr('aria-valuetext', formattedValue);
            },
            _clearTimer: function () {
                clearTimeout(this.timeout);
                clearInterval(this.timer);
            },
            _keydown: function (e) {
                var that = this;
                if (e.keyCode in that._keyMap) {
                    that._clearTooltipTimeout();
                    that._setValueInRange(that._keyMap[e.keyCode](that.options.value));
                    that._drag._updateTooltip(that.value());
                    e.preventDefault();
                }
            },
            _setValueInRange: function (val) {
                var that = this, options = that.options;
                val = round(val);
                if (isNaN(val)) {
                    that._update(options.min);
                    return;
                }
                val = math.max(math.min(val, options.max), options.min);
                that._update(val);
            },
            _nextValueByIndex: function (index) {
                var count = this._values.length;
                if (this._isRtl) {
                    index = count - 1 - index;
                }
                return this._values[math.max(0, math.min(index, count - 1))];
            },
            _formResetHandler: function () {
                var that = this, min = that.options.min;
                setTimeout(function () {
                    var value = that.element[0].value;
                    that.value(value === '' || isNaN(value) ? min : value);
                });
            },
            destroy: function () {
                var that = this;
                SliderBase.fn.destroy.call(that);
                that.wrapper.off(NS).find('.k-button').off(NS).end().find(DRAG_HANDLE).off(NS).end().find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).off(NS).end();
                that._drag.draggable.destroy();
                that._drag._removeTooltip(true);
            }
        });
        Slider.Selection = function (dragHandle, that, options) {
            function moveSelection(val) {
                var selectionValue = val - options.min, index = that._valueIndex = math.ceil(round(selectionValue / options.smallStep)), selection = parseInt(that._pixelSteps[index], 10), selectionDiv = that._trackDiv.find('.k-slider-selection'), halfDragHanndle = parseInt(that._outerSize(dragHandle) / 2, 10), rtlCorrection = that._isRtl ? 2 : 0;
                selectionDiv[that._sizeFn](that._isRtl ? that._maxSelection - selection : selection);
                dragHandle.css(that._position, selection - halfDragHanndle - rtlCorrection);
            }
            moveSelection(options.value);
            that.bind([
                SLIDE,
                MOVE_SELECTION
            ], function (e) {
                moveSelection(parseFloat(e.value, 10));
            });
            that.bind(CHANGE, function (e) {
                moveSelection(parseFloat(e.sender.value(), 10));
            });
        };
        Slider.Drag = function (element, type, owner, options) {
            var that = this;
            that.owner = owner;
            that.options = options;
            that.element = element;
            that.type = type;
            that.draggable = new Draggable(element, {
                distance: 0,
                dragstart: proxy(that._dragstart, that),
                drag: proxy(that.drag, that),
                dragend: proxy(that.dragend, that),
                dragcancel: proxy(that.dragcancel, that)
            });
            element.click(false);
            element.on('dragstart', function (e) {
                e.preventDefault();
            });
        };
        Slider.Drag.prototype = {
            dragstart: function (e) {
                this.owner._activeDragHandle = this;
                this.draggable.userEvents.cancel();
                this._dragstart(e);
                this.dragend();
            },
            _dragstart: function (e) {
                var that = this, owner = that.owner, options = that.options;
                if (!options.enabled) {
                    e.preventDefault();
                    return;
                }
                this.owner._activeDragHandle = this;
                owner.element.off(MOUSE_OVER);
                owner.wrapper.find('.' + STATE_FOCUSED).removeClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                that.element.addClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                $(document.documentElement).css('cursor', 'pointer');
                that.dragableArea = owner._getDraggableArea();
                that.step = math.max(options.smallStep * (owner._maxSelection / owner._distance()), 0);
                if (that.type) {
                    that.selectionStart = options.selectionStart;
                    that.selectionEnd = options.selectionEnd;
                    owner._setZIndex(that.type);
                } else {
                    that.oldVal = that.val = options.value;
                }
                that._removeTooltip(true);
                that._createTooltip();
            },
            _createTooltip: function () {
                var that = this, owner = that.owner, tooltip = that.options.tooltip, html = '', wnd = $(window), tooltipTemplate, colloutCssClass;
                if (!tooltip.enabled) {
                    return;
                }
                if (tooltip.template) {
                    tooltipTemplate = that.tooltipTemplate = kendo.template(tooltip.template);
                }
                $('.k-slider-tooltip').remove();
                that.tooltipDiv = $('<div class=\'k-widget k-tooltip k-slider-tooltip\'><!-- --></div>').appendTo(document.body);
                html = owner._getFormattedValue(that.val || owner.value(), that);
                if (!that.type) {
                    colloutCssClass = 'k-callout-' + (owner._isHorizontal ? 's' : 'e');
                    that.tooltipInnerDiv = '<div class=\'k-callout ' + colloutCssClass + '\'><!-- --></div>';
                    html += that.tooltipInnerDiv;
                }
                that.tooltipDiv.html(html);
                that._scrollOffset = {
                    top: wnd.scrollTop(),
                    left: wnd.scrollLeft()
                };
                that.moveTooltip();
            },
            drag: function (e) {
                var that = this, owner = that.owner, x = e.x.location, y = e.y.location, startPoint = that.dragableArea.startPoint, endPoint = that.dragableArea.endPoint, slideParams;
                e.preventDefault();
                if (owner._isHorizontal) {
                    if (owner._isRtl) {
                        that.val = that.constrainValue(x, startPoint, endPoint, x < endPoint);
                    } else {
                        that.val = that.constrainValue(x, startPoint, endPoint, x >= endPoint);
                    }
                } else {
                    that.val = that.constrainValue(y, endPoint, startPoint, y <= endPoint);
                }
                if (that.oldVal != that.val) {
                    that.oldVal = that.val;
                    if (that.type) {
                        if (that.type == 'firstHandle') {
                            if (that.val < that.selectionEnd) {
                                that.selectionStart = that.val;
                            } else {
                                that.selectionStart = that.selectionEnd = that.val;
                            }
                        } else {
                            if (that.val > that.selectionStart) {
                                that.selectionEnd = that.val;
                            } else {
                                that.selectionStart = that.selectionEnd = that.val;
                            }
                        }
                        slideParams = {
                            values: [
                                that.selectionStart,
                                that.selectionEnd
                            ],
                            value: [
                                that.selectionStart,
                                that.selectionEnd
                            ]
                        };
                    } else {
                        slideParams = { value: that.val };
                    }
                    owner.trigger(SLIDE, slideParams);
                }
                that._updateTooltip(that.val);
            },
            _updateTooltip: function (val) {
                var that = this, options = that.options, tooltip = options.tooltip, html = '';
                if (!tooltip.enabled) {
                    return;
                }
                if (!that.tooltipDiv) {
                    that._createTooltip();
                }
                html = that.owner._getFormattedValue(round(val), that);
                if (!that.type) {
                    html += that.tooltipInnerDiv;
                }
                that.tooltipDiv.html(html);
                that.moveTooltip();
            },
            dragcancel: function () {
                this.owner._refresh();
                $(document.documentElement).css('cursor', '');
                return this._end();
            },
            dragend: function () {
                var that = this, owner = that.owner;
                $(document.documentElement).css('cursor', '');
                if (that.type) {
                    owner._update(that.selectionStart, that.selectionEnd);
                } else {
                    owner._update(that.val);
                    that.draggable.userEvents._disposeAll();
                }
                that.draggable.userEvents.cancel();
                return that._end();
            },
            _end: function () {
                var that = this, owner = that.owner;
                owner._focusWithMouse(that.element);
                owner.element.on(MOUSE_OVER);
                return false;
            },
            _removeTooltip: function (noAnimation) {
                var that = this, owner = that.owner;
                if (that.tooltipDiv && owner.options.tooltip.enabled && owner.options.enabled) {
                    if (noAnimation) {
                        that.tooltipDiv.remove();
                        that.tooltipDiv = null;
                    } else {
                        that.tooltipDiv.fadeOut('slow', function () {
                            $(this).remove();
                            that.tooltipDiv = null;
                        });
                    }
                }
            },
            moveTooltip: function () {
                var that = this, owner = that.owner, top = 0, left = 0, element = that.element, offset = kendo.getOffset(element), margin = 8, viewport = $(window), callout = that.tooltipDiv.find('.k-callout'), width = outerWidth(that.tooltipDiv), height = outerHeight(that.tooltipDiv), dragHandles, sdhOffset, diff, anchorSize;
                if (that.type) {
                    dragHandles = owner.wrapper.find(DRAG_HANDLE);
                    offset = kendo.getOffset(dragHandles.eq(0));
                    sdhOffset = kendo.getOffset(dragHandles.eq(1));
                    if (owner._isHorizontal) {
                        top = sdhOffset.top;
                        left = offset.left + (sdhOffset.left - offset.left) / 2;
                    } else {
                        top = offset.top + (sdhOffset.top - offset.top) / 2;
                        left = sdhOffset.left;
                    }
                    anchorSize = outerWidth(dragHandles.eq(0)) + 2 * margin;
                } else {
                    top = offset.top;
                    left = offset.left;
                    anchorSize = outerWidth(element) + 2 * margin;
                }
                if (owner._isHorizontal) {
                    left -= parseInt((width - owner._outerSize(element)) / 2, 10);
                    top -= height + margin + (callout.length ? callout.height() : 0);
                } else {
                    top -= parseInt((height - owner._outerSize(element)) / 2, 10);
                    left -= width + margin + (callout.length ? callout.width() : 0);
                }
                if (owner._isHorizontal) {
                    diff = that._flip(top, height, anchorSize, outerHeight(viewport) + that._scrollOffset.top);
                    top += diff;
                    left += that._fit(left, width, outerWidth(viewport) + that._scrollOffset.left);
                } else {
                    diff = that._flip(left, width, anchorSize, outerWidth(viewport) + that._scrollOffset.left);
                    top += that._fit(top, height, outerHeight(viewport) + that._scrollOffset.top);
                    left += diff;
                }
                if (diff > 0 && callout) {
                    callout.removeClass();
                    callout.addClass('k-callout k-callout-' + (owner._isHorizontal ? 'n' : 'w'));
                }
                that.tooltipDiv.css({
                    top: top,
                    left: left
                });
            },
            _fit: function (position, size, viewPortEnd) {
                var output = 0;
                if (position + size > viewPortEnd) {
                    output = viewPortEnd - (position + size);
                }
                if (position < 0) {
                    output = -position;
                }
                return output;
            },
            _flip: function (offset, size, anchorSize, viewPortEnd) {
                var output = 0;
                if (offset + size > viewPortEnd) {
                    output += -(anchorSize + size);
                }
                if (offset + output < 0) {
                    output += anchorSize + size;
                }
                return output;
            },
            constrainValue: function (position, min, max, maxOverflow) {
                var that = this, val = 0;
                if (min < position && position < max) {
                    val = that.owner._getValueFromPosition(position, that.dragableArea);
                } else {
                    if (maxOverflow) {
                        val = that.options.max;
                    } else {
                        val = that.options.min;
                    }
                }
                return val;
            }
        };
        kendo.ui.plugin(Slider);
        var RangeSlider = SliderBase.extend({
            init: function (element, options) {
                var that = this, inputs = $(element).find('input'), firstInput = inputs.eq(0)[0], secondInput = inputs.eq(1)[0];
                firstInput.type = 'text';
                secondInput.type = 'text';
                if (options && options.showButtons) {
                    if (window.console) {
                        window.console.warn('showbuttons option is not supported for the range slider, ignoring');
                    }
                    options.showButtons = false;
                }
                options = extend({}, {
                    selectionStart: parseAttr(firstInput, 'value'),
                    min: parseAttr(firstInput, 'min'),
                    max: parseAttr(firstInput, 'max'),
                    smallStep: parseAttr(firstInput, 'step')
                }, {
                    selectionEnd: parseAttr(secondInput, 'value'),
                    min: parseAttr(secondInput, 'min'),
                    max: parseAttr(secondInput, 'max'),
                    smallStep: parseAttr(secondInput, 'step')
                }, options);
                if (options && options.enabled === undefined) {
                    options.enabled = !inputs.is('[disabled]');
                }
                SliderBase.fn.init.call(that, element, options);
                options = that.options;
                if (!defined(options.selectionStart) || options.selectionStart === null) {
                    options.selectionStart = options.min;
                    inputs.eq(0).prop('value', formatValue(options.min));
                }
                if (!defined(options.selectionEnd) || options.selectionEnd === null) {
                    options.selectionEnd = options.max;
                    inputs.eq(1).prop('value', formatValue(options.max));
                }
                var dragHandles = that.wrapper.find(DRAG_HANDLE);
                this._selection = new RangeSlider.Selection(dragHandles, that, options);
                that._firstHandleDrag = new Slider.Drag(dragHandles.eq(0), 'firstHandle', that, options);
                that._lastHandleDrag = new Slider.Drag(dragHandles.eq(1), 'lastHandle', that, options);
            },
            options: {
                name: 'RangeSlider',
                leftDragHandleTitle: 'drag',
                rightDragHandleTitle: 'drag',
                tooltip: { format: '{0:#,#.##}' },
                selectionStart: null,
                selectionEnd: null
            },
            enable: function (enable) {
                var that = this, options = that.options, clickHandler;
                that.disable();
                if (enable === false) {
                    return;
                }
                that.wrapper.removeClass(STATE_DISABLED).addClass(STATE_DEFAULT);
                that.wrapper.find('input').removeAttr(DISABLED);
                clickHandler = function (e) {
                    var touch = getTouches(e)[0];
                    if (!touch) {
                        return;
                    }
                    var mousePosition = that._isHorizontal ? touch.location.pageX : touch.location.pageY, dragableArea = that._getDraggableArea(), val = that._getValueFromPosition(mousePosition, dragableArea), target = $(e.target), from, to, drag;
                    if (target.hasClass('k-draghandle')) {
                        that.wrapper.find('.' + STATE_FOCUSED).removeClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                        target.addClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                        return;
                    }
                    if (val < options.selectionStart) {
                        from = val;
                        to = options.selectionEnd;
                        drag = that._firstHandleDrag;
                    } else if (val > that.selectionEnd) {
                        from = options.selectionStart;
                        to = val;
                        drag = that._lastHandleDrag;
                    } else {
                        if (val - options.selectionStart <= options.selectionEnd - val) {
                            from = val;
                            to = options.selectionEnd;
                            drag = that._firstHandleDrag;
                        } else {
                            from = options.selectionStart;
                            to = val;
                            drag = that._lastHandleDrag;
                        }
                    }
                    drag.dragstart(e);
                    that._setValueInRange(from, to);
                    that._focusWithMouse(drag.element);
                };
                that.wrapper.find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).on(TRACK_MOUSE_DOWN, clickHandler).end().on(TRACK_MOUSE_DOWN, function () {
                    $(document.documentElement).one('selectstart', kendo.preventDefault);
                }).on(TRACK_MOUSE_UP, function () {
                    if (that._activeDragHandle) {
                        that._activeDragHandle._end();
                    }
                });
                that.wrapper.find(DRAG_HANDLE).attr(TABINDEX, 0).on(MOUSE_UP, function () {
                    that._setTooltipTimeout();
                }).on(CLICK, function (e) {
                    that._focusWithMouse(e.target);
                    e.preventDefault();
                }).on(FOCUS, proxy(that._focus, that)).on(BLUR, proxy(that._blur, that));
                that.wrapper.find(DRAG_HANDLE).off(KEY_DOWN, kendo.preventDefault).eq(0).on(KEY_DOWN, proxy(function (e) {
                    this._keydown(e, 'firstHandle');
                }, that)).end().eq(1).on(KEY_DOWN, proxy(function (e) {
                    this._keydown(e, 'lastHandle');
                }, that));
                that.options.enabled = true;
            },
            disable: function () {
                var that = this;
                that.wrapper.removeClass(STATE_DEFAULT).addClass(STATE_DISABLED);
                that.wrapper.find('input').prop(DISABLED, DISABLED);
                that.wrapper.find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).off(TRACK_MOUSE_DOWN).off(TRACK_MOUSE_UP);
                that.wrapper.find(DRAG_HANDLE).attr(TABINDEX, -1).off(MOUSE_UP).off(KEY_DOWN).off(CLICK).off(FOCUS).off(BLUR);
                that.options.enabled = false;
            },
            _keydown: function (e, handle) {
                var that = this, selectionStartValue = that.options.selectionStart, selectionEndValue = that.options.selectionEnd, dragSelectionStart, dragSelectionEnd, activeHandleDrag;
                if (e.keyCode in that._keyMap) {
                    that._clearTooltipTimeout();
                    if (handle == 'firstHandle') {
                        activeHandleDrag = that._activeHandleDrag = that._firstHandleDrag;
                        selectionStartValue = that._keyMap[e.keyCode](selectionStartValue);
                        if (selectionStartValue > selectionEndValue) {
                            selectionEndValue = selectionStartValue;
                        }
                    } else {
                        activeHandleDrag = that._activeHandleDrag = that._lastHandleDrag;
                        selectionEndValue = that._keyMap[e.keyCode](selectionEndValue);
                        if (selectionStartValue > selectionEndValue) {
                            selectionStartValue = selectionEndValue;
                        }
                    }
                    that._setValueInRange(round(selectionStartValue), round(selectionEndValue));
                    dragSelectionStart = Math.max(selectionStartValue, that.options.selectionStart);
                    dragSelectionEnd = Math.min(selectionEndValue, that.options.selectionEnd);
                    activeHandleDrag.selectionEnd = Math.max(dragSelectionEnd, that.options.selectionStart);
                    activeHandleDrag.selectionStart = Math.min(dragSelectionStart, that.options.selectionEnd);
                    activeHandleDrag._updateTooltip(that.value()[that._activeHandle]);
                    e.preventDefault();
                }
            },
            _update: function (selectionStart, selectionEnd) {
                var that = this, values = that.value();
                var change = values[0] != selectionStart || values[1] != selectionEnd;
                that.value([
                    selectionStart,
                    selectionEnd
                ]);
                if (change) {
                    that.trigger(CHANGE, {
                        values: [
                            selectionStart,
                            selectionEnd
                        ],
                        value: [
                            selectionStart,
                            selectionEnd
                        ]
                    });
                }
            },
            value: function (value) {
                if (value && value.length) {
                    return this._value(value[0], value[1]);
                } else {
                    return this._value();
                }
            },
            _value: function (start, end) {
                var that = this, options = that.options, selectionStart = options.selectionStart, selectionEnd = options.selectionEnd;
                if (isNaN(start) && isNaN(end)) {
                    return [
                        selectionStart,
                        selectionEnd
                    ];
                } else {
                    start = round(start);
                    end = round(end);
                }
                if (start >= options.min && start <= options.max && end >= options.min && end <= options.max && start <= end) {
                    if (selectionStart != start || selectionEnd != end) {
                        that.element.find('input').eq(0).prop('value', formatValue(start)).end().eq(1).prop('value', formatValue(end));
                        options.selectionStart = start;
                        options.selectionEnd = end;
                        that._refresh();
                        that._refreshAriaAttr(start, end);
                    }
                }
            },
            values: function (start, end) {
                if (isArray(start)) {
                    return this._value(start[0], start[1]);
                } else {
                    return this._value(start, end);
                }
            },
            _refresh: function () {
                var that = this, options = that.options;
                that.trigger(MOVE_SELECTION, {
                    values: [
                        options.selectionStart,
                        options.selectionEnd
                    ],
                    value: [
                        options.selectionStart,
                        options.selectionEnd
                    ]
                });
                if (options.selectionStart == options.max && options.selectionEnd == options.max) {
                    that._setZIndex('firstHandle');
                }
            },
            _refreshAriaAttr: function (start, end) {
                var that = this, dragHandles = that.wrapper.find(DRAG_HANDLE), drag = that._activeHandleDrag, formattedValue;
                formattedValue = that._getFormattedValue([
                    start,
                    end
                ], drag);
                dragHandles.eq(0).attr('aria-valuenow', start);
                dragHandles.eq(1).attr('aria-valuenow', end);
                dragHandles.attr('aria-valuetext', formattedValue);
            },
            _setValueInRange: function (selectionStart, selectionEnd) {
                var options = this.options;
                selectionStart = math.max(math.min(selectionStart, options.max), options.min);
                selectionEnd = math.max(math.min(selectionEnd, options.max), options.min);
                if (selectionStart == options.max && selectionEnd == options.max) {
                    this._setZIndex('firstHandle');
                }
                this._update(math.min(selectionStart, selectionEnd), math.max(selectionStart, selectionEnd));
            },
            _setZIndex: function (type) {
                this.wrapper.find(DRAG_HANDLE).each(function (index) {
                    $(this).css('z-index', type == 'firstHandle' ? 1 - index : index);
                });
            },
            _formResetHandler: function () {
                var that = this, options = that.options;
                setTimeout(function () {
                    var inputs = that.element.find('input');
                    var start = inputs[0].value;
                    var end = inputs[1].value;
                    that.values(start === '' || isNaN(start) ? options.min : start, end === '' || isNaN(end) ? options.max : end);
                });
            },
            destroy: function () {
                var that = this;
                SliderBase.fn.destroy.call(that);
                that.wrapper.off(NS).find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).off(NS).end().find(DRAG_HANDLE).off(NS);
                that._firstHandleDrag.draggable.destroy();
                that._lastHandleDrag.draggable.destroy();
            }
        });
        RangeSlider.Selection = function (dragHandles, that, options) {
            function moveSelection(value) {
                value = value || [];
                var selectionStartValue = value[0] - options.min, selectionEndValue = value[1] - options.min, selectionStartIndex = math.ceil(round(selectionStartValue / options.smallStep)), selectionEndIndex = math.ceil(round(selectionEndValue / options.smallStep)), selectionStart = that._pixelSteps[selectionStartIndex], selectionEnd = that._pixelSteps[selectionEndIndex], halfHandle = parseInt(that._outerSize(dragHandles.eq(0)) / 2, 10), rtlCorrection = that._isRtl ? 2 : 0;
                dragHandles.eq(0).css(that._position, selectionStart - halfHandle - rtlCorrection).end().eq(1).css(that._position, selectionEnd - halfHandle - rtlCorrection);
                makeSelection(selectionStart, selectionEnd);
            }
            function makeSelection(selectionStart, selectionEnd) {
                var selection, selectionPosition, selectionDiv = that._trackDiv.find('.k-slider-selection');
                selection = math.abs(selectionStart - selectionEnd);
                selectionDiv[that._sizeFn](selection);
                if (that._isRtl) {
                    selectionPosition = math.max(selectionStart, selectionEnd);
                    selectionDiv.css('right', that._maxSelection - selectionPosition - 1);
                } else {
                    selectionPosition = math.min(selectionStart, selectionEnd);
                    selectionDiv.css(that._position, selectionPosition - 1);
                }
            }
            moveSelection(that.value());
            that.bind([
                CHANGE,
                SLIDE,
                MOVE_SELECTION
            ], function (e) {
                moveSelection(e.values);
            });
        };
        kendo.ui.plugin(RangeSlider);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.colorpicker', [
        'kendo.core',
        'kendo.color',
        'kendo.popup',
        'kendo.slider',
        'kendo.userevents',
        'kendo.button'
    ], f);
}(function () {
    var __meta__ = {
        id: 'colorpicker',
        name: 'Color tools',
        category: 'web',
        description: 'Color selection widgets',
        depends: [
            'core',
            'color',
            'popup',
            'slider',
            'userevents',
            'button'
        ]
    };
    (function ($, parseInt, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, parseColor = kendo.parseColor, Color = kendo.Color, KEYS = kendo.keys, BACKGROUNDCOLOR = 'background-color', ITEMSELECTEDCLASS = 'k-state-selected', SIMPLEPALETTE = '000000,7f7f7f,880015,ed1c24,ff7f27,fff200,22b14c,00a2e8,3f48cc,a349a4,ffffff,c3c3c3,b97a57,ffaec9,ffc90e,efe4b0,b5e61d,99d9ea,7092be,c8bfe7', WEBPALETTE = 'FFFFFF,FFCCFF,FF99FF,FF66FF,FF33FF,FF00FF,CCFFFF,CCCCFF,CC99FF,CC66FF,CC33FF,CC00FF,99FFFF,99CCFF,9999FF,9966FF,9933FF,9900FF,FFFFCC,FFCCCC,FF99CC,FF66CC,FF33CC,FF00CC,CCFFCC,CCCCCC,CC99CC,CC66CC,CC33CC,CC00CC,99FFCC,99CCCC,9999CC,9966CC,9933CC,9900CC,FFFF99,FFCC99,FF9999,FF6699,FF3399,FF0099,CCFF99,CCCC99,CC9999,CC6699,CC3399,CC0099,99FF99,99CC99,999999,996699,993399,990099,FFFF66,FFCC66,FF9966,FF6666,FF3366,FF0066,CCFF66,CCCC66,CC9966,CC6666,CC3366,CC0066,99FF66,99CC66,999966,996666,993366,990066,FFFF33,FFCC33,FF9933,FF6633,FF3333,FF0033,CCFF33,CCCC33,CC9933,CC6633,CC3333,CC0033,99FF33,99CC33,999933,996633,993333,990033,FFFF00,FFCC00,FF9900,FF6600,FF3300,FF0000,CCFF00,CCCC00,CC9900,CC6600,CC3300,CC0000,99FF00,99CC00,999900,996600,993300,990000,66FFFF,66CCFF,6699FF,6666FF,6633FF,6600FF,33FFFF,33CCFF,3399FF,3366FF,3333FF,3300FF,00FFFF,00CCFF,0099FF,0066FF,0033FF,0000FF,66FFCC,66CCCC,6699CC,6666CC,6633CC,6600CC,33FFCC,33CCCC,3399CC,3366CC,3333CC,3300CC,00FFCC,00CCCC,0099CC,0066CC,0033CC,0000CC,66FF99,66CC99,669999,666699,663399,660099,33FF99,33CC99,339999,336699,333399,330099,00FF99,00CC99,009999,006699,003399,000099,66FF66,66CC66,669966,666666,663366,660066,33FF66,33CC66,339966,336666,333366,330066,00FF66,00CC66,009966,006666,003366,000066,66FF33,66CC33,669933,666633,663333,660033,33FF33,33CC33,339933,336633,333333,330033,00FF33,00CC33,009933,006633,003333,000033,66FF00,66CC00,669900,666600,663300,660000,33FF00,33CC00,339900,336600,333300,330000,00FF00,00CC00,009900,006600,003300,000000', WHITE = '#ffffff', MESSAGES = {
                apply: 'Apply',
                cancel: 'Cancel',
                noColor: 'no color',
                clearColor: 'Clear color',
                previewInput: 'Color Hexadecimal Code'
            }, NS = '.kendoColorTools', CLICK_NS = 'click' + NS, KEYDOWN_NS = 'keydown' + NS, browser = kendo.support.browser, isIE8 = browser.msie && browser.version < 9;
        var ColorSelector = Widget.extend({
            init: function (element, options) {
                var that = this, ariaId;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                that._value = options.value = parseColor(options.value);
                that._tabIndex = element.attr('tabIndex') || 0;
                ariaId = that._ariaId = options.ariaId;
                if (ariaId) {
                    element.attr('aria-labelledby', ariaId);
                }
                if (options._standalone) {
                    that._triggerSelect = that._triggerChange;
                }
            },
            options: {
                name: 'ColorSelector',
                value: null,
                _standalone: true
            },
            events: [
                'change',
                'select',
                'cancel'
            ],
            color: function (value) {
                if (value !== undefined) {
                    this._value = parseColor(value);
                    this._updateUI(this._value);
                }
                return this._value;
            },
            value: function (color) {
                color = this.color(color);
                if (color) {
                    if (this.options.opacity) {
                        color = color.toCssRgba();
                    } else {
                        color = color.toCss();
                    }
                }
                return color || null;
            },
            enable: function (enable) {
                if (arguments.length === 0) {
                    enable = true;
                }
                $('.k-disabled-overlay', this.wrapper).remove();
                if (!enable) {
                    this.wrapper.append('<div class=\'k-disabled-overlay\'></div>');
                }
                this._onEnable(enable);
            },
            _select: function (color, nohooks) {
                var prev = this._value;
                color = this.color(color);
                if (!nohooks) {
                    this.element.trigger('change');
                    if (!color.equals(prev)) {
                        this.trigger('change', { value: this.value() });
                    } else if (!this._standalone) {
                        this.trigger('cancel');
                    }
                }
            },
            _triggerSelect: function (color) {
                triggerEvent(this, 'select', color);
            },
            _triggerChange: function (color) {
                triggerEvent(this, 'change', color);
            },
            destroy: function () {
                if (this.element) {
                    this.element.off(NS);
                }
                if (this.wrapper) {
                    this.wrapper.off(NS).find('*').off(NS);
                }
                this.wrapper = null;
                Widget.fn.destroy.call(this);
            },
            _updateUI: $.noop,
            _selectOnHide: function () {
                return null;
            },
            _cancel: function () {
                this.trigger('cancel');
            }
        });
        function triggerEvent(self, type, color) {
            color = parseColor(color);
            if (color && !color.equals(self.color())) {
                if (type == 'change') {
                    self._value = color;
                }
                if (color.a != 1) {
                    color = color.toCssRgba();
                } else {
                    color = color.toCss();
                }
                self.trigger(type, { value: color });
            }
        }
        var ColorPalette = ColorSelector.extend({
            init: function (element, options) {
                var that = this;
                ColorSelector.fn.init.call(that, element, options);
                element = that.wrapper = that.element;
                options = that.options;
                var colors = options.palette;
                if (colors == 'websafe') {
                    colors = WEBPALETTE;
                    options.columns = 18;
                } else if (colors == 'basic') {
                    colors = SIMPLEPALETTE;
                }
                if (typeof colors == 'string') {
                    colors = colors.split(',');
                }
                if ($.isArray(colors)) {
                    colors = $.map(colors, function (x) {
                        return parseColor(x);
                    });
                }
                that._selectedID = (options.ariaId || kendo.guid()) + '_selected';
                element.addClass('k-widget k-colorpalette').attr('role', 'grid').attr('aria-readonly', 'true').append($(that._template({
                    colors: colors,
                    columns: options.columns,
                    tileSize: options.tileSize,
                    value: that._value,
                    id: options.ariaId
                }))).on(CLICK_NS, '.k-item', function (ev) {
                    that._select($(ev.currentTarget).css(BACKGROUNDCOLOR));
                }).attr('tabIndex', that._tabIndex).on(KEYDOWN_NS, bind(that._keydown, that));
                var tileSize = options.tileSize, width, height;
                if (tileSize) {
                    if (/number|string/.test(typeof tileSize)) {
                        width = height = parseFloat(tileSize);
                    } else if (typeof tileSize == 'object') {
                        width = parseFloat(tileSize.width);
                        height = parseFloat(tileSize.height);
                    } else {
                        throw new Error('Unsupported value for the \'tileSize\' argument');
                    }
                    element.find('.k-item').css({
                        width: width,
                        height: height
                    });
                }
            },
            focus: function () {
                if (this.wrapper && !this.wrapper.is('[unselectable=\'on\']')) {
                    this.wrapper.focus();
                }
            },
            options: {
                name: 'ColorPalette',
                columns: 10,
                tileSize: null,
                palette: 'basic'
            },
            _onEnable: function (enable) {
                if (enable) {
                    this.wrapper.attr('tabIndex', this._tabIndex);
                } else {
                    this.wrapper.removeAttr('tabIndex');
                }
            },
            _keydown: function (e) {
                var selected, wrapper = this.wrapper, items = wrapper.find('.k-item'), current = items.filter('.' + ITEMSELECTEDCLASS).get(0), keyCode = e.keyCode;
                if (keyCode == KEYS.LEFT) {
                    selected = relative(items, current, -1);
                } else if (keyCode == KEYS.RIGHT) {
                    selected = relative(items, current, 1);
                } else if (keyCode == KEYS.DOWN) {
                    selected = relative(items, current, this.options.columns);
                } else if (keyCode == KEYS.UP) {
                    selected = relative(items, current, -this.options.columns);
                } else if (keyCode == KEYS.ENTER) {
                    preventDefault(e);
                    if (current) {
                        this._select($(current).css(BACKGROUNDCOLOR));
                    }
                } else if (keyCode == KEYS.ESC) {
                    this._cancel();
                }
                if (selected) {
                    preventDefault(e);
                    this._current(selected);
                    try {
                        var color = parseColor(selected.css(BACKGROUNDCOLOR));
                        this._triggerSelect(color);
                    } catch (ex) {
                    }
                }
            },
            _current: function (item) {
                this.wrapper.find('.' + ITEMSELECTEDCLASS).removeClass(ITEMSELECTEDCLASS).attr('aria-selected', false).removeAttr('id');
                $(item).addClass(ITEMSELECTEDCLASS).attr('aria-selected', true).attr('id', this._selectedID);
                this.element.removeAttr('aria-activedescendant').attr('aria-activedescendant', this._selectedID);
            },
            _updateUI: function (color) {
                var item = null;
                this.wrapper.find('.k-item').each(function () {
                    var c = parseColor($(this).css(BACKGROUNDCOLOR));
                    if (c && c.equals(color)) {
                        item = this;
                        return false;
                    }
                });
                this._current(item);
            },
            _template: kendo.template('<table class="k-palette k-reset" role="presentation"><tr role="row">' + '# for (var i = 0; i < colors.length; ++i) { #' + '# var selected = colors[i].equals(value); #' + '# if (i && i % columns == 0) { # </tr><tr role="row"> # } #' + '<td role="gridcell" unselectable="on" style="background-color:#= colors[i].toCss() #"' + '#= selected ? " aria-selected=true" : "" # ' + '#=(id && i === 0) ? "id=\\""+id+"\\" " : "" # ' + 'class="k-item#= selected ? " ' + ITEMSELECTEDCLASS + '" : "" #" ' + 'aria-label="#= colors[i].toCss() #"></td>' + '# } #' + '</tr></table>')
        });
        var FlatColorPicker = ColorSelector.extend({
            init: function (element, options) {
                var that = this;
                ColorSelector.fn.init.call(that, element, options);
                options = that.options;
                options.messages = options.options ? $.extend(that.options.messages, options.options.messages) : that.options.messages;
                element = that.element;
                that.wrapper = element.addClass('k-widget k-flatcolorpicker').append(that._template(options));
                that._hueElements = $('.k-hsv-rectangle, .k-transparency-slider .k-slider-track', element);
                that._selectedColor = $('.k-selected-color-display', element);
                that._colorAsText = $('input.k-color-value', element);
                that._sliders();
                that._hsvArea();
                that._updateUI(that._value || parseColor('#f00'));
                element.find('input.k-color-value').on(KEYDOWN_NS, function (ev) {
                    var input = this;
                    if (ev.keyCode == KEYS.ENTER) {
                        try {
                            var color = parseColor(input.value);
                            var val = that.color();
                            that._select(color, color.equals(val));
                        } catch (ex) {
                            $(input).addClass('k-state-error');
                        }
                    } else if (that.options.autoupdate) {
                        setTimeout(function () {
                            var color = parseColor(input.value, true);
                            if (color) {
                                that._updateUI(color, true);
                            }
                        }, 10);
                    }
                }).end().on(CLICK_NS, '.k-controls button.apply', function () {
                    if (that.options._clearedColor) {
                        that.trigger('change');
                    } else {
                        that._select(that._getHSV());
                    }
                }).on(CLICK_NS, '.k-controls button.cancel', function () {
                    that._updateUI(that.color());
                    that._cancel();
                });
                if (isIE8) {
                    that._applyIEFilter();
                }
            },
            destroy: function () {
                this._hueSlider.destroy();
                if (this._opacitySlider) {
                    this._opacitySlider.destroy();
                }
                this._hueSlider = this._opacitySlider = this._hsvRect = this._hsvHandle = this._hueElements = this._selectedColor = this._colorAsText = null;
                ColorSelector.fn.destroy.call(this);
            },
            options: {
                name: 'FlatColorPicker',
                opacity: false,
                buttons: false,
                input: true,
                preview: true,
                clearButton: false,
                autoupdate: true,
                messages: MESSAGES
            },
            _applyIEFilter: function () {
                var track = this.element.find('.k-hue-slider .k-slider-track')[0], url = track.currentStyle.backgroundImage;
                url = url.replace(/^url\([\'\"]?|[\'\"]?\)$/g, '');
                track.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + url + '\', sizingMethod=\'scale\')';
            },
            _sliders: function () {
                var that = this, element = that.element, hueSlider = element.find('.k-hue-slider'), opacitySlider = element.find('.k-transparency-slider');
                function hueChange(e) {
                    that._updateUI(that._getHSV(e.value, null, null, null));
                }
                hueSlider.attr('aria-label', 'hue saturation');
                that._hueSlider = hueSlider.kendoSlider({
                    min: 0,
                    max: 360,
                    tickPlacement: 'none',
                    showButtons: false,
                    slide: hueChange,
                    change: hueChange
                }).data('kendoSlider');
                function opacityChange(e) {
                    that._updateUI(that._getHSV(null, null, null, e.value / 100));
                }
                opacitySlider.attr('aria-label', 'opacity');
                that._opacitySlider = opacitySlider.kendoSlider({
                    min: 0,
                    max: 100,
                    tickPlacement: 'none',
                    showButtons: false,
                    slide: opacityChange,
                    change: opacityChange
                }).data('kendoSlider');
            },
            _hsvArea: function () {
                var that = this, element = that.element, hsvRect = element.find('.k-hsv-rectangle'), hsvHandle = hsvRect.find('.k-draghandle').attr('tabIndex', 0).on(KEYDOWN_NS, bind(that._keydown, that));
                function update(x, y) {
                    var offset = this.offset, dx = x - offset.left, dy = y - offset.top, rw = this.width, rh = this.height;
                    dx = dx < 0 ? 0 : dx > rw ? rw : dx;
                    dy = dy < 0 ? 0 : dy > rh ? rh : dy;
                    that._svChange(dx / rw, 1 - dy / rh);
                }
                that._hsvEvents = new kendo.UserEvents(hsvRect, {
                    global: true,
                    press: function (e) {
                        this.offset = kendo.getOffset(hsvRect);
                        this.width = hsvRect.width();
                        this.height = hsvRect.height();
                        hsvHandle.focus();
                        update.call(this, e.x.location, e.y.location);
                    },
                    start: function () {
                        hsvRect.addClass('k-dragging');
                        hsvHandle.focus();
                    },
                    move: function (e) {
                        e.preventDefault();
                        update.call(this, e.x.location, e.y.location);
                    },
                    end: function () {
                        hsvRect.removeClass('k-dragging');
                    }
                });
                that._hsvRect = hsvRect;
                that._hsvHandle = hsvHandle;
            },
            _onEnable: function (enable) {
                this._hueSlider.enable(enable);
                if (this._opacitySlider) {
                    this._opacitySlider.enable(enable);
                }
                this.wrapper.find('input').attr('disabled', !enable);
                var handle = this._hsvRect.find('.k-draghandle');
                if (enable) {
                    handle.attr('tabIndex', this._tabIndex);
                } else {
                    handle.removeAttr('tabIndex');
                }
            },
            _keydown: function (ev) {
                var that = this;
                function move(prop, d) {
                    var c = that._getHSV();
                    c[prop] += d * (ev.shiftKey ? 0.01 : 0.05);
                    if (c[prop] < 0) {
                        c[prop] = 0;
                    }
                    if (c[prop] > 1) {
                        c[prop] = 1;
                    }
                    that._updateUI(c);
                    preventDefault(ev);
                }
                function hue(d) {
                    var c = that._getHSV();
                    c.h += d * (ev.shiftKey ? 1 : 5);
                    if (c.h < 0) {
                        c.h = 0;
                    }
                    if (c.h > 359) {
                        c.h = 359;
                    }
                    that._updateUI(c);
                    preventDefault(ev);
                }
                switch (ev.keyCode) {
                case KEYS.LEFT:
                    if (ev.ctrlKey) {
                        hue(-1);
                    } else {
                        move('s', -1);
                    }
                    break;
                case KEYS.RIGHT:
                    if (ev.ctrlKey) {
                        hue(1);
                    } else {
                        move('s', 1);
                    }
                    break;
                case KEYS.UP:
                    move(ev.ctrlKey && that._opacitySlider ? 'a' : 'v', 1);
                    break;
                case KEYS.DOWN:
                    move(ev.ctrlKey && that._opacitySlider ? 'a' : 'v', -1);
                    break;
                case KEYS.ENTER:
                    that._select(that._getHSV());
                    break;
                case KEYS.F2:
                    that.wrapper.find('input.k-color-value').focus().select();
                    break;
                case KEYS.ESC:
                    that._cancel();
                    break;
                }
            },
            focus: function () {
                this._hsvHandle.focus();
            },
            _getHSV: function (h, s, v, a) {
                var rect = this._hsvRect, width = rect.width(), height = rect.height(), handlePosition = this._hsvHandle.position();
                if (h == null) {
                    h = this._hueSlider.value();
                }
                if (s == null) {
                    s = handlePosition.left / width;
                }
                if (v == null) {
                    v = 1 - handlePosition.top / height;
                }
                if (a == null) {
                    a = this._opacitySlider ? this._opacitySlider.value() / 100 : 1;
                }
                return Color.fromHSV(h, s, v, a);
            },
            _svChange: function (s, v) {
                var color = this._getHSV(null, s, v, null);
                this._updateUI(color);
            },
            _updateUI: function (color, dontChangeInput) {
                var that = this, rect = that._hsvRect;
                if (!color) {
                    return;
                }
                this._colorAsText.attr('title', that.options.messages.previewInput);
                this._colorAsText.removeClass('k-state-error');
                that._selectedColor.css(BACKGROUNDCOLOR, color.toDisplay());
                if (!dontChangeInput) {
                    that._colorAsText.val(that._opacitySlider ? color.toCssRgba() : color.toCss());
                }
                that._triggerSelect(color);
                color = color.toHSV();
                that._hsvHandle.css({
                    left: color.s * rect.width() + 'px',
                    top: (1 - color.v) * rect.height() + 'px'
                });
                that._hueElements.css(BACKGROUNDCOLOR, Color.fromHSV(color.h, 1, 1, 1).toCss());
                that._hueSlider.value(color.h);
                if (that._opacitySlider) {
                    that._opacitySlider.value(100 * color.a);
                }
            },
            _selectOnHide: function () {
                return this.options.buttons ? null : this._getHSV();
            },
            _template: kendo.template('# if (preview) { #' + '<div class="k-selected-color"><div class="k-selected-color-display"><div class="k-color-input"><input class="k-color-value" ' + '# if (clearButton && !_standalone) { #' + 'placeholder="#: messages.noColor #" ' + '# } #' + '#= !data.input ? \'style="visibility: hidden;"\' : "" #>' + '# if (clearButton && !_standalone) { #' + '<span class="k-clear-color k-button k-bare" title="#: messages.clearColor #"></span>' + '# } #' + '</div></div></div>' + '# } #' + '# if (clearButton && !_standalone && !preview) { #' + '<div class="k-clear-color-container"><span class="k-clear-color k-button k-bare">#: messages.clearColor #</span></div>' + '# } #' + '<div class="k-hsv-rectangle"><div class="k-hsv-gradient"></div><div class="k-draghandle"></div></div>' + '<input class="k-hue-slider" />' + '# if (opacity) { #' + '<input class="k-transparency-slider" />' + '# } #' + '# if (buttons) { #' + '<div unselectable="on" class="k-controls"><button class="k-button k-primary apply">#: messages.apply #</button> <button class="k-button cancel">#: messages.cancel #</button></div>' + '# } #')
        });
        function relative(array, element, delta) {
            array = Array.prototype.slice.call(array);
            var n = array.length;
            var pos = array.indexOf(element);
            if (pos < 0) {
                return delta < 0 ? array[n - 1] : array[0];
            }
            pos += delta;
            if (pos < 0) {
                pos += n;
            } else {
                pos %= n;
            }
            return array[pos];
        }
        var ColorPicker = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element;
                var value = element.attr('value') || element.val();
                if (value) {
                    value = parseColor(value, true);
                } else {
                    value = parseColor(options.value, true);
                }
                that._value = options.value = value;
                var content = that.wrapper = $(that._template(options));
                element.hide().after(content);
                if (element.is('input')) {
                    element.appendTo(content);
                    var label = element.closest('label');
                    var id = element.attr('id');
                    if (id) {
                        label = label.add('label[for="' + id + '"]');
                    }
                    label.click(function (ev) {
                        that.open();
                        ev.preventDefault();
                    });
                }
                that._tabIndex = element.attr('tabIndex') || 0;
                that.enable(!element.attr('disabled'));
                var accesskey = element.attr('accesskey');
                if (accesskey) {
                    element.attr('accesskey', null);
                    content.attr('accesskey', accesskey);
                }
                that.bind('activate', function (ev) {
                    if (!ev.isDefaultPrevented()) {
                        that.toggle();
                    }
                });
                that._updateUI(value);
            },
            destroy: function () {
                this.wrapper.off(NS).find('*').off(NS);
                if (this._popup) {
                    this._selector.destroy();
                    this._popup.destroy();
                }
                this._selector = this._popup = this.wrapper = null;
                Widget.fn.destroy.call(this);
            },
            enable: function (enable) {
                var that = this, wrapper = that.wrapper, innerWrapper = wrapper.children('.k-picker-wrap'), arrow = innerWrapper.find('.k-select');
                if (arguments.length === 0) {
                    enable = true;
                }
                that.element.attr('disabled', !enable);
                wrapper.attr('aria-disabled', !enable);
                arrow.off(NS).on('mousedown' + NS, preventDefault);
                wrapper.addClass('k-state-disabled').removeAttr('tabIndex').add('*', wrapper).off(NS);
                if (enable) {
                    wrapper.removeClass('k-state-disabled').attr('tabIndex', that._tabIndex).on('mouseenter' + NS, function () {
                        innerWrapper.addClass('k-state-hover');
                    }).on('mouseleave' + NS, function () {
                        innerWrapper.removeClass('k-state-hover');
                    }).on('focus' + NS, function () {
                        innerWrapper.addClass('k-state-focused');
                    }).on('blur' + NS, function () {
                        innerWrapper.removeClass('k-state-focused');
                    }).on(KEYDOWN_NS, bind(that._keydown, that)).on(CLICK_NS, '.k-select', bind(that.toggle, that)).on(CLICK_NS, that.options.toolIcon ? '.k-tool-icon' : '.k-selected-color', function () {
                        that.trigger('activate');
                    });
                } else {
                    that.close();
                }
            },
            _template: kendo.template('<span role="textbox" aria-haspopup="true" class="k-widget k-colorpicker">' + '<span class="k-picker-wrap k-state-default">' + '# if (toolIcon) { #' + '<span class="k-icon k-tool-icon #= toolIcon #">' + '<span class="k-selected-color"></span>' + '</span>' + '# } else { #' + '<span class="k-selected-color"><span class="k-icon k-i-line" style="display: none;"></span></span>' + '# } #' + '<span class="k-select" unselectable="on" aria-label="select">' + '<span class="k-icon k-i-arrow-60-down"></span>' + '</span>' + '</span>' + '</span>'),
            options: {
                name: 'ColorPicker',
                palette: null,
                columns: 10,
                toolIcon: null,
                value: null,
                messages: MESSAGES,
                opacity: false,
                buttons: true,
                preview: true,
                clearButton: false,
                ARIATemplate: 'Current selected color is #=data || ""#'
            },
            events: [
                'activate',
                'change',
                'select',
                'open',
                'close'
            ],
            open: function () {
                if (!this.element.prop('disabled')) {
                    this._getPopup().open();
                }
            },
            close: function () {
                var selOptions = this._selector && this._selector.options || {};
                selOptions._closing = true;
                this._getPopup().close();
                delete selOptions._closing;
            },
            toggle: function () {
                if (!this.element.prop('disabled')) {
                    this._getPopup().toggle();
                }
            },
            _noColorIcon: function () {
                return this.wrapper.find('.k-picker-wrap > .k-selected-color > .k-icon.k-i-line');
            },
            color: ColorSelector.fn.color,
            value: ColorSelector.fn.value,
            _select: ColorSelector.fn._select,
            _triggerSelect: ColorSelector.fn._triggerSelect,
            _isInputTypeColor: function () {
                var el = this.element[0];
                return /^input$/i.test(el.tagName) && /^color$/i.test(el.type);
            },
            _updateUI: function (value) {
                var formattedValue = '';
                if (value) {
                    if (this._isInputTypeColor() || value.a == 1) {
                        formattedValue = value.toCss();
                    } else {
                        formattedValue = value.toCssRgba();
                    }
                    this.element.val(formattedValue);
                }
                if (!this._ariaTemplate) {
                    this._ariaTemplate = kendo.template(this.options.ARIATemplate);
                }
                this.wrapper.attr('aria-label', this._ariaTemplate(formattedValue));
                this._triggerSelect(value);
                this.wrapper.find('.k-selected-color').css(BACKGROUNDCOLOR, value ? value.toDisplay() : WHITE);
                this._noColorIcon()[formattedValue ? 'hide' : 'show']();
            },
            _keydown: function (ev) {
                var key = ev.keyCode;
                if (this._getPopup().visible()) {
                    if (key == KEYS.ESC) {
                        this._selector._cancel();
                    } else {
                        this._selector._keydown(ev);
                    }
                    preventDefault(ev);
                } else if (key == KEYS.ENTER || key == KEYS.DOWN) {
                    this.open();
                    preventDefault(ev);
                }
            },
            _getPopup: function () {
                var that = this, popup = that._popup;
                if (!popup) {
                    var options = that.options;
                    var selectorType;
                    if (options.palette) {
                        selectorType = ColorPalette;
                    } else {
                        selectorType = FlatColorPicker;
                    }
                    options._standalone = false;
                    delete options.select;
                    delete options.change;
                    delete options.cancel;
                    var id = kendo.guid();
                    var selector = that._selector = new selectorType($('<div id="' + id + '"/>').appendTo(document.body), options);
                    that.wrapper.attr('aria-owns', id);
                    that._popup = popup = selector.wrapper.kendoPopup({
                        anchor: that.wrapper,
                        adjustSize: {
                            width: 5,
                            height: 0
                        }
                    }).data('kendoPopup');
                    selector.element.find('.k-clear-color').kendoButton({
                        icon: 'reset-color',
                        click: function (e) {
                            selector.options._clearedColor = true;
                            that.value(null);
                            that.element.val(null);
                            that._updateUI(null);
                            selector._colorAsText.val('');
                            selector._hsvHandle.css({
                                top: '0px',
                                left: '0px'
                            });
                            selector._selectedColor.css(BACKGROUNDCOLOR, WHITE);
                            that.trigger('change', { value: that.value() });
                            e.preventDefault();
                        }
                    });
                    selector.bind({
                        select: function (ev) {
                            that._updateUI(parseColor(ev.value));
                            delete selector.options._clearedColor;
                        },
                        change: function () {
                            if (!selector.options._clearedColor) {
                                that._select(selector.color());
                            }
                            that.close();
                        },
                        cancel: function () {
                            if (selector.options._clearedColor && !that.value() && selector.value()) {
                                that._select(selector.color(), true);
                            }
                            that.close();
                        }
                    });
                    popup.bind({
                        close: function (ev) {
                            if (that.trigger('close')) {
                                ev.preventDefault();
                                return;
                            }
                            that.wrapper.children('.k-picker-wrap').removeClass('k-state-focused');
                            var color = selector._selectOnHide();
                            var selectorColor = selector.value();
                            var value = that.value();
                            var options = selector.options;
                            if (!color) {
                                setTimeout(function () {
                                    if (that.wrapper && !that.wrapper.is('[unselectable=\'on\']')) {
                                        that.wrapper.focus();
                                    }
                                });
                                if (!options._closing && options._clearedColor && !value && selectorColor) {
                                    that._select(selectorColor, true);
                                } else {
                                    that._updateUI(that.color());
                                }
                            } else if (!(options._clearedColor && !value)) {
                                that._select(color);
                            }
                        },
                        open: function (ev) {
                            if (that.trigger('open')) {
                                ev.preventDefault();
                            } else {
                                that.wrapper.children('.k-picker-wrap').addClass('k-state-focused');
                            }
                        },
                        activate: function () {
                            selector._select(that.color(), true);
                            selector.focus();
                            that.wrapper.children('.k-picker-wrap').addClass('k-state-focused');
                        }
                    });
                }
                return popup;
            }
        });
        function preventDefault(ev) {
            ev.preventDefault();
        }
        function bind(callback, obj) {
            return function () {
                return callback.apply(obj, arguments);
            };
        }
        ui.plugin(ColorPalette);
        ui.plugin(FlatColorPicker);
        ui.plugin(ColorPicker);
    }(jQuery, parseInt));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.numerictextbox', [
        'kendo.core',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'numerictextbox',
        name: 'NumericTextBox',
        category: 'web',
        description: 'The NumericTextBox widget can format and display numeric, percentage or currency textbox.',
        depends: [
            'core',
            'userevents'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, caret = kendo.caret, keys = kendo.keys, ui = kendo.ui, Widget = ui.Widget, activeElement = kendo._activeElement, extractFormat = kendo._extractFormat, parse = kendo.parseFloat, placeholderSupported = kendo.support.placeholder, getCulture = kendo.getCulture, CHANGE = 'change', DISABLED = 'disabled', READONLY = 'readonly', INPUT = 'k-input', SPIN = 'spin', ns = '.kendoNumericTextBox', TOUCHEND = 'touchend', MOUSELEAVE = 'mouseleave' + ns, HOVEREVENTS = 'mouseenter' + ns + ' ' + MOUSELEAVE, DEFAULT = 'k-state-default', FOCUSED = 'k-state-focused', HOVER = 'k-state-hover', FOCUS = 'focus', POINT = '.', CLASS_ICON = 'k-icon', SELECTED = 'k-state-selected', STATEDISABLED = 'k-state-disabled', STATE_INVALID = 'k-state-invalid', ARIA_DISABLED = 'aria-disabled', INTEGER_REGEXP = /^(-)?(\d*)$/, NULL = null, proxy = $.proxy, extend = $.extend;
        var NumericTextBox = Widget.extend({
            init: function (element, options) {
                var that = this, isStep = options && options.step !== undefined, min, max, step, value, disabled;
                var inputType;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element.on('focusout' + ns, proxy(that._focusout, that)).attr('role', 'spinbutton');
                options.placeholder = options.placeholder || element.attr('placeholder');
                min = that.min(element.attr('min'));
                max = that.max(element.attr('max'));
                step = that._parse(element.attr('step'));
                if (options.min === NULL && min !== NULL) {
                    options.min = min;
                }
                if (options.max === NULL && max !== NULL) {
                    options.max = max;
                }
                if (!isStep && step !== NULL) {
                    options.step = step;
                }
                that._initialOptions = extend({}, options);
                inputType = element.attr('type');
                that._reset();
                that._wrapper();
                that._arrows();
                that._validation();
                that._input();
                if (!kendo.support.mobileOS) {
                    that._text.on(FOCUS + ns, proxy(that._click, that));
                } else {
                    that._text.on(TOUCHEND + ns + ' ' + FOCUS + ns, function () {
                        if (kendo.support.browser.edge) {
                            that._text.one(FOCUS + ns, function () {
                                that._toggleText(false);
                                element.focus();
                            });
                        } else {
                            that._toggleText(false);
                            element.focus();
                        }
                    });
                }
                element.attr('aria-valuemin', options.min !== NULL ? options.min * options.factor : options.min).attr('aria-valuemax', options.max !== NULL ? options.max * options.factor : options.max);
                options.format = extractFormat(options.format);
                value = options.value;
                if (value == NULL) {
                    if (inputType == 'number') {
                        value = parseFloat(element.val());
                    } else {
                        value = element.val();
                    }
                }
                that.value(value);
                disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                that.angular('compile', function () {
                    return { elements: that._text.get() };
                });
                kendo.notify(that);
            },
            options: {
                name: 'NumericTextBox',
                decimals: NULL,
                restrictDecimals: false,
                min: NULL,
                max: NULL,
                value: NULL,
                step: 1,
                round: true,
                culture: '',
                format: 'n',
                spinners: true,
                placeholder: '',
                factor: 1,
                upArrowText: 'Increase value',
                downArrowText: 'Decrease value'
            },
            events: [
                CHANGE,
                SPIN
            ],
            _editable: function (options) {
                var that = this, element = that.element, disable = options.disable, readonly = options.readonly, text = that._text.add(element), wrapper = that._inputWrapper.off(HOVEREVENTS);
                that._toggleText(true);
                that._upArrowEventHandler.unbind('press');
                that._downArrowEventHandler.unbind('press');
                element.off('keydown' + ns).off('keypress' + ns).off('keyup' + ns).off('paste' + ns);
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    text.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false);
                    that._upArrowEventHandler.bind('press', function (e) {
                        e.preventDefault();
                        that._spin(1);
                        that._upArrow.addClass(SELECTED);
                    });
                    that._downArrowEventHandler.bind('press', function (e) {
                        e.preventDefault();
                        that._spin(-1);
                        that._downArrow.addClass(SELECTED);
                    });
                    that.element.on('keydown' + ns, proxy(that._keydown, that)).on('keypress' + ns, proxy(that._keypress, that)).on('keyup' + ns, proxy(that._keyup, that)).on('paste' + ns, proxy(that._paste, that));
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    text.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            setOptions: function (options) {
                var that = this;
                Widget.fn.setOptions.call(that, options);
                that._arrowsWrap.toggle(that.options.spinners);
                that._inputWrapper.toggleClass('k-expand-padding', !that.options.spinners);
                that._text.prop('placeholder', that.options.placeholder);
                that._placeholder(that.options.placeholder);
                that.element.attr({
                    'aria-valuemin': that.options.min !== NULL ? that.options.min * that.options.factor : that.options.min,
                    'aria-valuemax': that.options.max !== NULL ? that.options.max * that.options.factor : that.options.max
                });
                that.options.format = extractFormat(that.options.format);
                if (options.value !== undefined) {
                    that.value(options.value);
                }
            },
            destroy: function () {
                var that = this;
                that.element.add(that._text).add(that._upArrow).add(that._downArrow).add(that._inputWrapper).off(ns);
                that._upArrowEventHandler.destroy();
                that._downArrowEventHandler.destroy();
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
                Widget.fn.destroy.call(that);
            },
            min: function (value) {
                return this._option('min', value);
            },
            max: function (value) {
                return this._option('max', value);
            },
            step: function (value) {
                return this._option('step', value);
            },
            value: function (value) {
                var that = this, adjusted;
                if (value === undefined) {
                    return that._value;
                }
                value = that._parse(value);
                adjusted = that._adjust(value);
                if (value !== adjusted) {
                    return;
                }
                that._update(value);
                that._old = that._value;
            },
            focus: function () {
                this._focusin();
            },
            _adjust: function (value) {
                var that = this, options = that.options, min = options.min, max = options.max;
                if (value === NULL) {
                    return value;   // return "";  //Custom Change// // don't keep//  //**line 33847 (--NumericTextBox--)
                }
                if (min !== NULL && value < min) {
                    value = min;
                } else if (max !== NULL && value > max) {
                    value = max;
                }
                return value;
            },
            _arrows: function () {
                var that = this, arrows, _release = function () {
                        clearTimeout(that._spinning);
                        arrows.removeClass(SELECTED);
                    }, options = that.options, spinners = options.spinners, element = that.element;
                arrows = element.siblings('.' + CLASS_ICON);
                if (!arrows[0]) {
                    arrows = $(buttonHtml('increase', options.upArrowText) + buttonHtml('decrease', options.downArrowText)).insertAfter(element);
                    that._arrowsWrap = arrows.wrapAll('<span class="k-select"/>').parent();
                }
                if (!spinners) {
                    arrows.parent().toggle(spinners);
                    that._inputWrapper.addClass('k-expand-padding');
                }
                that._upArrow = arrows.eq(0);
                that._upArrowEventHandler = new kendo.UserEvents(that._upArrow, { release: _release });
                that._downArrow = arrows.eq(1);
                that._downArrowEventHandler = new kendo.UserEvents(that._downArrow, { release: _release });
            },
            _validation: function () {
                var that = this;
                var element = that.element;
                that._validationIcon = $('<span class=\'' + CLASS_ICON + ' k-i-warning\'></span>').hide().insertAfter(element);
            },
            _blur: function () {
                var that = this;
                that._toggleText(true);
                that._change(that.element.val());
            },
            _click: function (e) {
                var that = this;
                clearTimeout(that._focusing);
                that._focusing = setTimeout(function () {
                    var input = e.target, idx = caret(input)[0], value = input.value.substring(0, idx), format = that._format(that.options.format), group = format[','], result, groupRegExp, extractRegExp, caretPosition = 0;
                    if (group) {
                        groupRegExp = new RegExp('\\' + group, 'g');
                        extractRegExp = new RegExp('(^(-)$)|(^(-)?([\\d\\' + group + ']+)(\\' + format[POINT] + ')?(\\d+)?)');
                    }
                    if (extractRegExp) {
                        result = extractRegExp.exec(value);
                    }
                    if (result) {
                        caretPosition = result[0].replace(groupRegExp, '').length;
                        if (value.indexOf('(') != -1 && that._value < 0) {
                            caretPosition++;
                        }
                    }
                    that._focusin();
                    caret(that.element[0], caretPosition);
                });
            },
            _change: function (value) {
                var that = this, factor = that.options.factor;
                if (factor && factor !== 1) {
                    value = kendo.parseFloat(value);
                    if (value !== null) {
                        value = value / factor;
                    }
                }
                that._update(value);
                value = that._value;
                if (that._old != value) {
                    that._old = value;
                    if (!that._typing) {
                        that.element.trigger(CHANGE);
                    }
                    that.trigger(CHANGE);
                }
                that._typing = false;
            },
            _culture: function (culture) {
                return culture || getCulture(this.options.culture);
            },
            _focusin: function () {
                var that = this;
                that._inputWrapper.addClass(FOCUSED);
                that._toggleText(false);
                that.element[0].focus();
            },
            _focusout: function () {
                var that = this;
                clearTimeout(that._focusing);
                that._inputWrapper.removeClass(FOCUSED).removeClass(HOVER);
                that._blur();
                that._removeInvalidState();
            },
            _format: function (format, culture) {
                var numberFormat = this._culture(culture).numberFormat;
                format = format.toLowerCase();
                if (format.indexOf('c') > -1) {
                    numberFormat = numberFormat.currency;
                } else if (format.indexOf('p') > -1) {
                    numberFormat = numberFormat.percent;
                }
                return numberFormat;
            },
            _input: function () {
                var that = this, options = that.options, CLASSNAME = 'k-formatted-value', element = that.element.addClass(INPUT).show()[0], accessKey = element.accessKey, wrapper = that.wrapper, text;
                text = wrapper.find(POINT + CLASSNAME);
                if (!text[0]) {
                    text = $('<input type="text"/>').insertBefore(element).addClass(CLASSNAME);
                }
                try {
                    element.setAttribute('type', 'text');
                } catch (e) {
                    element.type = 'text';
                }
                text[0].title = element.title;
                text[0].tabIndex = element.tabIndex;
                text[0].style.cssText = element.style.cssText;
                text.prop('placeholder', options.placeholder);
                if (accessKey) {
                    text.attr('accesskey', accessKey);
                    element.accessKey = '';
                }
                that._text = text.addClass(element.className).attr({
                    'role': 'spinbutton',
                    'aria-valuemin': options.min !== NULL ? options.min * options.factor : options.min,
                    'aria-valuemax': options.max !== NULL ? options.max * options.factor : options.max,
                    'autocomplete': 'off'
                });
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode;
                that._key = key;
                if (key == keys.DOWN) {
                    that._step(-1);
                } else if (key == keys.UP) {
                    that._step(1);
                } else if (key == keys.ENTER) {
                    that._change(that.element.val());
                } else if (key != keys.TAB) {
                    that._typing = true;
                }
            },
            _keypress: function (e) {
                if (e.which === 0 || e.metaKey || e.ctrlKey || e.keyCode === keys.BACKSPACE || e.keyCode === keys.ENTER) {
                    return;
                }
                var that = this;
                var min = that.options.min;
                var element = that.element;
                var selection = caret(element);
                var selectionStart = selection[0];
                var selectionEnd = selection[1];
                var character = String.fromCharCode(e.which);
                var numberFormat = that._format(that.options.format);
                var isNumPadDecimal = that._key === keys.NUMPAD_DOT;
                var value = element.val();
                var isValid;
                if (isNumPadDecimal) {
                    character = numberFormat[POINT];
                }
                value = value.substring(0, selectionStart) + character + value.substring(selectionEnd);
                isValid = that._numericRegex(numberFormat).test(value);
                if (isValid && isNumPadDecimal) {
                    element.val(value);
                    caret(element, selectionStart + character.length);
                    e.preventDefault();
                } else if (min !== null && min >= 0 && value.charAt(0) === '-' || !isValid) {
                    that._addInvalidState();
                    e.preventDefault();
                }
                that._key = 0;
            },
            _keyup: function () {
                this._removeInvalidState();
            },
            _addInvalidState: function () {
                var that = this;
                that._inputWrapper.addClass(STATE_INVALID);
                that._validationIcon.show();
            },
            _removeInvalidState: function () {
                var that = this;
                that._inputWrapper.removeClass(STATE_INVALID);
                that._validationIcon.hide();
            },
            _numericRegex: function (numberFormat) {
                var that = this;
                var separator = numberFormat[POINT];
                var precision = that.options.decimals;
                var fractionRule = '*';
                if (separator === POINT) {
                    separator = '\\' + separator;
                }
                if (precision === NULL) {
                    precision = numberFormat.decimals;
                }
                if (precision === 0 && that.options.restrictDecimals) {
                    return INTEGER_REGEXP;
                }
                if (that.options.restrictDecimals) {
                    fractionRule = '{0,' + precision + '}';
                }
                if (that._separator !== separator) {
                    that._separator = separator;
                    that._floatRegExp = new RegExp('^(-)?(((\\d+(' + separator + '\\d' + fractionRule + ')?)|(' + separator + '\\d' + fractionRule + ')))?$');
                }
                return that._floatRegExp;
            },
            _paste: function (e) {
                var that = this;
                var element = e.target;
                var value = element.value;
                var numberFormat = that._format(that.options.format);
                setTimeout(function () {
                    var result = that._parse(element.value);
                    if (result === NULL) {
                        that._update(value);
                    } else {
                        element.value = result.toString().replace(POINT, numberFormat[POINT]);
                        if (that._adjust(result) !== result || !that._numericRegex(numberFormat).test(element.value)) {
                            that._update(value);
                        }
                    }
                });
            },
            _option: function (option, value) {
                var that = this, element = that.element, options = that.options;
                if (value === undefined) {
                    return options[option];
                }
                value = that._parse(value);
                if (!value && option === 'step') {
                    return;
                }
                options[option] = value;
                element.add(that._text).attr('aria-value' + option, value);
                element.attr(option, value);
            },
            _spin: function (step, timeout) {
                var that = this;
                timeout = timeout || 500;
                clearTimeout(that._spinning);
                that._spinning = setTimeout(function () {
                    that._spin(step, 50);
                }, timeout);
                that._step(step);
            },
            _step: function (step) {
                var that = this, element = that.element, originalValue = that._value, value = that._parse(element.val()) || 0, precision = that.options.decimals || 2;
                if (activeElement() != element[0]) {
                    that._focusin();
                }
                if (that.options.factor && value) {
                    value = value / that.options.factor;
                }
                value = +(value + that.options.step * step).toFixed(precision);
                value = that._adjust(value);
                that._update(value);
                that._typing = false;
                if (originalValue !== value) {
                    that.trigger(SPIN);
                }
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _toggleText: function (toggle) {
                var that = this;
                that._text.toggle(toggle);
                that.element.toggle(!toggle);
            },
            _parse: function (value, culture) {
                return parse(value, this._culture(culture), this.options.format);
            },
            _round: function (value, precision) {
                var rounder = this.options.round ? kendo._round : truncate;
                return rounder(value, precision);
            },
            _update: function (value) {
                var that = this, options = that.options, factor = options.factor, format = options.format, decimals = options.decimals, culture = that._culture(), numberFormat = that._format(format, culture), isNotNull;
                if (decimals === NULL) {
                    decimals = numberFormat.decimals;
                }
                value = that._parse(value, culture);
                isNotNull = value !== NULL;
                if (isNotNull) {
                    value = parseFloat(that._round(value, decimals), 10);
                }
                that._value = value = that._adjust(value);
                that._placeholder(kendo.toString(value, format, culture));
                if (isNotNull) {
                    if (factor) {
                        value = parseFloat(that._round(value * factor, decimals), 10);
                    }
                    value = value.toString();
                    if (value.indexOf('e') !== -1) {
                        value = that._round(+value, decimals);
                    }
                    value = value.replace(POINT, numberFormat[POINT]);
                } else {
                    value = null;
                }
                that.element.val(value);
                that.element.add(that._text).attr('aria-valuenow', value);
            },
            _placeholder: function (value) {
                var input = this._text;
                input.val(value);
                if (!placeholderSupported && !value) {
                    input.val(this.options.placeholder);
                }
                input.attr('title', this.element.attr('title') || input.val());
            },
            _wrapper: function () {
                var that = this, element = that.element, DOMElement = element[0], wrapper;
                wrapper = element.parents('.k-numerictextbox');
                if (!wrapper.is('span.k-numerictextbox')) {
                    wrapper = element.hide().wrap('<span class="k-numeric-wrap k-state-default" />').parent();
                    wrapper = wrapper.wrap('<span/>').parent();
                }
                wrapper[0].style.cssText = DOMElement.style.cssText;
                DOMElement.style.width = '';
                that.wrapper = wrapper.addClass('k-widget k-numerictextbox').addClass(DOMElement.className).css('display', '');
                that._inputWrapper = $(wrapper[0].firstChild);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(element[0].value);
                            that.max(that._initialOptions.max);
                            that.min(that._initialOptions.min);
                        });
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            }
        });
        function buttonHtml(direction, text) {
            var className = 'k-i-arrow-' + (direction === 'increase' ? '60-up' : '60-down');
            return '<span unselectable="on" class="k-link k-link-' + direction + '" aria-label="' + text + '" title="' + text + '">' + '<span unselectable="on" class="' + CLASS_ICON + ' ' + className + '"></span>' + '</span>';
        }
        function truncate(value, precision) {
            var parts = parseFloat(value, 10).toString().split(POINT);
            if (parts[1]) {
                parts[1] = parts[1].substring(0, precision);
            }
            return parts.join(POINT);
        }
        ui.plugin(NumericTextBox);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.filtermenu', [
        'kendo.datepicker',
        'kendo.numerictextbox',
        'kendo.dropdownlist',
        'kendo.binder'
    ], f);
}(function () {
    var __meta__ = {
        id: 'filtermenu',
        name: 'Filtering Menu',
        category: 'framework',
        depends: [
            'datepicker',
            'numerictextbox',
            'dropdownlist',
            'binder'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, proxy = $.proxy, support = kendo.support, AUTOCOMPLETEVALUE = support.browser.chrome ? 'disabled' : 'off', POPUP = 'kendoPopup', INIT = 'init', OPEN = 'open', REFRESH = 'refresh', CHANGE = 'change', NS = '.kendoFilterMenu', EQ = 'Is equal to', NEQ = 'Is not equal to', roles = {
                'number': 'numerictextbox',
                'date': 'datepicker'
            }, mobileRoles = {
                'string': 'text',
                'number': 'number',
                'date': 'date'
            }, isFunction = kendo.isFunction, Widget = ui.Widget;
        var booleanTemplate = '<div class="k-filter-menu-container">' + '<div class="k-filter-help-text">#=messages.info#</div>' + '<label>' + '<input type="radio" data-#=ns#bind="checked: filters[0].value" value="true" name="filters[0].value"/>' + '#=messages.isTrue#' + '</label>' + '<label>' + '<input type="radio" data-#=ns#bind="checked: filters[0].value" value="false" name="filters[0].value"/>' + '#=messages.isFalse#' + '</label>' + '<div class="k-action-buttons">' + '<button type="submit" title="#=messages.filter#" class="k-button k-primary">#=messages.filter#</button>' + '<button type="reset" title="#=messages.clear#" class="k-button">#=messages.clear#</button>' + '</div>' + '</div>';
        var customBooleanTemplate = '<div class="k-filter-menu-container">' + '<div class="k-filter-help-text">#=messages.info#</div>' + '<label>' + '<input class="k-textbox" data-#=ns#bind="value: filters[0].value" name="filters[0].value"/>' + '</label>' + '<div class="k-action-buttons">' + '<button type="submit" title="#=messages.filter#" class="k-button k-primary">#=messages.filter#</button>' + '<button type="reset" title="#=messages.clear#" class="k-button">#=messages.clear#</button>' + '</div>' + '</div>';
        var defaultTemplate = '<div class="k-filter-menu-container">' + '<div class="k-filter-help-text">#=messages.info#</div>' + '<select title="#=messages.operator#" data-#=ns#bind="value: filters[0].operator" data-#=ns#role="dropdownlist">' + '#for(var op in operators){#' + '<option value="#=op#">#=operators[op]#</option>' + '#}#' + '</select>' + '#if(values){#' + '<select title="#=messages.value#" data-#=ns#bind="value:filters[0].value" data-#=ns#text-field="text" data-#=ns#value-field="value" data-#=ns#source=\'#=kendo.stringify(values).replace(/\'/g,"&\\#39;")#\' data-#=ns#role="dropdownlist" data-#=ns#option-label="#=messages.selectValue#" data-#=ns#value-primitive="true">' + '</select>' + '#}else{#' + '<input title="#=messages.value#" data-#=ns#bind="value:filters[0].value" class="k-textbox" type="text" #=role ? "data-" + ns + "role=\'" + role + "\'" : ""# />' + '#}#' + '#if(extra){#' + '<select title="#=messages.logic#" class="k-filter-and" data-#=ns#bind="value: logic" data-#=ns#role="dropdownlist">' + '<option value="and">#=messages.and#</option>' + '<option value="or">#=messages.or#</option>' + '</select>' + '<select title="#=messages.additionalOperator#" data-#=ns#bind="value: filters[1].operator" data-#=ns#role="dropdownlist">' + '#for(var op in operators){#' + '<option value="#=op#">#=operators[op]#</option>' + '#}#' + '</select>' + '#if(values){#' + '<select title="#=messages.additionalValue#" data-#=ns#bind="value:filters[1].value" data-#=ns#text-field="text" data-#=ns#value-field="value" data-#=ns#source=\'#=kendo.stringify(values).replace(/\'/g,"&\\#39;")#\' data-#=ns#role="dropdownlist" data-#=ns#option-label="#=messages.selectValue#" data-#=ns#value-primitive="true">' + '</select>' + '#}else{#' + '<input title="#=messages.additionalValue#" data-#=ns#bind="value: filters[1].value" class="k-textbox" type="text" #=role ? "data-" + ns + "role=\'" + role + "\'" : ""#/>' + '#}#' + '#}#' + '<div class="k-action-buttons">' + '<button type="submit" title="#=messages.filter#" class="k-button k-primary">#=messages.filter#</button>' + '<button type="reset" title="#=messages.clear#" class="k-button">#=messages.clear#</button>' + '</div>' + '</div>';
        var defaultMobileTemplate = '<div data-#=ns#role="view" class="k-grid-filter-menu">' + '<div data-#=ns#role="header" class="k-header">' + '<a href="\\#" class="k-header-cancel k-link" title="#=messages.cancel#" ' + 'aria-label="#=messages.cancel#"><span class="k-icon k-i-arrow-chevron-left"></span></a>' + '#=messages.filter# #=messages.into# #=title#' + '<a href="\\#" class="k-header-done k-link" title="#=messages.done#" ' + 'aria-label="#=messages.done#"><span class="k-icon k-i-check"></span></a>' + '</div>' + '<form title="#=messages.title#" class="k-filter-menu k-mobile-list">' + '<ul>' + '<li>' + '<span class="k-filter-help-text">#=messages.info#</span>' + '<ul>' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-filter-operator-text">#=messages.operator#</span>' + '<select id="operator_#=filterMenuGuid#" title="#=messages.operator#" class="k-filter-operator" data-#=ns#bind="value: filters[0].operator" autocomplete="' + AUTOCOMPLETEVALUE + '" >' + '#for(var op in operators){#' + '<option value="#=op#">#=operators[op]#</option>' + '#}#' + '</select>' + '</label>' + '</li>' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-filter-input-text">#=messages.value#</span>' + '#if(values){#' + '<select id="value_#=filterMenuGuid#" title="#=messages.value#" data-#=ns#bind="value:filters[0].value" autocomplete="' + AUTOCOMPLETEVALUE + '" >' + '<option value="">#=messages.selectValue#</option>' + '#for(var val in values){#' + '<option value="#=values[val].value#">#=values[val].text#</option>' + '#}#' + '</select>' + '#}else{#' + '<input id="value_#=filterMenuGuid#" title="#=messages.value#" data-#=ns#bind="value:filters[0].value" class="k-value-input" type="#=inputType#" autocomplete="' + AUTOCOMPLETEVALUE + '" />' + '#}#' + '</label>' + '</li>' + '</ul>' + '#if(extra){#' + '<ul>' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-filter-logic-and-text">#=messages.and#</span>' + '<input id="and_#=filterMenuGuid#" title="#=messages.and#" type="radio" name="logic" class="k-radio" data-#=ns#bind="checked: logic" value="and" autocomplete="' + AUTOCOMPLETEVALUE + '" />' + '<span class="k-radio-label"></span>' + '</label>' + '</li>' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-filter-logic-or-text">#=messages.or#</span>' + '<input id="or_#=filterMenuGuid#" title="#=messages.or#" type="radio" name="logic" class="k-radio" data-#=ns#bind="checked: logic" value="or" autocomplete="' + AUTOCOMPLETEVALUE + '" />' + '<span class="k-radio-label"></label>' + '</label>' + '</li>' + '</ul>' + '<ul>' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-filter-operator-text">#=messages.additionalOperator#</span>' + '<select id="additionalOperator_#=filterMenuGuid#" title="#=messages.additionalOperator#" class="k-filter-operator" data-#=ns#bind="value: filters[1].operator" autocomplete="' + AUTOCOMPLETEVALUE + '" >' + '#for(var op in operators){#' + '<option value="#=op#">#=operators[op]#</option>' + '#}#' + '</select>' + '</label>' + '</li>' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-filter-input-text">#=messages.additionalValue#</span>' + '#if(values){#' + '<select id="additionalValue_#=filterMenuGuid#" title="#=messages.additionalValue#" data-#=ns#bind="value:filters[1].value" autocomplete="' + AUTOCOMPLETEVALUE + '" >' + '<option value="">#=messages.selectValue#</option>' + '#for(var val in values){#' + '<option value="#=values[val].value#">#=values[val].text#</option>' + '#}#' + '</select>' + '#}else{#' + '<input id="additionalValue_#=filterMenuGuid#" title="#=messages.additionalValue#" data-#=ns#bind="value:filters[1].value" class="k-value-input" type="#=inputType#" autocomplete="' + AUTOCOMPLETEVALUE + '" />' + '#}#' + '</label>' + '</li>' + '</ul>' + '#}#' + '</li>' + '<li class="k-item k-clear-wrap">' + '<span class="k-label k-clear" title="#=messages.clear#" ' + 'aria-label="#=messages.clear#">#=messages.clear#</span>' + '</li>' + '</ul>' + '</form>' + '</div>';
        var booleanMobileTemplate = '<div data-#=ns#role="view" class="k-grid-filter-menu">' + '<div data-#=ns#role="header" class="k-header">' + '<a href="\\#" class="k-header-cancel k-link" title="#=messages.cancel#" ' + 'aria-label="#=messages.cancel#"><span class="k-icon k-i-arrow-chevron-left"></span></a>' + '#=messages.filter# #=messages.into# #=title#' + '<a href="\\#" class="k-header-done k-link" title="#=messages.done#" ' + 'aria-label="#=messages.done#"><span class="k-icon k-i-check"></span></a>' + '</div>' + '<form title="#=messages.title#" class="k-filter-menu k-mobile-list">' + '<ul>' + '<li>' + '<span class="k-filter-help-text">#=messages.info#</span>' + '<ul class="k-multicheck-bool-wrap">' + '<li class="k-item"><label class="k-label">' + '<input id="true_#=filterMenuGuid#" title="#=messages.isTrue#" class="k-check" type="radio" data-#=ns#bind="checked: filters[0].value" value="true" name="filters[0].value" autocomplete="' + AUTOCOMPLETEVALUE + '" />' + '<span class="k-item-title">#=messages.isTrue#</span>' + '</label></li>' + '<li class="k-item"><label class="k-label">' + '<input id="false_#=filterMenuGuid#" title="#=messages.isFalse#" class="k-check" type="radio" data-#=ns#bind="checked: filters[0].value" value="false" name="filters[0].value"/> autocomplete="' + AUTOCOMPLETEVALUE + '" ' + '<span for="false_#=filterMenuGuid#" class="k-item-title">#=messages.isFalse#</span>' + '</label></li>' + '</ul>' + '</li>' + '<li class="k-item k-clear-wrap">' + '<span class="k-label k-clear" title="#=messages.clear#" ' + 'aria-label="#=messages.clear#">#=messages.clear#</span>' + '</li>' + '</ul>' + '</form>' + '</div>';
        function removeFiltersForField(expression, field) {
            if (expression.filters) {
                expression.filters = $.grep(expression.filters, function (filter) {
                    removeFiltersForField(filter, field);
                    if (filter.filters) {
                        return filter.filters.length;
                    } else {
                        return filter.field != field;
                    }
                });
            }
        }
        function convertItems(items) {
            var idx, length, item, value, text, result;
            if (items && items.length) {
                result = [];
                for (idx = 0, length = items.length; idx < length; idx++) {
                    item = items[idx];
                    text = item.text !== '' ? item.text || item.value || item : item.text;
                    value = item.value == null ? item.text || item : item.value;
                    result[idx] = {
                        text: text,
                        value: value
                    };
                }
            }
            return result;
        }
        function clearFilter(filters, field) {
            return $.grep(filters, function (expr) {
                if (expr.filters) {
                    expr.filters = $.grep(expr.filters, function (nested) {
                        return nested.field != field;
                    });
                    return expr.filters.length;
                }
                return expr.field != field;
            });
        }
        var FilterMenu = Widget.extend({
            init: function (element, options) {
                var that = this, type = 'string', operators, initial, link, field;
                Widget.fn.init.call(that, element, options);
                operators = that.operators = options.operators || {};
                element = that.element;
                options = that.options;
                if (!options.appendToElement) {
                    link = element.addClass('k-with-icon k-filterable').find('.k-grid-filter');
                    if (!link[0]) {
                        link = element.prepend('<a class="k-grid-filter" href="#" title="' + options.messages.filter + '" aria-label="' + options.messages.filter + '"><span class="k-icon k-i-filter"></span></a>').find('.k-grid-filter');
                    }
                    link.attr('tabindex', -1).on('click' + NS, proxy(that._click, that));
                }
                that.link = link || $();
                that.dataSource = DataSource.create(options.dataSource);
                that.field = options.field || element.attr(kendo.attr('field'));
                that.model = that.dataSource.reader.model;
                that._parse = function (value) {
                    return value != null ? value + '' : value;
                };
                if (that.model && that.model.fields) {
                    field = that.model.fields[that.field];
                    if (field) {
                        type = field.type || 'string';
                        if (field.parse) {
                            that._parse = proxy(field.parse, field);
                        }
                    }
                }
                if (options.values) {
                    type = 'enums';
                }
                that.type = type;
                operators = operators[type] || options.operators[type];
                for (initial in operators) {
                    break;
                }
                that._defaultFilter = function () {
                    return {
                        field: that.field,
                        operator: initial || 'eq',
                        value: ''
                    };
                };
                that._refreshHandler = proxy(that.refresh, that);
                that.dataSource.bind(CHANGE, that._refreshHandler);
                if (options.appendToElement) {
                    that._init();
                } else {
                    that.refresh();
                }
            },
            _init: function () {
                var that = this, ui = that.options.ui, setUI = isFunction(ui), role;
                that.pane = that.options.pane;
                if (that.pane) {
                    that._isMobile = true;
                }
                if (!setUI) {
                    role = ui || roles[that.type];
                }
                if (that._isMobile) {
                    that._createMobileForm(role);
                } else {
                    that._createForm(role);
                }
                that.form.on('submit' + NS, proxy(that._submit, that)).on('reset' + NS, proxy(that._reset, that));
                if (setUI) {
                    that.form.find('.k-textbox').removeClass('k-textbox').each(function () {
                        ui($(this));
                    });
                }
                that.form.find('[' + kendo.attr('role') + '=numerictextbox]').removeClass('k-textbox').end().find('[' + kendo.attr('role') + '=datetimepicker]').removeClass('k-textbox').end().find('[' + kendo.attr('role') + '=timepicker]').removeClass('k-textbox').end().find('[' + kendo.attr('role') + '=datepicker]').removeClass('k-textbox');
                that.refresh();
                that.trigger(INIT, {
                    field: that.field,
                    container: that.form
                });
                kendo.cycleForm(that.form);
            },
            _createForm: function (role) {
                var that = this, options = that.options, operators = that.operators || {}, type = that.type, hasCustomTemplate = isFunction(that.options.ui);
                operators = operators[type] || options.operators[type];
                that.form = $('<form title="' + that.options.messages.title + '" class="k-filter-menu"/>').html(kendo.template(type === 'boolean' ? hasCustomTemplate ? customBooleanTemplate : booleanTemplate : defaultTemplate)({
                    field: that.field,
                    format: options.format,
                    ns: kendo.ns,
                    messages: options.messages,
                    extra: options.extra,
                    operators: operators,
                    type: type,
                    role: role,
                    values: convertItems(options.values)
                }));
                if (!options.appendToElement) {
                    that.popup = that.form[POPUP]({
                        anchor: that.link,
                        open: proxy(that._open, that),
                        activate: proxy(that._activate, that),
                        close: function () {
                            if (that.options.closeCallback) {
                                that.options.closeCallback(that.element);
                            }
                        }
                    }).data(POPUP);
                } else {
                    that.element.append(that.form);
                    that.popup = that.element.closest('.k-popup').data(POPUP);
                }
                that.form.on('keydown' + NS, proxy(that._keydown, that));
            },
            _createMobileForm: function (role) {
                var that = this, options = that.options, operators = that.operators || {}, filterMenuGuid = kendo.guid(), type = that.type;
                operators = operators[type] || options.operators[type];
                that.form = $('<div />').html(kendo.template(type === 'boolean' ? booleanMobileTemplate : defaultMobileTemplate)({
                    field: that.field,
                    title: options.title || that.field,
                    format: options.format,
                    ns: kendo.ns,
                    messages: options.messages,
                    extra: options.extra,
                    operators: operators,
                    filterMenuGuid: filterMenuGuid,
                    type: type,
                    role: role,
                    inputType: mobileRoles[type],
                    values: convertItems(options.values)
                }));
                that.view = that.pane.append(that.form.html());
                that.form = that.view.element.find('form');
                that.view.element.on('click', '.k-header-done', function (e) {
                    that.form.submit();
                    e.preventDefault();
                }).on('click', '.k-header-cancel', function (e) {
                    that._closeForm();
                    e.preventDefault();
                }).on('click', '.k-clear', function (e) {
                    that._mobileClear();
                    e.preventDefault();
                });
                that.view.bind('show', function () {
                    that.refresh();
                });
            },
            refresh: function () {
                var that = this, expression = that.dataSource.filter() || {
                        filters: [],
                        logic: 'and'
                    };
                var defaultFilters = [that._defaultFilter()];
                var defaultOperator = that._defaultFilter().operator;
                if (that.options.extra || defaultOperator !== 'isnull' && defaultOperator !== 'isnullorempty' && defaultOperator !== 'isnotnullorempty' && defaultOperator !== 'isnotnull' && defaultOperator !== 'isempty' && defaultOperator !== 'isnotempty') {
                    defaultFilters.push(that._defaultFilter());
                }
                that.filterModel = kendo.observable({
                    logic: 'and',
                    filters: defaultFilters
                });
                if (that.form) {
                    kendo.bind(that.form.children().first(), that.filterModel);
                }
                if (that._bind(expression)) {
                    that.link.addClass('k-state-active');
                } else {
                    that.link.removeClass('k-state-active');
                }
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                if (that.form) {
                    kendo.unbind(that.form);
                    kendo.destroy(that.form);
                    that.form.unbind(NS);
                    if (that.popup) {
                        that.popup.destroy();
                        that.popup = null;
                    }
                    that.form = null;
                }
                if (that.view) {
                    that.view.purge();
                    that.view = null;
                }
                that.link.unbind(NS);
                if (that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                    that.dataSource = null;
                }
                that.element = that.link = that._refreshHandler = that.filterModel = null;
            },
            _bind: function (expression) {
                var that = this, filters = expression.filters, idx, length, found = false, current = 0, filterModel = that.filterModel, currentFilter, filter;
                for (idx = 0, length = filters.length; idx < length; idx++) {
                    filter = filters[idx];
                    if (filter.field == that.field) {
                        filterModel.set('logic', expression.logic);
                        currentFilter = filterModel.filters[current];
                        if (!currentFilter) {
                            filterModel.filters.push({ field: that.field });
                            currentFilter = filterModel.filters[current];
                        }
                        currentFilter.set('value', that._parse(filter.value));
                        currentFilter.set('operator', filter.operator);
                        current++;
                        found = true;
                    } else if (filter.filters) {
                        found = found || that._bind(filter);
                    }
                }
                return found;
            },
            _stripFilters: function (filters) {
                return $.grep(filters, function (filter) {
                    return filter.value !== '' && filter.value != null || (filter.operator === 'isnull' || filter.operator === 'isnotnull' || filter.operator === 'isempty' || filter.operator === 'isnotempty' || filter.operator == 'isnullorempty' || filter.operator == 'isnotnullorempty');
                });
            },
            _merge: function (expression) {
                var that = this, logic = expression.logic || 'and', filters = this._stripFilters(expression.filters), filter, result = that.dataSource.filter() || {
                        filters: [],
                        logic: 'and'
                    }, idx, length;
                removeFiltersForField(result, that.field);
                for (idx = 0, length = filters.length; idx < length; idx++) {
                    filter = filters[idx];
                    filter.value = that._parse(filter.value);
                }
                if (filters.length) {
                    if (result.filters.length) {
                        expression.filters = filters;
                        if (result.logic !== 'and') {
                            result.filters = [{
                                    logic: result.logic,
                                    filters: result.filters
                                }];
                            result.logic = 'and';
                        }
                        if (filters.length > 1) {
                            result.filters.push(expression);
                        } else {
                            result.filters.push(filters[0]);
                        }
                    } else {
                        result.filters = filters;
                        result.logic = logic;
                    }
                }
                return result;
            },
            filter: function (expression) {
                var filters = this._stripFilters(expression.filters);
                if (filters.length && this.trigger('change', {
                        filter: {
                            logic: expression.logic,
                            filters: filters
                        },
                        field: this.field
                    })) {
                    return;
                }
                expression = this._merge(expression);
                if (expression.filters.length) {
                    this.dataSource.filter(expression);
                }
            },
            clear: function () {
                var that = this, expression = that.dataSource.filter() || { filters: [] };
                if (this.trigger('change', {
                        filter: null,
                        field: that.field
                    })) {
                    return;
                }
                that._removeFilter(expression);
            },
            _mobileClear: function () {
                var that = this;
                var viewElement = that.view.element;
                if (that.type === 'boolean') {
                    var booleanRadioButton = viewElement.find('.k-check:checked');
                    var booleanRadioButtonValue = booleanRadioButton.val();
                    booleanRadioButton.val('');
                    booleanRadioButton.trigger('change');
                    booleanRadioButton.val(booleanRadioButtonValue);
                    booleanRadioButton.prop('checked', false);
                } else {
                    var operatorSelects = viewElement.find('select');
                    operatorSelects.each(function (i, e) {
                        var input = $(e);
                        input.val(input.find('option:first').val());
                        input.trigger('change');
                    });
                    if (that.type === 'string' || that.type === 'date' || that.type === 'number') {
                        var valueInputs = viewElement.find('.k-value-input');
                        valueInputs.each(function (i, e) {
                            var input = $(e);
                            input.val('');
                            input.trigger('change');
                        });
                    }
                    if (that.options.extra) {
                        var andLogicRadio = viewElement.find('[name=logic]').first();
                        andLogicRadio.prop('checked', true);
                        andLogicRadio.trigger('change');
                    }
                }
            },
            _removeFilter: function (expression) {
                var that = this;
                expression.filters = $.grep(expression.filters, function (filter) {
                    if (filter.filters) {
                        filter.filters = clearFilter(filter.filters, that.field);
                        return filter.filters.length;
                    }
                    return filter.field != that.field;
                });
                if (!expression.filters.length) {
                    expression = null;
                }
                that.dataSource.filter(expression);
            },
            _submit: function (e) {
                e.preventDefault();
                e.stopPropagation();
                var expression = this.filterModel.toJSON();
                var containsFilters = $.grep(expression.filters, function (filter) {
                    return filter.value !== '' && filter.value !== null;
                });
                if (this._checkForNullOrEmptyFilter(expression) || containsFilters && containsFilters.length) {
                    this.filter(expression);
                } else {
                    var currentExpression = this.dataSource.filter();
                    if (currentExpression) {
                        currentExpression.filters.push(expression);
                        expression = currentExpression;
                    }
                    this._removeFilter(expression);
                }
                this._closeForm();
            },
            _checkForNullOrEmptyFilter: function (expression) {
                if (!expression || !expression.filters || !expression.filters.length) {
                    return false;
                }
                var firstNullOrEmpty = false;
                var secondNullOrEmpty = false;
                var operator;
                if (expression.filters[0]) {
                    operator = expression.filters[0].operator;
                    firstNullOrEmpty = operator == 'isnull' || operator == 'isnotnull' || operator == 'isnotempty' || operator == 'isempty' || operator == 'isnullorempty' || operator == 'isnotnullorempty';
                }
                if (expression.filters[1]) {
                    operator = expression.filters[1].operator;
                    secondNullOrEmpty = operator == 'isnull' || operator == 'isnotnull' || operator == 'isnotempty' || operator == 'isempty' || operator == 'isnullorempty' || operator == 'isnotnullorempty';
                }
                return !this.options.extra && firstNullOrEmpty || this.options.extra && (firstNullOrEmpty || secondNullOrEmpty);
            },
            _reset: function () {
                this.clear();
                if (this.options.search && this.container) {
                    this.container.find('label').parent().show();
                }
                this._closeForm();
            },
            _closeForm: function () {
                if (this._isMobile) {
                    this.pane.navigate('', this.options.animations.right);
                } else {
                    this.popup.close();
                }
            },
            _click: function (e) {
                e.preventDefault();
                e.stopPropagation();
                if (!this.popup && !this.pane) {
                    this._init();
                }
                if (this._isMobile) {
                    this.pane.navigate(this.view, this.options.animations.left);
                } else {
                    this.popup.toggle();
                }
            },
            _open: function () {
                var popup;
                $('.k-filter-menu').not(this.form).each(function () {
                    popup = $(this).data(POPUP);
                    if (popup) {
                        popup.close();
                    }
                });
            },
            _activate: function () {
                this.form.find(':kendoFocusable:first').focus();
                this.trigger(OPEN, {
                    field: this.field,
                    container: this.form
                });
            },
            _keydown: function (e) {
                if (e.keyCode == kendo.keys.ESC) {
                    this.popup.close();
                }
            },
            events: [
                INIT,
                'change',
                OPEN
            ],
            options: {
                name: 'FilterMenu',
                extra: true,
                appendToElement: false,
                type: 'string',
                operators: {
                    string: {
                        eq: EQ,
                        neq: NEQ,
                        startswith: 'Starts with',
                        contains: 'Contains',
                        doesnotcontain: 'Does not contain',
                        endswith: 'Ends with',
                        isnull: 'Is null',
                        isnotnull: 'Is not null',
                        isempty: 'Is empty',
                        isnotempty: 'Is not empty',
                        isnullorempty: 'Has no value',
                        isnotnullorempty: 'Has value'
                    },
                    number: {
                        eq: EQ,
                        neq: NEQ,
                        gte: 'Is greater than or equal to',
                        gt: 'Is greater than',
                        lte: 'Is less than or equal to',
                        lt: 'Is less than',
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    },
                    date: {
                        eq: EQ,
                        neq: NEQ,
                        gte: 'Is after or equal to',
                        gt: 'Is after',
                        lte: 'Is before or equal to',
                        lt: 'Is before',
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    },
                    enums: {
                        eq: EQ,
                        neq: NEQ,
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    }
                },
                messages: {
                    info: 'Show items with value that:',
                    title: 'Show items with value that:',
                    isTrue: 'is true',
                    isFalse: 'is false',
                    filter: 'Filter',
                    clear: 'Clear',
                    and: 'And',
                    or: 'Or',
                    selectValue: '-Select value-',
                    operator: 'Operator',
                    value: 'Value',
                    additionalValue: 'Additional value',
                    additionalOperator: 'Additional operator',
                    logic: 'Filters logic',
                    cancel: 'Cancel',
                    done: 'Done',
                    into: 'in'
                },
                animations: {
                    left: 'slide',
                    right: 'slide:right'
                }
            }
        });
        var multiCheckNS = '.kendoFilterMultiCheck';
        function filterValuesForField(expression, field) {
            if (expression.filters) {
                expression.filters = $.grep(expression.filters, function (filter) {
                    filterValuesForField(filter, field);
                    if (filter.filters) {
                        return filter.filters.length;
                    } else {
                        return filter.field == field && filter.operator == 'eq';
                    }
                });
            }
        }
        function flatFilterValues(expression) {
            if (expression.logic == 'and' && expression.filters.length > 1) {
                return [];
            }
            if (expression.filters) {
                return $.map(expression.filters, function (filter) {
                    return flatFilterValues(filter);
                });
            } else if (expression.value !== undefined) {
                return [expression.value];
            } else {
                return [];
            }
        }
        function distinct(items, field) {
            var getter = kendo.getter(field, true), result = [], index = 0, seen = {};
            while (index < items.length) {
                var item = items[index++], text = getter(item);
                if (text !== undefined && !seen.hasOwnProperty(text)) {
                    result.push(item);
                    seen[text] = true;
                }
            }
            return result;
        }
        function removeDuplicates(dataSelector, dataTextField) {
            return function (e) {
                var items = dataSelector(e);
                return distinct(items, dataTextField);
            };
        }
        var DataSource = kendo.data.DataSource;
        var multiCkeckMobileTemplate = '<div data-#=ns#role="view" class="k-grid-filter-menu">' + '<div data-#=ns#role="header" class="k-header">' + '<a href="\\#" class="k-header-cancel k-link" title="#=messages.cancel#" ' + 'aria-label="#=messages.cancel#"><span class="k-icon k-i-arrow-chevron-left"></span></a>' + '#=messages.filter# #=messages.into# #=title#' + '<a href="\\#" class="k-header-done k-link" title="#=messages.done#" ' + 'aria-label="#=messages.done#"><span class="k-icon k-i-check"></span></a>' + '</div>' + '<form class="k-filter-menu k-mobile-list">' + '<ul>' + '#if(search){#' + '<li class="k-textbox k-space-right">' + '<input placeholder="#=messages.search#" title="#=messages.search#" autocomplete="' + AUTOCOMPLETEVALUE + '"  />' + '<span class="k-icon k-i-zoom" />' + '</li>' + '#}#' + '<li class="k-filter-tools">' + '<span style="#=checkAll ? "" : "visibility: hidden;" #" class="k-label k-select-all" title="#=messages.checkAll#" ' + 'aria-label="#=messages.checkAll#">#=messages.checkAll#</span>' + '<span class="k-label k-clear-all" title="#=messages.clearAll#" ' + 'aria-label="#=messages.clearAll#">#=messages.clearAll#</span>' + '</li>' + '#if(messages.selectedItemsFormat){#' + '<li>' + '<div class="k-filter-selected-items"></div>' + '</li>' + '#}#' + '<li>' + '<ul class="k-multicheck-wrap"></ul>' + '</li>' + '</ul>' + '</form>' + '</div>';
        var FilterMultiCheck = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                options = this.options;
                this.element = $(element);
                var field = this.field = this.options.field || this.element.attr(kendo.attr('field'));
                var checkSource = options.checkSource;
                if (this._foreignKeyValues()) {
                    this.checkSource = DataSource.create(options.values);
                    this.checkSource.fetch();
                } else if (options.forceUnique) {
                    checkSource = $.extend(true, {}, options.dataSource.options);
                    delete checkSource.pageSize;
                    this.checkSource = DataSource.create(checkSource);
                    this.checkSource.reader.data = removeDuplicates(this.checkSource.reader.data, this.field);
                } else {
                    this.checkSource = DataSource.create(checkSource);
                }
                this.dataSource = options.dataSource;
                this.model = this.dataSource.reader.model;
                this._parse = function (value) {
                    return value + '';
                };
                if (this.model && this.model.fields) {
                    field = this.model.fields[this.field];
                    if (field) {
                        if (field.type == 'number') {
                            this._parse = function (value) {
                                if (typeof value === 'string' && value.toLowerCase() === 'null') {
                                    return null;
                                }
                                return parseFloat(value);
                            };
                        } else if (field.parse) {
                            this._parse = proxy(field.parse, field);
                        }
                        this.type = field.type || 'string';
                    }
                }
                if (!options.appendToElement) {
                    this._createLink();
                } else {
                    this._init();
                }
                this._refreshHandler = proxy(this.refresh, this);
                this.dataSource.bind(CHANGE, this._refreshHandler);
            },
            _createLink: function () {
                var element = this.element;
                var link = element.addClass('k-with-icon k-filterable').find('.k-grid-filter');
                if (!link[0]) {
                    link = element.prepend('<a class="k-grid-filter" href="#" title="' + this.options.messages.filter + '" aria-label="' + this.options.messages.filter + '"><span class="k-icon k-i-filter"/></a>').find('.k-grid-filter');
                }
                this._link = link.attr('tabindex', -1).on('click' + NS, proxy(this._click, this));
            },
            _init: function () {
                var that = this;
                var forceUnique = this.options.forceUnique;
                var options = this.options;
                this.pane = options.pane;
                if (this.pane) {
                    this._isMobile = true;
                }
                this._createForm();
                if (this._foreignKeyValues()) {
                    this.refresh();
                } else if (forceUnique && !this.checkSource.options.serverPaging && this.dataSource.data().length) {
                    this.checkSource.data(distinct(this.dataSource.data(), this.field));
                    this.refresh();
                } else {
                    this._attachProgress();
                    this.checkSource.fetch(function () {
                        that.refresh.call(that);
                    });
                }
                if (!this.options.forceUnique) {
                    this.checkChangeHandler = function () {
                        that.container.empty();
                        that.refresh();
                    };
                    this.checkSource.bind(CHANGE, this.checkChangeHandler);
                }
                this.form.on('keydown' + multiCheckNS, proxy(this._keydown, this)).on('submit' + multiCheckNS, proxy(this._filter, this)).on('reset' + multiCheckNS, proxy(this._reset, this));
                this.trigger(INIT, {
                    field: this.field,
                    container: this.form
                });
            },
            _attachProgress: function () {
                var that = this;
                this._progressHandler = function () {
                    ui.progress(that.container, true);
                };
                this._progressHideHandler = function () {
                    ui.progress(that.container, false);
                };
                this.checkSource.bind('progress', this._progressHandler).bind('change', this._progressHideHandler);
            },
            _input: function () {
                var that = this;
                that._clearTypingTimeout();
                that._typingTimeout = setTimeout(function () {
                    that.search();
                }, 100);
            },
            _clearTypingTimeout: function () {
                if (this._typingTimeout) {
                    clearTimeout(this._typingTimeout);
                    this._typingTimeout = null;
                }
            },
            search: function () {
                var ignoreCase = this.options.ignoreCase;
                var searchString = this.searchTextBox[0].value;
                var labels = this.container.find('label');
                if (ignoreCase) {
                    searchString = searchString.toLowerCase();
                }
                var i = 0;
                if (this.options.checkAll && labels.length) {
                    if (!this._isMobile) {
                        labels[0].parentNode.style.display = searchString ? 'none' : '';
                        i++;
                    } else {
                        this.view.element.find('.k-select-all')[0].style.visibility = searchString ? 'hidden' : '';
                    }
                }
                while (i < labels.length) {
                    var label = labels[i];
                    var labelText = label.textContent || label.innerText;
                    if (ignoreCase) {
                        labelText = labelText.toLowerCase();
                    }
                    label.parentNode.style.display = labelText.indexOf(searchString) >= 0 ? '' : 'none';
                    i++;
                }
            },
            _activate: function () {
                this.form.find(':kendoFocusable:first').focus();
                this.trigger(OPEN, {
                    field: this.field,
                    container: this.form
                });
            },
            _createForm: function () {
                var options = this.options;
                var html = '';
                var that = this;
                if (!this._isMobile) {
                    html += '<div class=\'k-filter-menu-container\'>';
                    if (options.search) {
                        html += '<div class=\'k-textbox k-space-right\'>' + '<input placeholder=\'' + options.messages.search + '\'/>' + '<span class=\'k-icon k-i-zoom\' />' + '</div>';
                    }
                    html += '<ul class=\'k-reset k-multicheck-wrap\'></ul>';
                    if (options.messages.selectedItemsFormat) {
                        html += '<div class=\'k-filter-selected-items\'>' + kendo.format(options.messages.selectedItemsFormat, 0) + '</div>';
                    }
                    html += '<div class=\'k-action-buttons\'>';
                    html += '<button type=\'submit\' class=\'k-button k-primary\'>' + options.messages.filter + '</button>';
                    html += '<button type=\'reset\' class=\'k-button\'>' + options.messages.clear + '</button>';
                    html += '</div>';
                    html += '</div>';
                    this.form = $('<form class="k-filter-menu"/>').html(html);
                    this.container = this.form.find('.k-multicheck-wrap');
                }
                if (this._isMobile) {
                    that.form = $('<div />').html(kendo.template(multiCkeckMobileTemplate)({
                        field: that.field,
                        title: options.title || that.field,
                        ns: kendo.ns,
                        messages: options.messages,
                        search: options.search,
                        checkAll: options.checkAll
                    }));
                    that.view = that.pane.append(that.form.html());
                    that.form = that.view.element.find('form');
                    var element = this.view.element;
                    this.container = element.find('.k-multicheck-wrap');
                    element.on('click', '.k-header-done', function (e) {
                        that.form.submit();
                        e.preventDefault();
                    }).on('click', '.k-header-cancel', function (e) {
                        that._closeForm();
                        e.preventDefault();
                    }).on('click', '.k-clear-all', function (e) {
                        that._mobileCheckAll(false);
                        e.preventDefault();
                    }).on('click', '.k-select-all', function (e) {
                        that._mobileCheckAll(true);
                        e.preventDefault();
                    });
                    that.view.bind('show', function () {
                        that.refresh();
                    });
                } else {
                    if (!options.appendToElement) {
                        that.popup = that.form.kendoPopup({
                            anchor: that._link,
                            open: proxy(that._open, that),
                            activate: proxy(that._activate, that),
                            close: function () {
                                if (that.options.closeCallback) {
                                    that.options.closeCallback(that.element);
                                }
                            }
                        }).data(POPUP);
                    } else {
                        this.popup = this.element.closest('.k-popup').data(POPUP);
                        this.element.append(this.form);
                    }
                }
                if (options.search) {
                    this.searchTextBox = this.form.find('.k-textbox > input');
                    this.searchTextBox.on('input', proxy(this._input, this));
                }
            },
            createCheckAllItem: function () {
                var options = this.options;
                var template = kendo.template(options.itemTemplate({
                    field: 'all',
                    mobile: this._isMobile
                }));
                var checkAllContainer = $(template({ all: options.messages.checkAll }));
                this.container.prepend(checkAllContainer);
                this.checkBoxAll = checkAllContainer.find(':checkbox').eq(0).addClass('k-check-all');
                this.checkAllHandler = proxy(this.checkAll, this);
                this.checkBoxAll.on(CHANGE + multiCheckNS, this.checkAllHandler);
            },
            updateCheckAllState: function () {
                if (this.options.messages.selectedItemsFormat) {
                    this.form.find('.k-filter-selected-items').text(kendo.format(this.options.messages.selectedItemsFormat, this.container.find(':checked:not(.k-check-all)').length));
                }
                if (this.checkBoxAll) {
                    var state = this.container.find(':checkbox:not(.k-check-all)').length == this.container.find(':checked:not(.k-check-all)').length;
                    this.checkBoxAll.prop('checked', state);
                }
            },
            refresh: function (e) {
                var forceUnique = this.options.forceUnique;
                var dataSource = this.dataSource;
                var filters = this.getFilterArray();
                if (this._link) {
                    this._link.toggleClass('k-state-active', filters.length !== 0);
                }
                if (this.form) {
                    if (e && forceUnique && e.sender === dataSource && !dataSource.options.serverPaging && (e.action == 'itemchange' || e.action == 'add' || e.action == 'remove' || dataSource.options.autoSync && e.action === 'sync') && !this._foreignKeyValues()) {
                        this.checkSource.data(distinct(this.dataSource.data(), this.field));
                        this.container.empty();
                    }
                    if (this.container.is(':empty')) {
                        this.createCheckBoxes();
                    }
                    this.checkValues(filters);
                    this.trigger(REFRESH);
                }
            },
            getFilterArray: function () {
                var expression = $.extend(true, {}, {
                    filters: [],
                    logic: 'and'
                }, this.dataSource.filter());
                filterValuesForField(expression, this.field);
                var flatValues = flatFilterValues(expression);
                return flatValues;
            },
            createCheckBoxes: function () {
                var options = this.options;
                var data;
                var templateOptions = {
                    field: this.field,
                    format: options.format,
                    mobile: this._isMobile,
                    type: this.type
                };
                if (!this.options.forceUnique) {
                    data = this.checkSource.view();
                } else if (this._foreignKeyValues()) {
                    data = this.checkSource.data();
                    templateOptions.valueField = 'value';
                    templateOptions.field = 'text';
                } else {
                    data = this.checkSource.data();
                }
                var template = kendo.template(options.itemTemplate(templateOptions));
                var itemsHtml = kendo.render(template, data);
                if (options.checkAll && !this._isMobile) {
                    this.createCheckAllItem();
                }
                this.container.on(CHANGE + multiCheckNS, ':checkbox', proxy(this.updateCheckAllState, this));
                this.container.append(itemsHtml);
            },
            checkAll: function () {
                var state = this.checkBoxAll.is(':checked');
                this.container.find(':checkbox').prop('checked', state);
            },
            checkValues: function (values) {
                var that = this;
                $($.grep(this.container.find(':checkbox').prop('checked', false), function (ele) {
                    var found = false;
                    if ($(ele).is('.k-check-all')) {
                        return;
                    }
                    var checkBoxVal = that._parse($(ele).val());
                    for (var i = 0; i < values.length; i++) {
                        if (that.type == 'date') {
                            if (values[i] && checkBoxVal) {
                                found = values[i].getTime() == checkBoxVal.getTime();
                            } else if (values[i] === null && checkBoxVal === null) {
                                found = true;
                            } else {
                                found = false;
                            }
                        } else {
                            found = values[i] == checkBoxVal;
                        }
                        if (found) {
                            return found;
                        }
                    }
                })).prop('checked', true);
                this.updateCheckAllState();
            },
            _mobileCheckAll: function (state) {
                var that = this;
                var checkboxes = that.container.find(':checkbox');
                checkboxes.each(function (i, e) {
                    var checkbox = $(e);
                    checkbox.prop('checked', state);
                    checkbox.trigger('change');
                });
            },
            _filter: function (e) {
                e.preventDefault();
                e.stopPropagation();
                var expression = { logic: 'or' };
                var that = this;
                expression.filters = $.map(this.form.find(':checkbox:checked:not(.k-check-all)'), function (item) {
                    return {
                        value: $(item).val(),
                        operator: 'eq',
                        field: that.field
                    };
                });
                if (expression.filters.length && this.trigger('change', {
                        filter: expression,
                        field: that.field
                    })) {
                    return;
                }
                expression = this._merge(expression);
                if (expression.filters.length) {
                    this.dataSource.filter(expression);
                } else {
                    this.clear();
                }
                this._closeForm();
            },
            _stripFilters: function (filters) {
                return $.grep(filters, function (filter) {
                    return filter.value != null;
                });
            },
            _foreignKeyValues: function () {
                var options = this.options;
                return options.values && !options.checkSource;
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                if (that.form) {
                    kendo.unbind(that.form);
                    kendo.destroy(that.form);
                    that.form.unbind(multiCheckNS);
                    if (that.popup) {
                        that.popup.destroy();
                        that.popup = null;
                    }
                    that.form = null;
                    if (that.container) {
                        that.container.unbind(multiCheckNS);
                        that.container = null;
                    }
                    if (that.checkBoxAll) {
                        that.checkBoxAll.unbind(multiCheckNS);
                    }
                }
                if (that.view) {
                    that.view.purge();
                    that.view = null;
                }
                if (that._link) {
                    that._link.unbind(NS);
                }
                if (that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                    that.dataSource = null;
                }
                if (that.checkChangeHandler) {
                    that.checkSource.unbind(CHANGE, that.checkChangeHandler);
                }
                if (that._progressHandler) {
                    that.checkSource.unbind('progress', that._progressHandler);
                }
                if (that._progressHideHandler) {
                    that.checkSource.unbind('change', that._progressHideHandler);
                }
                this._clearTypingTimeout();
                this.searchTextBox = null;
                that.element = that.checkSource = that.container = that.checkBoxAll = that._link = that._refreshHandler = that.checkAllHandler = null;
            },
            options: {
                name: 'FilterMultiCheck',
                itemTemplate: function (options) {
                    var field = options.field;
                    var format = options.format;
                    var valueField = options.valueField;
                    var mobile = options.mobile;
                    var valueFormat = '';
                    if (valueField === undefined) {
                        valueField = field;
                    }
                    if (options.type == 'date') {
                        valueFormat = ':yyyy-MM-ddTHH:mm:sszzz';
                    }
                    return '<li class=\'k-item\'>' + '<label class=\'k-label\'>' + '<input type=\'checkbox\' class=\'' + (mobile ? 'k-check' : '') + '\'  value=\'#:kendo.format(\'{0' + valueFormat + '}\',' + valueField + ')#\'/>' + '<span class=\'k-item-title\'>#:kendo.format(\'' + (format ? format : '{0}') + '\', ' + field + ')#</span>' + '</label>' + '</li>';
                    // CUSTOM CHANGE - do not keep // return '<li class=\'k-item\'>' + '<label class=\'k-label\'>' + '<input type=\'checkbox\' class=\'' + (mobile ? 'k-check' : '') + '\'  value=\'#:kendo.format(\'{0' + valueFormat + '}\',' + valueField + ')#\'/><span>' + '#:kendo.format(\'' + (format ? format : '{0}') + '\', ' + field + ')#' + '</span></label>' + '</li>';  //Custom Change// // don't keep//
                },
                checkAll: true,
                search: false,
                ignoreCase: true,
                appendToElement: false,
                messages: {
                    checkAll: 'Select All',
                    clearAll: 'Clear All',
                    clear: 'Clear',
                    filter: 'Filter',
                    search: 'Search',
                    cancel: 'Cancel',
                    selectedItemsFormat: '{0} items selected',
                    done: 'Done',
                    into: 'in'
                },
                forceUnique: true,
                animations: {
                    left: 'slide',
                    right: 'slide:right'
                }
            },
            events: [
                INIT,
                REFRESH,
                'change',
                OPEN
            ]
        });
        $.extend(FilterMultiCheck.fn, {
            _click: FilterMenu.fn._click,
            _keydown: FilterMenu.fn._keydown,
            _reset: FilterMenu.fn._reset,
            _closeForm: FilterMenu.fn._closeForm,
            _removeFilter: FilterMenu.fn._removeFilter,
            clear: FilterMenu.fn.clear,
            _merge: FilterMenu.fn._merge
        });
        ui.plugin(FilterMenu);
        ui.plugin(FilterMultiCheck);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.menu', [
        'kendo.popup',
        'kendo.data'
    ], f);
}(function () {
    var __meta__ = {
        id: 'menu',
        name: 'Menu',
        category: 'web',
        description: 'The Menu widget displays hierarchical data as a multi-level menu.',
        depends: [
            'popup',
            'data',
            'data.odata'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, activeElement = kendo._activeElement, touch = kendo.support.touch && kendo.support.mobileOS, isArray = $.isArray, HierarchicalDataSource = kendo.data.HierarchicalDataSource, MOUSEDOWN = 'mousedown', CLICK = 'click', DELAY = 30, SCROLLSPEED = 50, extend = $.extend, proxy = $.proxy, each = $.each, template = kendo.template, keys = kendo.keys, Widget = ui.Widget, excludedNodesRegExp = /^(ul|a|div)$/i, NS = '.kendoMenu', IMG = 'img', OPEN = 'open', MENU = 'k-menu', LINK = 'k-link k-menu-link', LINK_SELECTOR = '.k-link', ICON_SELECTOR = '.k-icon', LAST = 'k-last', CLOSE = 'close', TIMER = 'timer', FIRST = 'k-first', IMAGE = 'k-image', SELECT = 'select', ZINDEX = 'zIndex', ACTIVATE = 'activate', DEACTIVATE = 'deactivate', POINTERDOWN = 'touchstart' + NS + ' MSPointerDown' + NS + ' pointerdown' + NS, pointers = kendo.support.pointers, msPointers = kendo.support.msPointers, allPointers = msPointers || pointers, CHANGE = 'change', ERROR = 'error', TOUCHSTART = kendo.support.touch ? 'touchstart' : '', MOUSEENTER = pointers ? 'pointerover' : msPointers ? 'MSPointerOver' : 'mouseenter', MOUSELEAVE = pointers ? 'pointerout' : msPointers ? 'MSPointerOut' : 'mouseleave', MOUSEWHEEL = 'DOMMouseScroll' + NS + ' mousewheel' + NS, RESIZE = kendo.support.resize + NS, SCROLLWIDTH = 'scrollWidth', SCROLLHEIGHT = 'scrollHeight', OFFSETWIDTH = 'offsetWidth', OFFSETHEIGHT = 'offsetHeight', POPUP_ID_ATTR = 'group', POPUP_OPENER_ATTR = 'groupparent', DOCUMENT_ELEMENT = $(document.documentElement), KENDOPOPUP = 'kendoPopup', DEFAULTSTATE = 'k-state-default', HOVERSTATE = 'k-state-hover', FOCUSEDSTATE = 'k-state-focused', DISABLEDSTATE = 'k-state-disabled', SELECTEDSTATE = 'k-state-selected', menuSelector = '.k-menu', groupSelector = '.k-menu-group', animationContainerSelector = '.k-animation-container', popupSelector = groupSelector + ',' + animationContainerSelector, allItemsSelector = ':not(.k-list) > .k-item', disabledSelector = '.k-item.k-state-disabled', itemSelector = '.k-item', availableItemsSelector = '.k-item:not(.k-state-disabled)', linkSelector = '.k-item:not(.k-state-disabled) > .k-link', exclusionSelector = ':not(.k-item.k-separator)', nextSelector = itemSelector + exclusionSelector + ':eq(0)', lastSelector = itemSelector + exclusionSelector + ':last', templateSelector = 'div:not(.k-animation-container,.k-list-container)', scrollButtonSelector = '.k-menu-scroll-button', touchPointerTypes = {
                '2': 1,
                'touch': 1
            }, STRING = 'string', DATABOUND = 'dataBound', bindings = {
                text: 'dataTextField',
                url: 'dataUrlField',
                spriteCssClass: 'dataSpriteCssClassField',
                imageUrl: 'dataImageUrlField',
                imageAttr: 'dataImageAttrField',
                content: 'dataContentField'
            }, rendering = {
                wrapperCssClass: function (group, item) {
                    var result = 'k-item', index = item.index;
                    if (item.enabled === false) {
                        result += ' k-state-disabled';
                    } else {
                        result += ' k-state-default';
                    }
                    if (group.firstLevel && index === 0) {
                        result += ' k-first';
                    }
                    if (index == group.length - 1) {
                        result += ' k-last';
                    }
                    if (item.cssClass) {
                        result += ' ' + item.cssClass;
                    }
                    if (item.attr && item.attr.hasOwnProperty('class')) {
                        result += ' ' + item.attr['class'];
                    }
                    if (item.selected) {
                        result += ' ' + SELECTEDSTATE;
                    }
                    return result;
                },
                itemCssAttributes: function (item) {
                    var result = '';
                    var attributes = item.attr || {};
                    for (var attr in attributes) {
                        if (attributes.hasOwnProperty(attr) && attr !== 'class') {
                            result += attr + '="' + attributes[attr] + '" ';
                        }
                    }
                    return result;
                },
                imageCssAttributes: function (imgAttributes) {
                    var result = '';
                    var attributes = imgAttributes && imgAttributes.toJSON ? imgAttributes.toJSON() : {};
                    if (!attributes['class']) {
                        attributes['class'] = IMAGE;
                    } else {
                        attributes['class'] += ' ' + IMAGE;
                    }
                    for (var attr in attributes) {
                        if (attributes.hasOwnProperty(attr)) {
                            result += attr + '="' + attributes[attr] + '" ';
                        }
                    }
                    return result;
                },
                contentCssAttributes: function (item) {
                    var result = '';
                    var attributes = item.contentAttr || {};
                    var defaultClasses = 'k-content k-group k-menu-group';
                    if (!attributes['class']) {
                        attributes['class'] = defaultClasses;
                    } else {
                        attributes['class'] += ' ' + defaultClasses;
                    }
                    for (var attr in attributes) {
                        if (attributes.hasOwnProperty(attr)) {
                            result += attr + '="' + attributes[attr] + '" ';
                        }
                    }
                    return result;
                },
                textClass: function () {
                    return LINK;
                },
                arrowClass: function (item, group) {
                    var result = 'k-icon';
                    if (group.horizontal) {
                        result += ' k-i-arrow-60-down';
                    } else {
                        result += ' k-i-arrow-60-right';
                    }
                    return result;
                },
                groupAttributes: function (group) {
                    return group.expanded !== true ? ' style=\'display:none\'' : '';
                },
                groupCssClass: function () {
                    return 'k-group k-menu-group';
                },
                content: function (item) {
                    return item.content ? item.content : '&nbsp;';
                }
            };
        function getEffectDirection(direction, root) {
            direction = direction.split(' ')[!root + 0] || direction;
            return direction.replace('top', 'up').replace('bottom', 'down');
        }
        function parseDirection(direction, root, isRtl) {
            direction = direction.split(' ')[!root + 0] || direction;
            var output = {
                    origin: [
                        'bottom',
                        isRtl ? 'right' : 'left'
                    ],
                    position: [
                        'top',
                        isRtl ? 'right' : 'left'
                    ]
                }, horizontal = /left|right/.test(direction);
            if (horizontal) {
                output.origin = [
                    'top',
                    direction
                ];
                output.position[1] = kendo.directions[direction].reverse;
            } else {
                output.origin[0] = direction;
                output.position[0] = kendo.directions[direction].reverse;
            }
            output.origin = output.origin.join(' ');
            output.position = output.position.join(' ');
            return output;
        }
        function contains(parent, child) {
            try {
                return $.contains(parent, child);
            } catch (e) {
                return false;
            }
        }
        function updateItemClasses(item) {
            item = $(item);
            item.addClass('k-item').children(IMG).addClass(IMAGE);
            item.children('a').addClass(LINK).children(IMG).addClass(IMAGE);
            item.filter(':not([disabled])').addClass(DEFAULTSTATE);
            item.filter('.k-separator').empty().append('&nbsp;');
            item.filter('li[disabled]').addClass(DISABLEDSTATE).removeAttr('disabled').attr('aria-disabled', true);
            if (!item.filter('[role]').length) {
                item.attr('role', 'menuitem');
            }
            if (!item.children(LINK_SELECTOR).length) {
                item.contents().filter(function () {
                    return !this.nodeName.match(excludedNodesRegExp) && !(this.nodeType == 3 && !$.trim(this.nodeValue));
                }).wrapAll('<span class=\'' + LINK + '\'/>');
            }
            updateArrow(item);
            updateFirstLast(item);
        }
        function updateArrow(item) {
            item = $(item);
            item.find('> .k-link > [class*=k-i-arrow-60]:not(.k-sprite)').remove();
            item.filter(':has(.k-menu-group)').children('.k-link:not(:has([class*=k-i-arrow]:not(.k-sprite)))').each(function () {
                var item = $(this), arrowCssClass = getArrowCssClass(item);
                item.append('<span class=\'k-icon' + arrowCssClass + ' k-menu-expand-arrow\'/>');
            });
        }
        function getArrowCssClass(item) {
            var arrowCssClass, parent = item.parent().parent(), isRtl = kendo.support.isRtl(parent);
            if (parent.hasClass(MENU + '-horizontal')) {
                arrowCssClass = ' k-i-arrow-60-down';
            } else {
                if (isRtl) {
                    arrowCssClass = ' k-i-arrow-60-left';
                } else {
                    arrowCssClass = ' k-i-arrow-60-right';
                }
            }
            return arrowCssClass;
        }
        function updateFirstLast(item) {
            item = $(item);
            item.filter('.k-first:not(:first-child)').removeClass(FIRST);
            item.filter('.k-last:not(:last-child)').removeClass(LAST);
            item.filter(':first-child').addClass(FIRST);
            item.filter(':last-child').addClass(LAST);
        }
        function updateHasAriaPopup(parents) {
            if (parents && parents.length) {
                for (var index in parents) {
                    var parentLi = parents.eq(index);
                    if (parentLi.find('ul').length) {
                        parentLi.attr('aria-haspopup', true);
                    } else {
                        parentLi.removeAttr('aria-haspopup');
                    }
                }
            }
        }
        function getParentLiItems(group) {
            if (!group.hasClass(MENU)) {
                return group.parentsUntil('.' + MENU, 'li');
            }
        }
        function storeItemSelectEventHandler(element, options) {
            var selectHandler = getItemSelectEventHandler(options);
            if (selectHandler) {
                setItemData(element, selectHandler);
            }
            if (options.items) {
                $(element).children('ul').children('li').each(function (i) {
                    storeItemSelectEventHandler(this, options.items[i]);
                });
            }
        }
        function setItemData(element, selectHandler) {
            $(element).children('.k-link').data({ selectHandler: selectHandler });
        }
        function getItemSelectEventHandler(options) {
            var selectHandler = options.select, isFunction = kendo.isFunction;
            if (selectHandler && isFunction(selectHandler)) {
                return selectHandler;
            }
            return null;
        }
        function popupOpenerSelector(id) {
            return id ? 'li[data-groupparent=\'' + id + '\']' : 'li[data-groupparent]';
        }
        function popupGroupSelector(id) {
            return id ? 'ul[data-group=\'' + id + '\']' : 'ul[data-group]';
        }
        function getChildPopups(currentPopup, overflowWrapper) {
            var childPopupOpener = currentPopup.find(popupOpenerSelector());
            var result = [];
            childPopupOpener.each(function (i, opener) {
                opener = $(opener);
                var popupId = opener.data(POPUP_OPENER_ATTR);
                var popup = currentPopup;
                while (popupId) {
                    popup = overflowWrapper.find(popupGroupSelector(popupId) + ':visible');
                    if (popup.length) {
                        result.push(popup);
                    }
                    opener = popup.find(popupOpenerSelector());
                    popupId = opener.data(POPUP_OPENER_ATTR);
                }
            });
            return result;
        }
        function popupParentItem(popupElement, overflowWrapper) {
            var popupId = popupElement.data(POPUP_ID_ATTR);
            return popupId ? overflowWrapper.find(popupOpenerSelector(popupId)) : $([]);
        }
        function itemPopup(item, overflowWrapper) {
            var popupId = item.data(POPUP_OPENER_ATTR);
            return popupId ? overflowWrapper.children(animationContainerSelector).children(popupGroupSelector(popupId)) : $([]);
        }
        function overflowMenuParents(current, overflowWrapper) {
            var parents = [];
            var getParents = function (item) {
                while (item.parentNode && !overflowWrapper.is(item.parentNode)) {
                    parents.push(item.parentNode);
                    item = item.parentNode;
                }
            };
            var elem = current[0] || current;
            getParents(elem);
            var last = parents[parents.length - 1];
            while ($(last).is(animationContainerSelector)) {
                var popupElement = $(last).children('ul');
                elem = popupParentItem(popupElement, overflowWrapper)[0];
                if (!elem) {
                    break;
                }
                parents.push(elem);
                getParents(elem);
                last = parents[parents.length - 1];
            }
            return parents;
        }
        function mousewheelDelta(e) {
            var delta = 0;
            if (e.wheelDelta) {
                delta = -e.wheelDelta / 120;
                delta = delta > 0 ? Math.ceil(delta) : Math.floor(delta);
            }
            if (e.detail) {
                delta = Math.round(e.detail / 3);
            }
            return delta;
        }
        function parentsScroll(current, scrollDirection) {
            var scroll = 0;
            var parent = current.parentNode;
            while (parent && !isNaN(parent[scrollDirection])) {
                scroll += parent[scrollDirection];
                parent = parent.parentNode;
            }
            return scroll;
        }
        function isPointerTouch(e) {
            return allPointers && e.originalEvent && e.originalEvent.pointerType in touchPointerTypes;
        }
        function isTouch(e) {
            var ev = e.originalEvent;
            return touch && /touch/i.test(ev.type || '');
        }
        function removeSpacesBetweenItems(ul) {
            ul.contents().filter(function () {
                return this.nodeName != 'LI';
            }).remove();
        }
        var Menu = kendo.ui.DataBoundWidget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                element = that.wrapper = that.element;
                options = that.options;
                that._accessors();
                that._templates();
                that._dataSource();
                that._updateClasses();
                that._animations(options);
                that.nextItemZIndex = 100;
                that._tabindex();
                that._initOverflow(options);
                that._attachMenuEventsHandlers();
                if (options.openOnClick) {
                    that.clicked = false;
                }
                element.attr('role', 'menubar');
                if (element[0].id) {
                    that._ariaId = kendo.format('{0}_mn_active', element[0].id);
                }
                kendo.notify(that);
            },
            events: [
                OPEN,
                CLOSE,
                ACTIVATE,
                DEACTIVATE,
                SELECT,
                DATABOUND
            ],
            options: {
                name: 'Menu',
                animation: {
                    open: { duration: 200 },
                    close: { duration: 100 }
                },
                orientation: 'horizontal',
                direction: 'default',
                openOnClick: false,
                closeOnClick: true,
                hoverDelay: 100,
                scrollable: false,
                popupCollision: undefined
            },
            _initData: function () {
                var that = this;
                if (that.dataSource) {
                    that.angular('cleanup', function () {
                        return { elements: that.element.children() };
                    });
                    that.element.empty();
                    that.append(that.dataSource.view(), that.element);
                    that.angular('compile', function () {
                        return { elements: that.element.children() };
                    });
                }
            },
            _attachMenuEventsHandlers: function () {
                var that = this;
                var element = that.element;
                var options = that.options;
                var overflowWrapper = that._overflowWrapper();
                (overflowWrapper || element).on(POINTERDOWN, itemSelector, proxy(that._focusHandler, that)).on(CLICK + NS, disabledSelector, false).on(CLICK + NS, itemSelector, proxy(that._click, that)).on(POINTERDOWN + ' ' + MOUSEDOWN + NS, '.k-content', proxy(that._preventClose, that)).on(MOUSEENTER + NS, availableItemsSelector, proxy(that._mouseenter, that)).on(MOUSELEAVE + NS, availableItemsSelector, proxy(that._mouseleave, that)).on(MOUSEDOWN + NS, availableItemsSelector, proxy(that._mousedown, that)).on(TOUCHSTART + NS + ' ' + MOUSEENTER + NS + ' ' + MOUSELEAVE + NS + ' ' + MOUSEDOWN + NS + ' ' + CLICK + NS, linkSelector, proxy(that._toggleHover, that));
                element.on('keydown' + NS, proxy(that._keydown, that)).on('focus' + NS, proxy(that._focus, that)).on('focus' + NS, '.k-content', proxy(that._focus, that)).on('blur' + NS, proxy(that._removeHoverItem, that)).on('blur' + NS, '[tabindex]', proxy(that._checkActiveElement, that));
                if (overflowWrapper) {
                    overflowWrapper.on(MOUSELEAVE + NS, popupSelector, proxy(that._mouseleavePopup, that)).on(MOUSEENTER + NS, popupSelector, proxy(that._mouseenterPopup, that));
                }
                if (options.openOnClick) {
                    that._documentClickHandler = proxy(that._documentClick, that);
                    $(document).click(that._documentClickHandler);
                }
            },
            _detachMenuEventsHandlers: function () {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                if (overflowWrapper) {
                    overflowWrapper.off(NS);
                }
                that.element.off(NS);
                if (that._documentClickHandler) {
                    $(document).unbind('click', that._documentClickHandler);
                }
            },
            _initOverflow: function (options) {
                var that = this;
                var isHorizontal = options.orientation == 'horizontal';
                var backwardBtn, forwardBtn;
                if (options.scrollable) {
                    that._openedPopups = {};
                    that._scrollWrapper = that.element.wrap('<div class=\'k-menu-scroll-wrapper ' + options.orientation + '\'></div>').parent();
                    if (isHorizontal) {
                        removeSpacesBetweenItems(that.element);
                    }
                    backwardBtn = $(that.templates.scrollButton({ direction: isHorizontal ? 'left' : 'up' }));
                    forwardBtn = $(that.templates.scrollButton({ direction: isHorizontal ? 'right' : 'down' }));
                    backwardBtn.add(forwardBtn).appendTo(that._scrollWrapper);
                    that._initScrolling(that.element, backwardBtn, forwardBtn, isHorizontal);
                    var initialWidth = that.element.outerWidth();
                    var initialCssWidth = that.element[0].style.width;
                    initialCssWidth = initialCssWidth === 'auto' ? '' : initialCssWidth;
                    if (isHorizontal) {
                        $(window).on(RESIZE, kendo.throttle(function () {
                            that._setOverflowWrapperWidth(initialWidth, initialCssWidth);
                            that._toggleScrollButtons(that.element, backwardBtn, forwardBtn, isHorizontal);
                        }, 100));
                    }
                    that._setOverflowWrapperWidth(initialWidth, initialCssWidth);
                    that._toggleScrollButtons(that.element, backwardBtn, forwardBtn, isHorizontal);
                }
            },
            _overflowWrapper: function () {
                return this._scrollWrapper || this._popupsWrapper;
            },
            _setOverflowWrapperWidth: function (initialWidth, initialCssWidth) {
                var that = this;
                var wrapperCssWidth = that._scrollWrapper.css('width');
                that._scrollWrapper.css({ width: '' });
                var wrapperWidth = that._scrollWrapper.outerWidth();
                that._scrollWrapper.css({ width: wrapperCssWidth });
                var menuWidth = that.element.outerWidth();
                var borders = that.element[0].offsetWidth - that.element[0].clientWidth;
                if (menuWidth != wrapperWidth && wrapperWidth > 0) {
                    var width = initialCssWidth ? Math.min(initialWidth, wrapperWidth) : wrapperWidth;
                    that.element.width(width - borders);
                    that._scrollWrapper.width(width);
                }
            },
            _reinitOverflow: function (options) {
                var that = this;
                var overflowChanged = options.scrollable && !that.options.scrollable || !options.scrollable && that.options.scrollable || options.scrollable && that.options.scrollable && options.scrollable.distance != that.options.scrollable.distance || options.orientation != that.options.orientation;
                if (overflowChanged) {
                    that._detachMenuEventsHandlers();
                    that._destroyOverflow();
                    that._initOverflow(options);
                    that._attachMenuEventsHandlers();
                }
            },
            _destroyOverflow: function () {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                if (overflowWrapper) {
                    overflowWrapper.off(NS);
                    overflowWrapper.find(scrollButtonSelector).off(NS).remove();
                    overflowWrapper.children(animationContainerSelector).each(function (i, popupWrapper) {
                        var ul = $(popupWrapper).children(groupSelector);
                        ul.off(MOUSEWHEEL);
                        var popupParentLi = popupParentItem(ul, overflowWrapper);
                        if (popupParentLi.length) {
                            popupParentLi.append(popupWrapper);
                        }
                    });
                    overflowWrapper.find(popupOpenerSelector()).removeAttr('data-groupparent');
                    overflowWrapper.find(popupGroupSelector()).removeAttr('data-group');
                    that.element.off(MOUSEWHEEL);
                    $(window).off(RESIZE);
                    overflowWrapper.contents().unwrap();
                    that._scrollWrapper = that._popupsWrapper = that._openedPopups = undefined;
                }
            },
            _initScrolling: function (scrollElement, backwardBtn, forwardBtn, isHorizontal) {
                var that = this;
                var scrollable = that.options.scrollable;
                var distance = $.isNumeric(scrollable.distance) ? scrollable.distance : SCROLLSPEED;
                var mouseWheelDistance = distance / 2;
                var backward = '-=' + distance;
                var forward = '+=' + distance;
                var backwardDouble = '-=' + distance * 2;
                var forwardDouble = '+=' + distance * 2;
                var scrolling = false;
                var touchEvents = false;
                var scroll = function (value) {
                    var scrollValue = isHorizontal ? { 'scrollLeft': value } : { 'scrollTop': value };
                    scrollElement.finish().animate(scrollValue, 'fast', 'linear', function () {
                        if (scrolling) {
                            scroll(value);
                        }
                    });
                    that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal);
                };
                var mouseenterHandler = function (e) {
                    if (!scrolling && !touchEvents) {
                        scroll(e.data.direction);
                        scrolling = true;
                    }
                };
                var mousedownHandler = function (e) {
                    var scrollValue = isHorizontal ? { 'scrollLeft': e.data.direction } : { 'scrollTop': e.data.direction };
                    touchEvents = isTouch(e) || isPointerTouch(e);
                    scrollElement.stop().animate(scrollValue, 'fast', 'linear', function () {
                        if (!touchEvents) {
                            $(e.currentTarget).trigger(MOUSEENTER);
                        } else {
                            that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal);
                            scrolling = true;
                        }
                    });
                    scrolling = false;
                    e.stopPropagation();
                    e.preventDefault();
                };
                backwardBtn.on(MOUSEENTER + NS, { direction: backward }, mouseenterHandler).on(kendo.eventMap.down + NS, { direction: backwardDouble }, mousedownHandler);
                forwardBtn.on(MOUSEENTER + NS, { direction: forward }, mouseenterHandler).on(kendo.eventMap.down + NS, { direction: forwardDouble }, mousedownHandler);
                backwardBtn.add(forwardBtn).on(MOUSELEAVE + NS, function () {
                    scrollElement.stop();
                    scrolling = false;
                    that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal);
                });
                scrollElement.on(MOUSEWHEEL, function (e) {
                    if (!e.ctrlKey && !e.shiftKey && !e.altKey) {
                        var wheelDelta = mousewheelDelta(e.originalEvent);
                        var scrollSpeed = Math.abs(wheelDelta) * mouseWheelDistance;
                        var value = (wheelDelta > 0 ? '+=' : '-=') + scrollSpeed;
                        var scrollValue = isHorizontal ? { 'scrollLeft': value } : { 'scrollTop': value };
                        that._closeChildPopups(scrollElement);
                        scrollElement.finish().animate(scrollValue, 'fast', 'linear', function () {
                            that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal);
                        });
                        e.preventDefault();
                    }
                });
            },
            _toggleScrollButtons: function (scrollElement, backwardBtn, forwardBtn, horizontal) {
                var currentScroll = horizontal ? scrollElement.scrollLeft() : scrollElement.scrollTop();
                var scrollSize = horizontal ? SCROLLWIDTH : SCROLLHEIGHT;
                var offset = horizontal ? OFFSETWIDTH : OFFSETHEIGHT;
                backwardBtn.toggle(currentScroll !== 0);
                forwardBtn.toggle(currentScroll < scrollElement[0][scrollSize] - scrollElement[0][offset] - 1);
            },
            setOptions: function (options) {
                var animation = this.options.animation;
                this._animations(options);
                options.animation = extend(true, animation, options.animation);
                if ('dataSource' in options) {
                    this._dataSource(options);
                }
                this._updateClasses();
                this._reinitOverflow(options);
                Widget.fn.setOptions.call(this, options);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that._detachMenuEventsHandlers();
                that._destroyOverflow();
                kendo.destroy(that.element);
            },
            enable: function (element, enable) {
                this._toggleDisabled(element, enable !== false);
                return this;
            },
            disable: function (element) {
                this._toggleDisabled(element, false);
                return this;
            },
            attemptGetItem: function (candidate) {
                candidate = candidate || this.element;
                var item = this.element.find(candidate);
                var overflowWrapper = this._overflowWrapper();
                if (item.length || candidate === this.element) {
                    return item;
                } else if (overflowWrapper) {
                    return overflowWrapper.find(candidate);
                } else {
                    return $();
                }
            },
            append: function (item, referenceItem) {
                referenceItem = this.attemptGetItem(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.length ? referenceItem.find('> .k-menu-group, > .k-animation-container > .k-menu-group') : null);
                each(inserted.items, function (i) {
                    inserted.group.append(this);
                    updateArrow(this);
                    storeItemSelectEventHandler(this, item[i] || item);
                });
                updateArrow(referenceItem);
                updateFirstLast(inserted.group.find('.k-first, .k-last').add(inserted.items));
                updateHasAriaPopup(getParentLiItems(inserted.group));
                return this;
            },
            insertBefore: function (item, referenceItem) {
                referenceItem = this.attemptGetItem(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.parent());
                each(inserted.items, function (i) {
                    referenceItem.before(this);
                    updateArrow(this);
                    updateFirstLast(this);
                    storeItemSelectEventHandler(this, item[i] || item);
                });
                updateFirstLast(referenceItem);
                return this;
            },
            insertAfter: function (item, referenceItem) {
                referenceItem = this.attemptGetItem(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.parent());
                each(inserted.items, function (i) {
                    referenceItem.after(this);
                    updateArrow(this);
                    updateFirstLast(this);
                    storeItemSelectEventHandler(this, item[i] || item);
                });
                updateFirstLast(referenceItem);
                return this;
            },
            _insert: function (item, referenceItem, parent) {
                var that = this, items, groups;
                if (!referenceItem || !referenceItem.length) {
                    parent = that.element;
                }
                var plain = $.isPlainObject(item) || item instanceof kendo.data.ObservableObject, groupData = {
                        firstLevel: parent.hasClass(MENU),
                        horizontal: parent.hasClass(MENU + '-horizontal'),
                        expanded: true,
                        length: parent.children().length
                    };
                if (referenceItem && !parent.length) {
                    parent = $(that.renderGroup({
                        group: groupData,
                        options: that.options
                    })).appendTo(referenceItem);
                }
                if (plain || isArray(item) || item instanceof kendo.data.ObservableArray) {
                    items = $($.map(plain ? [item] : item, function (value, idx) {
                        if (typeof value === 'string') {
                            return $(value).get();
                        } else {
                            return $(that.renderItem({
                                group: groupData,
                                item: extend(value, { index: idx })
                            })).get();
                        }
                    }));
                } else {
                    if (typeof item == 'string' && item.charAt(0) != '<') {
                        items = that.element.find(item);
                    } else {
                        items = $(item);
                    }
                    groups = items.find('> ul').addClass('k-menu-group').attr('role', 'menu');
                    items = items.filter('li');
                    items.add(groups.find('> li')).each(function () {
                        updateItemClasses(this);
                    });
                }
                return {
                    items: items,
                    group: parent
                };
            },
            remove: function (element) {
                element = this.attemptGetItem(element);
                var that = this, parent = element.parentsUntil(that.element, allItemsSelector), group = element.parent('ul:not(.k-menu)');
                element.remove();
                if (group && !group.children(allItemsSelector).length) {
                    var parentItems = getParentLiItems(group);
                    var container = group.parent(animationContainerSelector);
                    if (container.length) {
                        container.remove();
                    } else {
                        group.remove();
                    }
                    updateHasAriaPopup(parentItems);
                }
                if (parent.length) {
                    parent = parent.eq(0);
                    updateArrow(parent);
                    updateFirstLast(parent);
                }
                return that;
            },
            _openAfterLoad: function (element, dataItem) {
                var that = this;
                if (dataItem.loaded()) {
                    that.open(element);
                    that._loading = false;
                } else {
                    dataItem.one(CHANGE, function () {
                        element.find(ICON_SELECTOR).removeClass('k-i-loading');
                        if (that._loading) {
                            that.open(element);
                            that._loading = false;
                        }
                    });
                }
            },
            open: function (element) {
                var that = this;
                var options = that.options;
                var horizontal = options.orientation == 'horizontal';
                var direction = options.direction;
                var isRtl = kendo.support.isRtl(that.wrapper);
                var overflowWrapper = that._overflowWrapper();
                element = (overflowWrapper || that.element).find(element);
                var dataItem = that.dataSource && that.dataSource.getByUid(element.data('uid'));
                if (dataItem && dataItem.hasChildren && !dataItem.loaded() && !that._loading) {
                    that._loading = true;
                    element.find(ICON_SELECTOR).addClass('k-i-loading');
                    dataItem.load();
                    that._openAfterLoad(element, dataItem);
                    return;
                }
                if (/^(top|bottom|default)$/.test(direction)) {
                    if (isRtl) {
                        direction = horizontal ? (direction + ' left').replace('default', 'bottom') : 'left';
                    } else {
                        direction = horizontal ? (direction + ' right').replace('default', 'bottom') : 'right';
                    }
                }
                var visiblePopups = '>.k-popup:visible,>.k-animation-container>.k-popup:visible';
                var closePopup = function () {
                    var popup = $(this).data(KENDOPOPUP);
                    if (popup) {
                        that.close($(this).closest('li.k-item'), true);
                    }
                };
                element.siblings().find(visiblePopups).each(closePopup);
                if (overflowWrapper) {
                    element.find(visiblePopups).each(closePopup);
                }
                if (that.options.openOnClick) {
                    that.clicked = true;
                }
                element.each(function () {
                    var li = $(this);
                    clearTimeout(li.data(TIMER));
                    li.data(TIMER, setTimeout(function () {
                        var ul = li.find('.k-menu-group:first:hidden');
                        var popup;
                        var overflowPopup;
                        if (!ul[0] && overflowWrapper) {
                            overflowPopup = that._getPopup(li);
                            ul = overflowPopup && overflowPopup.element;
                        }
                        if (ul.is(':visible')) {
                            return;
                        }
                        if (ul[0] && that._triggerEvent({
                                item: li[0],
                                type: OPEN
                            }) === false) {
                            if (!ul.find('.k-menu-group')[0] && ul.children('.k-item').length > 1) {
                                var windowHeight = $(window).height(), setScrolling = function () {
                                        ul.css({
                                            maxHeight: windowHeight - (kendo._outerHeight(ul) - ul.height()) - kendo.getShadows(ul).bottom,
                                            overflow: 'auto'
                                        });
                                    };
                                if (kendo.support.browser.msie && kendo.support.browser.version <= 7) {
                                    setTimeout(setScrolling, 0);
                                } else {
                                    setScrolling();
                                }
                            } else {
                                ul.css({
                                    maxHeight: '',
                                    overflow: ''
                                });
                            }
                            li.data(ZINDEX, li.css(ZINDEX));
                            var nextZindex = that.nextItemZIndex++;
                            li.css(ZINDEX, nextZindex);
                            if (that.options.scrollable) {
                                li.parent().siblings(scrollButtonSelector).css({ zIndex: ++nextZindex });
                            }
                            popup = ul.data(KENDOPOPUP);
                            var root = li.parent().hasClass(MENU), parentHorizontal = root && horizontal, directions = parseDirection(direction, root, isRtl), effects = options.animation.open.effects, openEffects = effects !== undefined ? effects : 'slideIn:' + getEffectDirection(direction, root);
                            if (!popup) {
                                popup = ul.kendoPopup({
                                    activate: function () {
                                        that._triggerEvent({
                                            item: this.wrapper.parent(),
                                            type: ACTIVATE
                                        });
                                    },
                                    deactivate: function (e) {
                                        that._closing = false;
                                        e.sender.element.removeData('targetTransform').css({ opacity: '' });
                                        that._triggerEvent({
                                            item: this.wrapper.parent(),
                                            type: DEACTIVATE
                                        });
                                    },
                                    origin: directions.origin,
                                    position: directions.position,
                                    collision: options.popupCollision !== undefined ? options.popupCollision : parentHorizontal ? 'fit' : 'fit flip',
                                    anchor: li,
                                    appendTo: overflowWrapper || li,
                                    animation: {
                                        open: extend(true, { effects: openEffects }, options.animation.open),
                                        close: options.animation.close
                                    },
                                    open: proxy(that._popupOpen, that),
                                    close: function (e) {
                                        that._closing = true;
                                        var li = e.sender.wrapper.parent();
                                        if (overflowWrapper) {
                                            var popupId = e.sender.element.data(POPUP_ID_ATTR);
                                            if (popupId) {
                                                li = (overflowWrapper || that.element).find(popupOpenerSelector(popupId));
                                            }
                                            e.sender.wrapper.children(scrollButtonSelector).hide();
                                        }
                                        if (!that._triggerEvent({
                                                item: li[0],
                                                type: CLOSE
                                            })) {
                                            li.css(ZINDEX, li.data(ZINDEX));
                                            li.removeData(ZINDEX);
                                            if (that.options.scrollable) {
                                                li.parent().siblings(scrollButtonSelector).css({ zIndex: '' });
                                            }
                                            if (touch || allPointers || kendo.support.mouseAndTouchPresent) {
                                                li.removeClass(HOVERSTATE);
                                                that._removeHoverItem();
                                            }
                                        } else {
                                            e.preventDefault();
                                        }
                                    }
                                }).data(KENDOPOPUP);
                            } else {
                                popup = ul.data(KENDOPOPUP);
                                popup.options.origin = directions.origin;
                                popup.options.position = directions.position;
                                popup.options.animation.open.effects = openEffects;
                            }
                            ul.removeAttr('aria-hidden');
                            that._configurePopupOverflow(popup, li);
                            popup._hovered = true;
                            popup.open();
                            that._initPopupScrolling(popup);
                        }
                    }, that.options.hoverDelay));
                });
                return that;
            },
            _configurePopupOverflow: function (popup, popupOpener) {
                var that = this;
                if (that.options.scrollable) {
                    that._wrapPopupElement(popup);
                    if (!popupOpener.attr('data-groupparent')) {
                        var groupId = new Date().getTime();
                        popupOpener.attr('data-groupparent', groupId);
                        popup.element.attr('data-group', groupId);
                    }
                }
            },
            _wrapPopupElement: function (popup) {
                if (!popup.element.parent().is(animationContainerSelector)) {
                    popup.wrapper = kendo.wrap(popup.element, popup.options.autosize).css({
                        overflow: 'hidden',
                        display: 'block',
                        position: 'absolute'
                    });
                }
            },
            _initPopupScrolling: function (popup, isHorizontal, skipMouseEvents) {
                var that = this;
                if (that.options.scrollable && popup.element[0].scrollHeight > popup.element[0].offsetHeight) {
                    that._initPopupScrollButtons(popup, isHorizontal, skipMouseEvents);
                }
            },
            _initPopupScrollButtons: function (popup, isHorizontal, skipMouseEvents) {
                var that = this;
                var scrollButtons = popup.wrapper.children(scrollButtonSelector);
                var animation = that.options.animation;
                var timeout = (animation && animation.open && animation.open.duration || 0) + DELAY;
                setTimeout(function () {
                    if (!scrollButtons.length) {
                        var backwardBtn = $(that.templates.scrollButton({ direction: isHorizontal ? 'left' : 'up' }));
                        var forwardBtn = $(that.templates.scrollButton({ direction: isHorizontal ? 'right' : 'down' }));
                        scrollButtons = backwardBtn.add(forwardBtn).appendTo(popup.wrapper);
                        that._initScrolling(popup.element, backwardBtn, forwardBtn, isHorizontal);
                        if (!skipMouseEvents) {
                            scrollButtons.on(MOUSEENTER + NS, function () {
                                var overflowWrapper = that._overflowWrapper();
                                $(getChildPopups(popup.element, overflowWrapper)).each(function (i, p) {
                                    var popupOpener = overflowWrapper.find(popupOpenerSelector(p.data(POPUP_ID_ATTR)));
                                    that.close(popupOpener);
                                });
                            }).on(MOUSELEAVE + NS, function () {
                                setTimeout(function () {
                                    if ($.isEmptyObject(that._openedPopups)) {
                                        that._closeParentPopups(popup.element);
                                    }
                                }, DELAY);
                            });
                        }
                    }
                    that._toggleScrollButtons(popup.element, scrollButtons.first(), scrollButtons.last(), isHorizontal);
                }, timeout);
            },
            _popupOpen: function (e) {
                if (!this._keyTriggered) {
                    e.sender.element.children('.' + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
                }
                if (this.options.scrollable) {
                    this._setPopupHeight(e.sender);
                }
            },
            _setPopupHeight: function (popup, isFixed) {
                var popupElement = popup.element;
                var popups = popupElement.add(popupElement.parent(animationContainerSelector));
                popups.height(popupElement.hasClass(MENU) && this._initialHeight || '');
                var location = popup._location(isFixed);
                var windowHeight = $(window).height();
                var popupOuterHeight = location.height;
                var popupOffsetTop = isFixed ? 0 : Math.max(location.top, 0);
                var scrollTop = isFixed ? 0 : parentsScroll(this._overflowWrapper()[0], 'scrollTop');
                var bottomScrollbar = window.innerHeight - windowHeight;
                var maxHeight = windowHeight - kendo.getShadows(popupElement).bottom + bottomScrollbar;
                var canFit = maxHeight + scrollTop > popupOuterHeight + popupOffsetTop;
                if (!canFit) {
                    var height = Math.min(maxHeight, maxHeight - popupOffsetTop + scrollTop);
                    popups.css({
                        overflow: 'hidden',
                        height: height + 'px'
                    });
                }
            },
            close: function (items, dontClearClose) {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                var element = overflowWrapper || that.element;
                items = element.find(items);
                if (!items.length) {
                    items = element.find('>.k-item');
                }
                var hasChildPopupsHovered = function (currentPopup) {
                    var result = false;
                    if ($.isEmptyObject(that._openedPopups)) {
                        return result;
                    }
                    $(getChildPopups(currentPopup, overflowWrapper)).each(function (i, popup) {
                        result = !!that._openedPopups[popup.data(POPUP_ID_ATTR).toString()];
                        return !result;
                    });
                    return result;
                };
                var isPopupMouseLeaved = function (opener) {
                    var groupId = opener.data(POPUP_OPENER_ATTR);
                    return !overflowWrapper || !groupId || !that._openedPopups[groupId.toString()];
                };
                items.each(function () {
                    var li = $(this);
                    if (!dontClearClose && that._isRootItem(li)) {
                        that.clicked = false;
                    }
                    clearTimeout(li.data(TIMER));
                    li.data(TIMER, setTimeout(function () {
                        var popup = that._getPopup(li);
                        if (popup && (isPopupMouseLeaved(li) || that._forceClose)) {
                            if (!that._forceClose && hasChildPopupsHovered(popup.element)) {
                                return;
                            }
                            popup.close();
                            popup.element.attr('aria-hidden', true);
                            if (overflowWrapper) {
                                if (that._forceClose && items.last().is(li[0])) {
                                    delete that._forceClose;
                                }
                            }
                        }
                    }, that.options.hoverDelay));
                });
                return that;
            },
            _getPopup: function (li) {
                var that = this;
                var popup = li.find('.k-menu-group:not(.k-list-container):not(.k-calendar-container):first:visible').data(KENDOPOPUP);
                var overflowWrapper = that._overflowWrapper();
                if (!popup && overflowWrapper) {
                    var groupId = li.data(POPUP_OPENER_ATTR);
                    if (groupId) {
                        var popupElement = overflowWrapper.find(popupGroupSelector(groupId));
                        popup = popupElement.data(KENDOPOPUP);
                    }
                }
                return popup;
            },
            _toggleDisabled: function (items, enable) {
                this.element.find(items).each(function () {
                    $(this).toggleClass(DEFAULTSTATE, enable).toggleClass(DISABLEDSTATE, !enable).attr('aria-disabled', !enable);
                });
            },
            _toggleHover: function (e) {
                var target = $(kendo.eventTarget(e) || e.target).closest(allItemsSelector), isEnter = e.type == MOUSEENTER || MOUSEDOWN.indexOf(e.type) !== -1;
                target.siblings().removeClass(HOVERSTATE);
                if (!target.parents('li.' + DISABLEDSTATE).length) {
                    target.toggleClass(HOVERSTATE, isEnter || e.type == 'mousedown' || e.type == 'pointerover' || e.type == TOUCHSTART);
                }
                this._removeHoverItem();
            },
            _preventClose: function () {
                if (!this.options.closeOnClick) {
                    this._closurePrevented = true;
                }
            },
            _checkActiveElement: function (e) {
                var that = this, hoverItem = $(e ? e.currentTarget : this._hoverItem()), target = that._findRootParent(hoverItem)[0];
                if (!this._closurePrevented) {
                    setTimeout(function () {
                        if (!document.hasFocus() || !contains(target, kendo._activeElement()) && e && !contains(target, e.currentTarget)) {
                            that.close(target);
                        }
                    }, 0);
                }
                this._closurePrevented = false;
            },
            _removeHoverItem: function () {
                var oldHoverItem = this._hoverItem();
                if (oldHoverItem && oldHoverItem.hasClass(FOCUSEDSTATE)) {
                    oldHoverItem.removeClass(FOCUSEDSTATE);
                    this._oldHoverItem = null;
                }
            },
            _updateClasses: function () {
                var element = this.element, nonContentGroupsSelector = '.k-menu-init div ul', items;
                element.removeClass('k-menu-horizontal k-menu-vertical');
                element.addClass('k-widget k-reset k-header k-menu-init ' + MENU).addClass(MENU + '-' + this.options.orientation);
                element.find('li > ul').filter(function () {
                    return !kendo.support.matchesSelector.call(this, nonContentGroupsSelector);
                }).addClass('k-group k-menu-group').attr('role', 'menu').attr('aria-hidden', element.is(':visible')).parent('li').attr('aria-haspopup', 'true').end().find('li > div').addClass('k-content').attr('tabindex', '-1');
                items = element.find('> li,.k-menu-group > li');
                element.removeClass('k-menu-init');
                items.each(function () {
                    updateItemClasses(this);
                });
            },
            _mouseenter: function (e) {
                var that = this;
                var element = $(e.currentTarget);
                var hasChildren = that._itemHasChildren(element);
                var popupId = element.data(POPUP_OPENER_ATTR) || element.parent().data(POPUP_ID_ATTR);
                var pointerTouch = isPointerTouch(e);
                if (popupId) {
                    that._openedPopups[popupId.toString()] = true;
                }
                if (that._closing || e.delegateTarget != element.parents(menuSelector)[0] && e.delegateTarget != element.parents('.k-menu-scroll-wrapper,.k-popups-wrapper')[0]) {
                    return;
                }
                that._keyTriggered = false;
                if (that.options.openOnClick.rootMenuItems && that._isRootItem(element.closest(allItemsSelector)) || that.options.openOnClick.subMenuItems && !that._isRootItem(element.closest(allItemsSelector))) {
                    return;
                }
                if ((that.options.openOnClick === false || that.options.openOnClick.rootMenuItems === false && that._isRootItem(element.closest(allItemsSelector)) || that.options.openOnClick.subMenuItems === false && !that._isRootItem(element.closest(allItemsSelector)) || that.clicked) && !touch && !(pointerTouch && that._isRootItem(element.closest(allItemsSelector)))) {
                    if (!contains(e.currentTarget, e.relatedTarget) && hasChildren) {
                        that.open(element);
                    }
                }
                if (that.options.openOnClick === true && that.clicked || touch) {
                    element.siblings().each(proxy(function (_, sibling) {
                        that.close(sibling, true);
                    }, that));
                }
            },
            _mousedown: function (e) {
                var that = this;
                var element = $(e.currentTarget);
                if (that.options.openOnClick.subMenuItems && !that._isRootItem(element) || touch) {
                    element.siblings().each(proxy(function (_, sibling) {
                        that.close(sibling, true);
                    }, that));
                }
            },
            _mouseleave: function (e) {
                var that = this;
                var element = $(e.currentTarget);
                var popupOpener = element.data(POPUP_OPENER_ATTR);
                var hasChildren = element.children(animationContainerSelector).length || element.children(groupSelector).length || popupOpener;
                var $window = $(window);
                if (popupOpener) {
                    delete that._openedPopups[popupOpener.toString()];
                }
                if (element.parentsUntil(animationContainerSelector, '.k-list-container,.k-calendar-container')[0]) {
                    e.stopImmediatePropagation();
                    return;
                }
                if ((that.options.openOnClick === false || !that.options.openOnClick.rootMenuItems && that._isRootItem(element) || !that.options.openOnClick.subMenuItems && !that._isRootItem(element)) && !touch && !isPointerTouch(e) && !contains(e.currentTarget, e.relatedTarget || e.target) && hasChildren && !contains(e.currentTarget, kendo._activeElement())) {
                    that.close(element, true);
                    that._loading = false;
                    return;
                }
                if (kendo.support.browser.msie && !e.toElement && !e.relatedTarget && !isPointerTouch(e) || e.clientX < 0 || e.clientY < 0 || e.clientY > $window.height() || e.clientX > $window.width()) {
                    that.close(element);
                }
            },
            _mouseenterPopup: function (e) {
                var that = this;
                var popupElement = $(e.currentTarget);
                if (popupElement.parent().is(animationContainerSelector)) {
                    return;
                }
                popupElement = popupElement.children('ul');
                var popupId = popupElement.data(POPUP_ID_ATTR);
                if (popupId) {
                    that._openedPopups[popupId.toString()] = true;
                }
            },
            _mouseleavePopup: function (e) {
                var that = this;
                var popupElement = $(e.currentTarget);
                if (!isPointerTouch(e) && popupElement.is(animationContainerSelector)) {
                    that._closePopups(popupElement.children('ul'));
                }
            },
            _closePopups: function (rootPopup) {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                var popupId = rootPopup.data(POPUP_ID_ATTR);
                if (popupId) {
                    delete that._openedPopups[popupId.toString()];
                    var groupParent = overflowWrapper.find(popupOpenerSelector(popupId));
                    setTimeout(function () {
                        if (that.options.openOnClick) {
                            that._closeChildPopups(rootPopup);
                        } else {
                            if ($.isEmptyObject(that._openedPopups)) {
                                var innerPopup = that._innerPopup(rootPopup);
                                that._closeParentPopups(innerPopup);
                            } else {
                                that.close(groupParent, true);
                            }
                        }
                    }, 0);
                }
            },
            _closeChildPopups: function (current) {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                $(getChildPopups(current, overflowWrapper)).each(function () {
                    var popupOpener = overflowWrapper.find(popupOpenerSelector(this.data(POPUP_ID_ATTR)));
                    that.close(popupOpener, true);
                });
            },
            _innerPopup: function (current) {
                var overflowWrapper = this._overflowWrapper();
                var popups = getChildPopups(current, overflowWrapper);
                return popups[popups.length - 1] || current;
            },
            _closeParentPopups: function (current) {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                var popupId = current.data(POPUP_ID_ATTR);
                var popupOpener = overflowWrapper.find(popupOpenerSelector(popupId));
                popupId = popupOpener.parent().data(POPUP_ID_ATTR);
                that.close(popupOpener, true);
                while (popupId && !that._openedPopups[popupId]) {
                    if (popupOpener.parent().is(menuSelector)) {
                        break;
                    }
                    popupOpener = overflowWrapper.find(popupOpenerSelector(popupId));
                    that.close(popupOpener, true);
                    popupId = popupOpener.parent().data(POPUP_ID_ATTR);
                }
            },
            _click: function (e) {
                var that = this, openHandle, options = that.options, target = $(kendo.eventTarget(e)), targetElement = target[0], nodeName = target[0] ? target[0].nodeName.toUpperCase() : '', formNode = nodeName == 'INPUT' || nodeName == 'SELECT' || nodeName == 'BUTTON' || nodeName == 'LABEL', link = target.closest(LINK_SELECTOR), element = target.closest(allItemsSelector), itemElement = element[0], href = link.attr('href'), childGroup, childGroupVisible, targetHref = target.attr('href'), sampleHref = $('<a href=\'#\' />').attr('href'), isLink = !!href && href !== sampleHref, isLocalLink = isLink && !!href.match(/^#/), isTargetLink = !!targetHref && targetHref !== sampleHref, overflowWrapper = that._overflowWrapper(), shouldCloseTheRootItem;
                while (targetElement && targetElement.parentNode != itemElement) {
                    targetElement = targetElement.parentNode;
                }
                if ($(targetElement).is(templateSelector)) {
                    return;
                }
                if (element.hasClass(DISABLEDSTATE)) {
                    e.preventDefault();
                    return;
                }
                if (!e.handled && that._triggerSelect(target, itemElement) && !formNode) {
                    e.preventDefault();
                }
                e.handled = true;
                childGroup = element.children(popupSelector);
                if (overflowWrapper) {
                    var childPopupId = element.data(POPUP_OPENER_ATTR);
                    if (childPopupId) {
                        childGroup = overflowWrapper.find(popupGroupSelector(childPopupId));
                    }
                }
                childGroupVisible = childGroup.is(':visible');
                shouldCloseTheRootItem = options.openOnClick && childGroupVisible && that._isRootItem(element);
                if (options.closeOnClick && (!isLink || isLocalLink) && (!childGroup.length || shouldCloseTheRootItem)) {
                    element.removeClass(HOVERSTATE).css('height');
                    that._oldHoverItem = that._findRootParent(element);
                    var item = that._parentsUntil(link, that.element, allItemsSelector);
                    that._forceClose = !!overflowWrapper;
                    that.close(item);
                    that.clicked = false;
                    if ('MSPointerUp'.indexOf(e.type) != -1) {
                        e.preventDefault();
                    }
                    return;
                }
                if (isLink && e.enterKey) {
                    link[0].click();
                }
                if ((!that._isRootItem(element) || options.openOnClick === false) && !options.openOnClick.subMenuItems && !kendo.support.touch && !(isPointerTouch(e) && that._isRootItem(element.closest(allItemsSelector)))) {
                    return;
                }
                if (!isLink && !formNode && !isTargetLink) {
                    e.preventDefault();
                }
                that.clicked = true;
                openHandle = childGroup.is(':visible') ? CLOSE : OPEN;
                if (!options.closeOnClick && openHandle == CLOSE) {
                    return;
                }
                that[openHandle](element);
            },
            _parentsUntil: function (context, top, selector) {
                var overflowWrapper = this._overflowWrapper();
                if (!overflowWrapper) {
                    return context.parentsUntil(top, selector);
                } else {
                    var parents = overflowMenuParents(context, overflowWrapper);
                    var result = [];
                    $(parents).each(function () {
                        var parent = $(this);
                        if (parent.is(top)) {
                            return false;
                        }
                        if (parent.is(selector)) {
                            result.push(this);
                        }
                    });
                    return $(result);
                }
            },
            _triggerSelect: function (target, itemElement) {
                target = target.is('.k-link') ? target : target.closest('.k-link');
                var selectHandler = target.data('selectHandler'), itemSelectEventData;
                if (selectHandler) {
                    itemSelectEventData = this._getEventData(target);
                    selectHandler.call(this, itemSelectEventData);
                }
                var isSelectItemDefaultPrevented = itemSelectEventData && itemSelectEventData.isDefaultPrevented();
                var isSelectDefaultPrevented = this._triggerEvent({
                    item: itemElement,
                    type: SELECT
                });
                return isSelectItemDefaultPrevented || isSelectDefaultPrevented;
            },
            _getEventData: function (target) {
                var eventData = {
                    sender: this,
                    target: target,
                    _defaultPrevented: false,
                    preventDefault: function () {
                        this._defaultPrevented = true;
                    },
                    isDefaultPrevented: function () {
                        return this._defaultPrevented;
                    }
                };
                return eventData;
            },
            _documentClick: function (e) {
                var that = this;
                if (contains((that._overflowWrapper() || that.element)[0], e.target)) {
                    return;
                }
                that.clicked = false;
            },
            _focus: function (e) {
                var that = this, target = e.target, hoverItem = that._hoverItem(), active = activeElement();
                if (target != that.wrapper[0] && !$(target).is(':kendoFocusable')) {
                    e.stopPropagation();
                    $(target).closest('.k-content').closest('.k-menu-group').closest('.k-item').addClass(FOCUSEDSTATE);
                    that.wrapper.focus();
                    return;
                }
                if (active === e.currentTarget) {
                    if (hoverItem.length) {
                        that._moveHover([], hoverItem);
                    } else if (!that._oldHoverItem) {
                        that._moveHover([], that.wrapper.children().first());
                    }
                }
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, hoverItem = that._oldHoverItem, target, belongsToVertical, hasChildren, isRtl = kendo.support.isRtl(that.wrapper);
                if (e.target != e.currentTarget && key != keys.ESC) {
                    return;
                }
                if (!hoverItem) {
                    hoverItem = that._oldHoverItem = that._hoverItem();
                }
                belongsToVertical = that._itemBelongsToVertival(hoverItem);
                hasChildren = that._itemHasChildren(hoverItem);
                that._keyTriggered = true;
                if (key == keys.RIGHT) {
                    target = that[isRtl ? '_itemLeft' : '_itemRight'](hoverItem, belongsToVertical, hasChildren);
                } else if (key == keys.LEFT) {
                    target = that[isRtl ? '_itemRight' : '_itemLeft'](hoverItem, belongsToVertical, hasChildren);
                } else if (key == keys.DOWN) {
                    target = that._itemDown(hoverItem, belongsToVertical, hasChildren);
                } else if (key == keys.UP) {
                    target = that._itemUp(hoverItem, belongsToVertical, hasChildren);
                } else if (key == keys.HOME) {
                    that._moveHover(hoverItem, hoverItem.parent().children().first());
                    e.preventDefault();
                } else if (key == keys.END) {
                    that._moveHover(hoverItem, hoverItem.parent().children().last());
                    e.preventDefault();
                } else if (key == keys.ESC) {
                    target = that._itemEsc(hoverItem, belongsToVertical);
                } else if (key == keys.ENTER || key == keys.SPACEBAR) {
                    target = hoverItem.children('.k-link');
                    if (target.length > 0) {
                        that._click({
                            target: target[0],
                            preventDefault: function () {
                            },
                            enterKey: true
                        });
                        if (hasChildren && !hoverItem.hasClass(DISABLEDSTATE)) {
                            that.open(hoverItem);
                            that._moveHover(hoverItem, that._childPopupElement(hoverItem).children().first());
                        } else {
                            that._moveHover(hoverItem, that._findRootParent(hoverItem));
                        }
                    }
                } else if (key == keys.TAB) {
                    target = that._findRootParent(hoverItem);
                    that._moveHover(hoverItem, target);
                    that._checkActiveElement();
                    return;
                }
                if (target && target[0]) {
                    e.preventDefault();
                    e.stopPropagation();
                }
            },
            _hoverItem: function () {
                return this.wrapper.find('.k-item.k-state-hover,.k-item.k-state-focused').filter(':visible');
            },
            _itemBelongsToVertival: function (item) {
                var menuIsVertical = this.wrapper.hasClass('k-menu-vertical');
                if (!item.length) {
                    return menuIsVertical;
                }
                return item.parent().hasClass('k-menu-group') || menuIsVertical;
            },
            _itemHasChildren: function (item) {
                if (!item || !item.length || !item[0].nodeType) {
                    return false;
                }
                return item.children('.k-menu-group, div.k-animation-container').length > 0 || !!item.data(POPUP_OPENER_ATTR) && !!this._overflowWrapper().children(popupGroupSelector(item.data(POPUP_OPENER_ATTR)));
            },
            _moveHover: function (item, nextItem) {
                var that = this, id = that._ariaId;
                if (item.length && nextItem.length) {
                    item.removeClass(FOCUSEDSTATE);
                }
                if (nextItem.length) {
                    if (nextItem[0].id) {
                        id = nextItem[0].id;
                    }
                    nextItem.addClass(FOCUSEDSTATE);
                    that._oldHoverItem = nextItem;
                    if (id) {
                        that.element.removeAttr('aria-activedescendant');
                        $('#' + id).removeAttr('id');
                        nextItem.attr('id', id);
                        that.element.attr('aria-activedescendant', id);
                    }
                    that._scrollToItem(nextItem);
                }
            },
            _findRootParent: function (item) {
                if (this._isRootItem(item)) {
                    return item;
                } else {
                    return this._parentsUntil(item, menuSelector, 'li.k-item').last();
                }
            },
            _isRootItem: function (item) {
                return item.parent().hasClass(MENU);
            },
            _itemRight: function (item, belongsToVertical, hasChildren) {
                var that = this, nextItem, parentItem, overflowWrapper;
                if (!belongsToVertical) {
                    nextItem = item.nextAll(nextSelector);
                    if (!nextItem.length) {
                        nextItem = item.prevAll(lastSelector);
                    }
                    that.close(item);
                } else if (hasChildren && !item.hasClass(DISABLEDSTATE)) {
                    that.open(item);
                    nextItem = that._childPopupElement(item).children().first();
                } else if (that.options.orientation == 'horizontal') {
                    parentItem = that._findRootParent(item);
                    overflowWrapper = that._overflowWrapper();
                    if (overflowWrapper) {
                        var rootPopup = itemPopup(parentItem, overflowWrapper);
                        that._closeChildPopups(rootPopup);
                    }
                    that.close(parentItem);
                    nextItem = parentItem.nextAll(nextSelector);
                }
                if (nextItem && !nextItem.length) {
                    nextItem = that.wrapper.children('.k-item').first();
                } else if (!nextItem) {
                    nextItem = [];
                }
                that._moveHover(item, nextItem);
                return nextItem;
            },
            _itemLeft: function (item, belongsToVertical) {
                var that = this, nextItem, overflowWrapper;
                if (!belongsToVertical) {
                    nextItem = item.prevAll(nextSelector);
                    if (!nextItem.length) {
                        nextItem = item.nextAll(lastSelector);
                    }
                    that.close(item);
                } else {
                    nextItem = item.parent().closest('.k-item');
                    overflowWrapper = that._overflowWrapper();
                    if (!nextItem.length && overflowWrapper) {
                        nextItem = popupParentItem(item.parent(), overflowWrapper);
                    }
                    that.close(nextItem);
                    if (that._isRootItem(nextItem) && that.options.orientation == 'horizontal') {
                        nextItem = nextItem.prevAll(nextSelector);
                    }
                }
                if (!nextItem.length) {
                    nextItem = that.wrapper.children('.k-item').last();
                }
                that._moveHover(item, nextItem);
                return nextItem;
            },
            _itemDown: function (item, belongsToVertical, hasChildren) {
                var that = this, nextItem;
                if (!belongsToVertical) {
                    if (!hasChildren || item.hasClass(DISABLEDSTATE)) {
                        return;
                    } else {
                        that.open(item);
                        nextItem = that._childPopupElement(item).children().first();
                    }
                } else {
                    nextItem = item.nextAll(nextSelector);
                }
                if (!nextItem.length && item.length) {
                    nextItem = item.parent().children().first();
                } else if (!item.length) {
                    nextItem = that.wrapper.children('.k-item').first();
                }
                that._moveHover(item, nextItem);
                return nextItem;
            },
            _itemUp: function (item, belongsToVertical) {
                var that = this, nextItem;
                if (!belongsToVertical) {
                    return;
                } else {
                    nextItem = item.prevAll(nextSelector);
                }
                if (!nextItem.length && item.length) {
                    nextItem = item.parent().children().last();
                } else if (!item.length) {
                    nextItem = that.wrapper.children('.k-item').last();
                }
                that._moveHover(item, nextItem);
                return nextItem;
            },
            _scrollToItem: function (item) {
                var that = this;
                if (that.options.scrollable && item && item.length) {
                    var ul = item.parent();
                    var isHorizontal = ul.hasClass(MENU) ? that.options.orientation == 'horizontal' : false;
                    var scrollDir = isHorizontal ? 'scrollLeft' : 'scrollTop';
                    var getSize = isHorizontal ? kendo._outerWidth : kendo._outerHeight;
                    var currentScrollOffset = ul[scrollDir]();
                    var itemSize = getSize(item);
                    var itemOffset = item[0][isHorizontal ? 'offsetLeft' : 'offsetTop'];
                    var ulSize = getSize(ul);
                    var scrollButtons = ul.siblings(scrollButtonSelector);
                    var scrollButtonSize = scrollButtons.length ? getSize(scrollButtons.first()) : 0;
                    var itemPosition;
                    if (currentScrollOffset + ulSize < itemOffset + itemSize + scrollButtonSize) {
                        itemPosition = itemOffset + itemSize - ulSize + scrollButtonSize;
                    } else if (currentScrollOffset > itemOffset - scrollButtonSize) {
                        itemPosition = itemOffset - scrollButtonSize;
                    }
                    if (!isNaN(itemPosition)) {
                        var scrolling = {};
                        scrolling[scrollDir] = itemPosition;
                        ul.finish().animate(scrolling, 'fast', 'linear', function () {
                            that._toggleScrollButtons(ul, scrollButtons.first(), scrollButtons.last(), isHorizontal);
                        });
                    }
                }
            },
            _itemEsc: function (item, belongsToVertical) {
                var that = this, nextItem;
                if (!belongsToVertical) {
                    return item;
                } else {
                    nextItem = item.parent().closest('.k-item');
                    that.close(nextItem);
                    that._moveHover(item, nextItem);
                }
                return nextItem;
            },
            _childPopupElement: function (item) {
                var popupElement = item.find('.k-menu-group');
                var wrapper = this._overflowWrapper();
                if (!popupElement.length && wrapper) {
                    popupElement = itemPopup(item, wrapper);
                }
                return popupElement;
            },
            _triggerEvent: function (e) {
                var that = this;
                return that.trigger(e.type, {
                    type: e.type,
                    item: e.item
                });
            },
            _focusHandler: function (e) {
                var that = this, item = $(kendo.eventTarget(e)).closest(allItemsSelector);
                if (item.hasClass(DISABLEDSTATE)) {
                    return;
                }
                setTimeout(function () {
                    that._moveHover([], item);
                    if (item.children('.k-content')[0]) {
                        item.parent().closest('.k-item').removeClass(FOCUSEDSTATE);
                    }
                }, 200);
            },
            _animations: function (options) {
                if (options && 'animation' in options && !options.animation) {
                    options.animation = {
                        open: { effects: {} },
                        close: {
                            hide: true,
                            effects: {}
                        }
                    };
                }
            },
            _dataSource: function (options) {
                var that = this, dataSource = options ? options.dataSource : that.options.dataSource;
                if (!dataSource) {
                    return;
                }
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                that._unbindDataSource();
                if (!dataSource.fields) {
                    dataSource.fields = [
                        { field: 'uid' },
                        { field: 'text' },
                        { field: 'url' },
                        { field: 'cssClass' },
                        { field: 'spriteCssClass' },
                        { field: 'imageUrl' },
                        { field: 'imageAttr' },
                        { field: 'attr' },
                        { field: 'contentAttr' },
                        { field: 'content' },
                        { field: 'encoded' },
                        { field: 'items' },
                        { field: 'select' }
                    ];
                }
                that.dataSource = HierarchicalDataSource.create(dataSource);
                that._bindDataSource();
                that.dataSource.fetch();
            },
            _bindDataSource: function () {
                this._refreshHandler = proxy(this.refresh, this);
                this._errorHandler = proxy(this._error, this);
                this.dataSource.bind(CHANGE, this._refreshHandler);
                this.dataSource.bind(ERROR, this._errorHandler);
            },
            _unbindDataSource: function () {
                var dataSource = this.dataSource;
                if (dataSource) {
                    dataSource.unbind(CHANGE, this._refreshHandler);
                    dataSource.unbind(ERROR, this._errorHandler);
                }
            },
            _error: function () {
            },
            findByUid: function (uid) {
                var wrapperElement = this._overflowWrapper() || this.element;
                return wrapperElement.find('[data-uid=' + uid + ']');
            },
            refresh: function (ev) {
                var that = this;
                var node = ev.node;
                var action = ev.action;
                var parentElement = node ? that.findByUid(node.uid) : that.element;
                var itemsToUpdate = ev.items;
                var index = ev.index;
                var updateProxy = $.proxy(that._updateItem, that);
                var removeProxy = $.proxy(that._removeItem, that);
                if (action == 'add') {
                    that._appendItems(itemsToUpdate, index, parentElement);
                } else if (action == 'remove') {
                    itemsToUpdate.forEach(removeProxy);
                } else if (action == 'itemchange') {
                    itemsToUpdate.forEach(updateProxy);
                } else if (action === 'itemloaded') {
                    that.append(ev.items, parentElement);
                } else {
                    this._initData();
                }
                this.trigger(DATABOUND, {
                    item: parentElement,
                    dataItem: node
                });
            },
            _appendItems: function (items, index, parent) {
                var that = this;
                var referenceItem = parent.find(itemSelector).eq(index);
                if (referenceItem.length) {
                    that.insertBefore(items, referenceItem);
                } else {
                    that.append(items, parent);
                }
            },
            _removeItem: function (item) {
                var that = this;
                var element = that.findByUid(item.uid);
                that.remove(element);
            },
            _updateItem: function (item) {
                var that = this;
                var element = that.findByUid(item.uid);
                var nextElement = element.next();
                var parentNode = item.parentNode();
                that.remove(element);
                if (nextElement.length) {
                    that.insertBefore(item, nextElement);
                } else {
                    that.append(item, parentNode && that.findByUid(parentNode.uid));
                }
            },
            _accessors: function () {
                var that = this, options = that.options, i, field, textField, element = that.element;
                for (i in bindings) {
                    field = options[bindings[i]];
                    textField = element.attr(kendo.attr(i + '-field'));
                    if (!field && textField) {
                        field = textField;
                    }
                    if (!field) {
                        field = i;
                    }
                    if (!isArray(field)) {
                        field = [field];
                    }
                    options[bindings[i]] = field;
                }
            },
            _fieldAccessor: function (fieldName) {
                var fieldBindings = this.options[bindings[fieldName]] || [], count = fieldBindings.length, result = '(function(item) {';
                if (count === 0) {
                    result += 'return item[\'' + fieldName + '\'];';
                } else {
                    result += 'var levels = [' + $.map(fieldBindings, function (x) {
                        return 'function(d){ return ' + kendo.expr(x) + '}';
                    }).join(',') + '];';
                    result += 'if(item.level){return levels[Math.min(item.level(), ' + count + '-1)](item);}else';
                    result += '{return levels[' + count + '-1](item)}';
                }
                result += '})';
                return result;
            },
            _templates: function () {
                var that = this, options = that.options, fieldAccessor = proxy(that._fieldAccessor, that);
                if (options.template && typeof options.template == STRING) {
                    options.template = template(options.template);
                } else if (!options.template) {
                    options.template = template('# var text = ' + fieldAccessor('text') + '(data.item); #' + '# if (typeof data.item.encoded != \'undefined\' && data.item.encoded === false) {#' + '#= text #' + '# } else { #' + '#: text #' + '# } #');
                }
                that.templates = {
                    content: template('#var contentHtml = ' + fieldAccessor('content') + '(item);#' + '<div #= contentCssAttributes(item.toJSON ? item.toJSON() : item) # tabindex=\'-1\'>#= contentHtml || \'\' #</div>'),
                    group: template('<ul class=\'#= groupCssClass(group) #\'#= groupAttributes(group) # role=\'menu\' aria-hidden=\'true\'>' + '#= renderItems(data) #' + '</ul>'),
                    itemWrapper: template('# var url = ' + fieldAccessor('url') + '(item); #' + '# var imageUrl = ' + fieldAccessor('imageUrl') + '(item); #' + '# var imgAttributes = ' + fieldAccessor('imageAttr') + '(item);#' + '# var tag = url ? \'a\' : \'span\' #' + '<#= tag # class=\'#= textClass(item) #\' #if(url){#href=\'#= url #\'#}#>' + '# if (imageUrl) { #' + '<img #= imageCssAttributes(imgAttributes) #  alt=\'\' src=\'#= imageUrl #\' />' + '# } #' + '#= sprite(item) ##= data.menu.options.template(data) #' + '#= arrow(data) #' + '</#= tag #>'),
                    item: template('#var contentHtml = ' + fieldAccessor('content') + '(item);#' + '<li class=\'#= wrapperCssClass(group, item) #\' #= itemCssAttributes(item.toJSON ? item.toJSON() : item) # role=\'menuitem\'  #=item.items ? "aria-haspopup=\'true\'": ""#' + '#=item.enabled === false ? "aria-disabled=\'true\'" : \'\'#' + kendo.attr('uid') + '=\'#= item.uid #\' >' + '#= itemWrapper(data) #' + '#if (item.hasChildren || item.items) { #' + '#= subGroup({ items: item.items, menu: menu, group: { expanded: item.expanded } }) #' + '# } else if (item.content || item.contentUrl || contentHtml) { #' + '#= renderContent(data) #' + '# } #' + '</li>'),
                    scrollButton: template('<span class=\'k-button k-button-icon k-menu-scroll-button k-scroll-#= direction #\' unselectable=\'on\'>' + '<span class=\'k-icon k-i-arrow-60-#= direction #\'></span></span>'),
                    arrow: template('<span class=\'#= arrowClass(item, group) #\'></span>'),
                    sprite: template('# var spriteCssClass = ' + fieldAccessor('spriteCssClass') + '(data); if(spriteCssClass) {#<span class=\'k-sprite #= spriteCssClass #\'></span>#}#'),
                    empty: template('')
                };
            },
            renderItem: function (options) {
                var that = this;
                options = extend({
                    menu: that,
                    group: {}
                }, options);
                var empty = that.templates.empty, item = options.item;
                return that.templates.item(extend(options, {
                    sprite: that.templates.sprite,
                    itemWrapper: that.templates.itemWrapper,
                    renderContent: that.renderContent,
                    arrow: item.items || item.content || item[that.options.dataContentField[0]] ? that.templates.arrow : empty,
                    subGroup: that.renderGroup
                }, rendering));
            },
            renderGroup: function (options) {
                var that = this;
                var templates = that.templates || options.menu.templates;
                return templates.group(extend({
                    renderItems: function (options) {
                        var html = '', i = 0, items = options.items, len = items ? items.length : 0, group = extend({ length: len }, options.group);
                        for (; i < len; i++) {
                            html += options.menu.renderItem(extend(options, {
                                group: group,
                                item: extend({ index: i }, items[i])
                            }));
                        }
                        return html;
                    }
                }, options, rendering));
            },
            renderContent: function (options) {
                return options.menu.templates.content(extend(options, rendering));
            }
        });
        var ContextMenu = Menu.extend({
            init: function (element, options) {
                var that = this;
                Menu.fn.init.call(that, element, options);
                that._marker = kendo.guid().substring(0, 8);
                that.target = $(that.options.target);
                that._popup();
                that._wire();
            },
            _initOverflow: function (options) {
                var that = this;
                if (options.scrollable && !that._overflowWrapper()) {
                    that._openedPopups = {};
                    that._popupsWrapper = (that.element.parent().is(animationContainerSelector) ? that.element.parent() : that.element).wrap('<div class=\'k-popups-wrapper ' + options.orientation + '\'></div>').parent();
                    if (that.options.orientation == 'horizontal') {
                        removeSpacesBetweenItems(that.element);
                    }
                    if (options.appendTo) {
                        options.appendTo.append(that._popupsWrapper);
                    }
                    that._initialHeight = that.element[0].style.height;
                    that._initialWidth = that.element[0].style.width;
                }
            },
            options: {
                name: 'ContextMenu',
                filter: null,
                showOn: 'contextmenu',
                orientation: 'vertical',
                alignToAnchor: false,
                target: 'body'
            },
            events: [
                OPEN,
                CLOSE,
                ACTIVATE,
                DEACTIVATE,
                SELECT
            ],
            setOptions: function (options) {
                var that = this;
                Menu.fn.setOptions.call(that, options);
                that.target.off(that.showOn + NS + that._marker, that._showProxy);
                if (that.userEvents) {
                    that.userEvents.destroy();
                }
                that.target = $(that.options.target);
                if (options.orientation && that.popup.wrapper[0]) {
                    that.popup.element.unwrap();
                }
                that._wire();
                Menu.fn.setOptions.call(this, options);
            },
            destroy: function () {
                var that = this;
                that.target.off(that.options.showOn + NS + that._marker);
                DOCUMENT_ELEMENT.off(kendo.support.mousedown + NS + that._marker, that._closeProxy);
                if (that.userEvents) {
                    that.userEvents.destroy();
                }
                Menu.fn.destroy.call(that);
            },
            open: function (x, y) {
                var that = this;
                x = $(x)[0];
                if (contains(that.element[0], $(x)[0]) || that._itemHasChildren($(x))) {
                    Menu.fn.open.call(that, x);
                } else {
                    if (that._triggerEvent({
                            item: that.element,
                            type: OPEN
                        }) === false) {
                        if (that.popup.visible() && that.options.filter) {
                            that.popup.close(true);
                            that.popup.element.kendoStop(true);
                        }
                        if (y !== undefined) {
                            var overflowWrapper = that._overflowWrapper();
                            if (overflowWrapper) {
                                var offset = overflowWrapper.offset();
                                x -= offset.left;
                                y -= offset.top;
                            }
                            that.popup.wrapper.hide();
                            that._configurePopupScrolling(x, y);
                            that.popup.open(x, y);
                        } else {
                            that.popup.options.anchor = (x ? x : that.popup.anchor) || that.target;
                            that.popup.element.kendoStop(true);
                            that._configurePopupScrolling();
                            that.popup.open();
                        }
                        DOCUMENT_ELEMENT.off(that.popup.downEvent, that.popup._mousedownProxy);
                        DOCUMENT_ELEMENT.on(kendo.support.mousedown + NS + that._marker, that._closeProxy);
                    }
                }
                return that;
            },
            _configurePopupScrolling: function (x, y) {
                var that = this;
                var popup = that.popup;
                var isHorizontal = that.options.orientation == 'horizontal';
                if (that.options.scrollable) {
                    that._wrapPopupElement(popup);
                    popup.element.parent().css({
                        position: '',
                        height: ''
                    });
                    popup.element.css({
                        visibility: 'hidden',
                        display: '',
                        position: ''
                    });
                    if (isHorizontal) {
                        that._setPopupWidth(popup, isNaN(x) ? undefined : {
                            isFixed: true,
                            x: x,
                            y: y
                        });
                    } else {
                        that._setPopupHeight(popup, isNaN(x) ? undefined : {
                            isFixed: true,
                            x: x,
                            y: y
                        });
                    }
                    popup.element.css({
                        visibility: '',
                        display: 'none',
                        position: 'absolute'
                    });
                    that._initPopupScrollButtons(popup, isHorizontal, true);
                    popup.element.siblings(scrollButtonSelector).hide();
                }
            },
            _setPopupWidth: function (popup, isFixed) {
                var popupElement = popup.element;
                var popups = popupElement.add(popupElement.parent(animationContainerSelector));
                popups.width(this._initialWidth || '');
                var location = popup._location(isFixed);
                var windowWidth = $(window).width();
                var popupOuterWidth = location.width;
                var popupOffsetLeft = Math.max(location.left, 0);
                var scrollLeft = isFixed ? 0 : parentsScroll(this._overflowWrapper()[0], 'scrollLeft');
                var shadow = kendo.getShadows(popupElement);
                var maxWidth = windowWidth - shadow.left - shadow.right;
                var canFit = maxWidth + scrollLeft > popupOuterWidth + popupOffsetLeft;
                if (!canFit) {
                    popups.css({
                        overflow: 'hidden',
                        width: maxWidth - popupOffsetLeft + scrollLeft + 'px'
                    });
                }
            },
            close: function () {
                var that = this;
                if (contains(that.element[0], $(arguments[0])[0]) || that._itemHasChildren(arguments[0])) {
                    Menu.fn.close.call(that, arguments[0]);
                } else {
                    if (that.popup.visible()) {
                        if (that._triggerEvent({
                                item: that.element,
                                type: CLOSE
                            }) === false) {
                            that.popup.close();
                            DOCUMENT_ELEMENT.off(kendo.support.mousedown + NS + that._marker, that._closeProxy);
                            that.unbind(SELECT, that._closeTimeoutProxy);
                        }
                    }
                }
            },
            _showHandler: function (e) {
                var ev = e, offset, that = this, options = that.options, target = kendo.support.mobileOS ? $(ev.target) : $(ev.currentTarget);
                if (e.event) {
                    ev = e.event;
                    ev.pageX = e.x.location;
                    ev.pageY = e.y.location;
                }
                if (contains(that.element[0], e.relatedTarget || e.target)) {
                    return;
                }
                that._eventOrigin = ev;
                ev.preventDefault();
                ev.stopImmediatePropagation();
                that.element.find('.' + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
                if (options.filter && target.is(options.filter) || !options.filter) {
                    if (options.alignToAnchor) {
                        that.popup.options.anchor = ev.currentTarget;
                        that.open(ev.currentTarget);
                    } else {
                        that.popup.options.anchor = ev.currentTarget;
                        if (that._targetChild) {
                            offset = that.target.offset();
                            that.open(ev.pageX - offset.left, ev.pageY - offset.top);
                        } else {
                            that.open(ev.pageX, ev.pageY);
                        }
                    }
                }
            },
            _closeHandler: function (e) {
                var that = this, target = $(e.relatedTarget || e.target), sameTarget = target.closest(that.target.selector)[0] == that.target[0], item = target.closest(itemSelector), children = that._itemHasChildren(item), overflowWrapper = that._overflowWrapper(), containment = contains(that.element[0], target[0]) || overflowWrapper && contains(overflowWrapper[0], target[0]);
                that._eventOrigin = e;
                var normalClick = e.which !== 3;
                if (that.popup.visible() && (normalClick && sameTarget || !sameTarget) && (that.options.closeOnClick && !children && containment || !containment)) {
                    if (containment) {
                        this.unbind(SELECT, this._closeTimeoutProxy);
                        that.bind(SELECT, that._closeTimeoutProxy);
                    } else {
                        that.close();
                    }
                }
            },
            _wire: function () {
                var that = this, options = that.options, target = that.target;
                that._showProxy = proxy(that._showHandler, that);
                that._closeProxy = proxy(that._closeHandler, that);
                that._closeTimeoutProxy = proxy(that.close, that);
                if (target[0]) {
                    if (kendo.support.mobileOS && options.showOn == 'contextmenu') {
                        that.userEvents = new kendo.UserEvents(target, {
                            filter: options.filter,
                            allowSelection: false
                        });
                        target.on(options.showOn + NS + that._marker, false);
                        that.userEvents.bind('hold', that._showProxy);
                    } else {
                        if (options.filter) {
                            target.on(options.showOn + NS + that._marker, options.filter, that._showProxy);
                        } else {
                            target.on(options.showOn + NS + that._marker, that._showProxy);
                        }
                    }
                }
            },
            _triggerEvent: function (e) {
                var that = this, anchor = $(that.popup.options.anchor)[0], origin = that._eventOrigin;
                that._eventOrigin = undefined;
                return that.trigger(e.type, extend({
                    type: e.type,
                    item: e.item || this.element[0],
                    target: anchor
                }, origin ? { event: origin } : {}));
            },
            _popup: function () {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                that._triggerProxy = proxy(that._triggerEvent, that);
                that.popup = that.element.addClass('k-context-menu').kendoPopup({
                    autosize: that.options.orientation === 'horizontal',
                    anchor: that.target || 'body',
                    copyAnchorStyles: that.options.copyAnchorStyles,
                    collision: that.options.popupCollision || 'fit',
                    animation: that.options.animation,
                    activate: that._triggerProxy,
                    deactivate: that._triggerProxy,
                    appendTo: overflowWrapper || that.options.appendTo,
                    close: !overflowWrapper ? $.noop : function (e) {
                        $(getChildPopups(e.sender.element, overflowWrapper)).each(function (i, p) {
                            var popup = p.data(KENDOPOPUP);
                            if (popup) {
                                popup.close(true);
                            }
                        });
                    }
                }).data(KENDOPOPUP);
                that._targetChild = contains(that.target[0], that.popup.element[0]);
            }
        });
        ui.plugin(Menu);
        ui.plugin(ContextMenu);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.columnmenu', [
        'kendo.popup',
        'kendo.filtermenu',
        'kendo.menu'
    ], f);
}(function () {
    var __meta__ = {
        id: 'columnmenu',
        name: 'Column Menu',
        category: 'framework',
        depends: [
            'popup',
            'filtermenu',
            'menu'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, proxy = $.proxy, extend = $.extend, grep = $.grep, map = $.map, inArray = $.inArray, ACTIVE = 'k-state-selected', ASC = 'asc', DESC = 'desc', CHANGE = 'change', INIT = 'init', OPEN = 'open', SELECT = 'select', POPUP = 'kendoPopup', FILTERMENU = 'kendoFilterMenu', MENU = 'kendoMenu', NS = '.kendoColumnMenu', Widget = ui.Widget;
        function trim(text) {
            return $.trim(text).replace(/&nbsp;/gi, '');
        }
        function toHash(arr, key) {
            var result = {};
            var idx, len, current;
            for (idx = 0, len = arr.length; idx < len; idx++) {
                current = arr[idx];
                result[current[key]] = current;
            }
            return result;
        }
        function leafColumns(columns) {
            var result = [];
            for (var idx = 0; idx < columns.length; idx++) {
                if (!columns[idx].columns) {
                    result.push(columns[idx]);
                    continue;
                }
                result = result.concat(leafColumns(columns[idx].columns));
            }
            return result;
        }
        function attrEquals(attrName, attrValue) {
            return '[' + kendo.attr(attrName) + '=\'' + (attrValue || '').replace(/'/g, '"') + '\']';
        }
        function insertElementAt(index, element, container) {
            if (index > 0) {
                element.insertAfter(container.children().eq(index - 1));
            } else {
                container.prepend(element);
            }
        }
        var ColumnMenu = Widget.extend({
            init: function (element, options) {
                var that = this, link;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                that.owner = options.owner;
                that.dataSource = options.dataSource;
                that.field = element.attr(kendo.attr('field'));
                that.title = element.attr(kendo.attr('title'));
                link = element.find('.k-header-column-menu');
                if (!link[0]) {
                    link = element.addClass('k-with-icon').prepend('<a class="k-header-column-menu" href="#" title="' + options.messages.settings + '" aria-label="' + options.messages.settings + '"><span class="k-icon k-i-more-vertical"></span></a>').find('.k-header-column-menu');
                }
                that.link = link.attr('tabindex', -1).on('click' + NS, proxy(that._click, that));
                that.wrapper = $('<div class="k-column-menu"/>');
                that._refreshHandler = proxy(that.refresh, that);
                that.dataSource.bind(CHANGE, that._refreshHandler);
            },
            _init: function () {
                var that = this;
                that.pane = that.options.pane;
                if (that.pane) {
                    that._isMobile = true;
                }
                if (that._isMobile) {
                    that._createMobileMenu();
                } else {
                    that._createMenu();
                }
                that.owner._muteAngularRebind(function () {
                    that._angularItems('compile');
                });
                that._sort();
                that._columns();
                that._filter();
                that._lockColumns();
                that.trigger(INIT, {
                    field: that.field,
                    container: that.wrapper
                });
            },
            events: [
                INIT,
                OPEN,
                'sort',
                'filtering'
            ],
            options: {
                name: 'ColumnMenu',
                messages: {
                    sortAscending: 'Sort Ascending',
                    sortDescending: 'Sort Descending',
                    filter: 'Filter',
                    column: 'Column',
                    columns: 'Columns',
                    columnVisibility: 'Column Visibility',
                    clear: 'Clear',
                    cancel: 'Cancel',
                    done: 'Done',
                    settings: 'Edit Column Settings',
                    lock: 'Lock',
                    unlock: 'Unlock'
                },
                filter: '',
                columns: true,
                sortable: true,
                filterable: true,
                animations: { left: 'slide' }
            },
            _createMenu: function () {
                var that = this, options = that.options;
                that.wrapper.html(kendo.template(template)({
                    uid: kendo.guid(),
                    ns: kendo.ns,
                    messages: options.messages,
                    sortable: options.sortable,
                    filterable: options.filterable,
                    columns: that._ownerColumns(),
                    showColumns: options.columns,
                    lockedColumns: options.lockedColumns
                }));
                that.popup = that.wrapper[POPUP]({
                    anchor: that.link,
                    open: proxy(that._open, that),
                    activate: proxy(that._activate, that),
                    close: function () {
                        if (that.options.closeCallback) {
                            that.options.closeCallback(that.element);
                        }
                    }
                }).data(POPUP);
                that.menu = that.wrapper.children()[MENU]({
                    orientation: 'vertical',
                    closeOnClick: false,
                    open: function () {
                        that._updateMenuItems();
                    }
                }).data(MENU);
            },
            _createMobileMenu: function () {
                var that = this, options = that.options;
                var html = kendo.template(mobileTemplate)({
                    ns: kendo.ns,
                    field: that.field,
                    title: that.title || that.field,
                    messages: options.messages,
                    sortable: options.sortable,
                    filterable: options.filterable,
                    columns: that._ownerColumns(),
                    showColumns: options.columns,
                    lockedColumns: options.lockedColumns
                });
                that.view = that.pane.append(html);
                that.view.state = { columns: {} };
                that.wrapper = that.view.element.find('.k-column-menu');
                that.menu = new MobileMenu(that.wrapper.children(), {
                    pane: that.pane,
                    columnMenu: that
                });
                that.menu.element.on('transitionend' + NS, function (e) {
                    e.stopPropagation();
                });
                var viewElement = that.view.wrapper && that.view.wrapper[0] ? that.view.wrapper : that.view.element;
                viewElement.on('click', '.k-header-done', function (e) {
                    e.preventDefault();
                    that.menu._applyChanges();
                    that.menu._cancelChanges(false);
                    that.close();
                });
                viewElement.on('click', '.k-header-cancel', function (e) {
                    e.preventDefault();
                    that.menu._cancelChanges(true);
                    that.close();
                });
                that.view.bind('show', function () {
                    var view = that.view || { columns: {} };
                    if (that.options.lockedColumns) {
                        that._updateLockedColumns();
                    }
                    if (view.element.find('.k-sort-asc.k-state-selected').length) {
                        view.state.initialSort = 'asc';
                    } else if (view.element.find('.k-sort-desc.k-state-selected').length) {
                        view.state.initialSort = 'desc';
                    }
                });
            },
            _angularItems: function (action) {
                var that = this;
                that.angular(action, function () {
                    var items = that.wrapper.find('.k-columns-item input[' + kendo.attr('field') + ']').map(function () {
                        return $(this).closest('li');
                    });
                    var data = map(that._ownerColumns(), function (col) {
                        return { column: col._originalObject };
                    });
                    return {
                        elements: items,
                        data: data
                    };
                });
            },
            destroy: function () {
                var that = this;
                that._angularItems('cleanup');
                Widget.fn.destroy.call(that);
                if (that.filterMenu) {
                    that.filterMenu.destroy();
                }
                if (that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                }
                if (that.options.columns && that.owner) {
                    if (that._updateColumnsMenuHandler) {
                        that.owner.unbind('columnShow', that._updateColumnsMenuHandler);
                        that.owner.unbind('columnHide', that._updateColumnsMenuHandler);
                    }
                    if (that._updateColumnsLockedStateHandler) {
                        that.owner.unbind('columnLock', that._updateColumnsLockedStateHandler);
                        that.owner.unbind('columnUnlock', that._updateColumnsLockedStateHandler);
                    }
                }
                if (that.menu) {
                    that.menu.element.off(NS);
                    that.menu.destroy();
                }
                that.wrapper.off(NS);
                if (that.popup) {
                    that.popup.destroy();
                }
                if (that.view) {
                    that.view.purge();
                }
                that.link.off(NS);
                that.owner = null;
                that.wrapper = null;
                that.element = null;
            },
            close: function () {
                this.menu.close();
                if (this.popup) {
                    this.popup.close();
                    this.popup.element.off('keydown' + NS);
                }
            },
            _click: function (e) {
                var that = this;
                e.preventDefault();
                e.stopPropagation();
                var options = this.options;
                if (options.filter && this.element.is(!options.filter)) {
                    return;
                }
                if (!this.popup && !this.pane) {
                    this._init();
                } else {
                    that._updateMenuItems();
                }
                if (this._isMobile) {
                    this.pane.navigate(this.view, this.options.animations.left);
                } else {
                    this.popup.toggle();
                }
            },
            _updateMenuItems: function () {
                var that = this;
                that._setMenuItemsVisibility();
                that._reorderMenuItems();
            },
            _setMenuItemsVisibility: function () {
                var that = this;
                that._eachRenderedMenuItem(function (index, column, renderedListElement) {
                    if (column.matchesMedia === false) {
                        renderedListElement.hide();
                    } else {
                        renderedListElement.show();
                    }
                });
            },
            _reorderMenuItems: function () {
                var that = this;
                that._eachRenderedMenuItem(function (index, column, renderedListElement, renderedList) {
                    if (renderedListElement[0] && renderedListElement.index() !== index) {
                        insertElementAt(index, renderedListElement, renderedList);
                    }
                });
            },
            _eachRenderedMenuItem: function (callback) {
                var that = this;
                var renderedListElement;
                var duplcateColumns;
                var duplicateColumnIndex;
                var fieldValue;
                var currentColumn;
                var columns = grep(leafColumns(that.owner.columns), function (col) {
                    var result = true, title = trim(col.title || '');
                    if (col.menu === false || !col.field && !title.length) {
                        result = false;
                    }
                    return result;
                }).map(function (col) {
                    return {
                        field: col.field,
                        title: col.title,
                        matchesMedia: col.matchesMedia
                    };
                });
                var renderedList = that._isMobile && that.view ? $(that.view.element).find('.k-columns-item').children('ul') : $(that.wrapper).find('.k-menu-group').first();
                var filterByTitle = function (containerElement, tagName, index) {
                    return containerElement.find(tagName).filter(function () {
                        return filterCallback(columns[index], $(this).text());
                    });
                };
                var filterCallback = function (column, text) {
                    return matchTitle(column, text);
                };
                var matchTitle = function (column, titleAttr) {
                    return column.title ? titleAttr === column.title : titleAttr === column.field;
                };
                var duplicateColumns = function (index) {
                    return grep(columns, function (col) {
                        return JSON.stringify(columns[index]) == JSON.stringify(col);
                    });
                };
                for (var i = 0; i < columns.length; i++) {
                    currentColumn = columns[i];
                    duplcateColumns = duplicateColumns(i);
                    duplicateColumnIndex = $.inArray(currentColumn, duplcateColumns);
                    renderedListElement = filterByTitle(renderedList, 'span', i);
                    renderedListElement = this._isMobile ? renderedListElement.next() : renderedListElement;
                    fieldValue = currentColumn.field ? currentColumn.field : currentColumn.title;
                    renderedListElement = renderedListElement.find(attrEquals('field', fieldValue)).closest('li').eq(duplicateColumnIndex);
                    callback(i, currentColumn, renderedListElement, renderedList);
                }
            },
            _open: function () {
                var that = this;
                $('.k-column-menu').not(that.wrapper).each(function () {
                    $(this).data(POPUP).close();
                });
                that.popup.element.on('keydown' + NS, function (e) {
                    if (e.keyCode == kendo.keys.ESC) {
                        that.close();
                    }
                });
                if (that.options.lockedColumns) {
                    that._updateLockedColumns();
                }
            },
            _activate: function () {
                this.menu.element.focus();
                this.trigger(OPEN, {
                    field: this.field,
                    container: this.wrapper
                });
            },
            _ownerColumns: function () {
                var columns = leafColumns(this.owner.columns), menuColumns = grep(columns, function (col) {
                        var result = true, title = trim(col.title || '');
                        if (col.menu === false || !col.field && !title.length) {
                            result = false;
                        }
                        return result;
                    });
                return map(menuColumns, function (col) {
                    return {
                        originalField: col.field,
                        field: col.field || col.title,
                        title: col.title || col.field,
                        hidden: col.hidden,
                        matchesMedia: col.matchesMedia,
                        index: inArray(col, columns),
                        locked: !!col.locked,
                        _originalObject: col
                    };
                });
            },
            _sort: function () {
                var that = this;
                if (that.options.sortable) {
                    that.refresh();
                    that.menu.bind(SELECT, function (e) {
                        var item = $(e.item), dir;
                        if (item.hasClass('k-sort-asc')) {
                            dir = ASC;
                        } else if (item.hasClass('k-sort-desc')) {
                            dir = DESC;
                        }
                        if (!dir) {
                            return;
                        }
                        item.parent().find('.k-sort-' + (dir == ASC ? DESC : ASC)).removeClass(ACTIVE);
                        that._sortDataSource(item, dir);
                        if (!that._isMobile) {
                            that.close();
                        }
                    });
                }
            },
            _sortDataSource: function (item, dir) {
                var that = this, sortable = that.options.sortable, compare = sortable.compare === null ? undefined : sortable.compare, dataSource = that.dataSource, idx, length, sort = dataSource.sort() || [];
                var removeClass = item.hasClass(ACTIVE) && sortable && sortable.allowUnsort !== false;
                dir = !removeClass ? dir : undefined;
                if (that.trigger('sort', {
                        sort: {
                            field: that.field,
                            dir: dir,
                            compare: compare
                        }
                    })) {
                    return;
                }
                if (removeClass) {
                    item.removeClass(ACTIVE);
                } else {
                    item.addClass(ACTIVE);
                }
                if (sortable.mode === 'multiple') {
                    for (idx = 0, length = sort.length; idx < length; idx++) {
                        if (sort[idx].field === that.field) {
                            sort.splice(idx, 1);
                            break;
                        }
                    }
                    sort.push({
                        field: that.field,
                        dir: dir,
                        compare: compare
                    });
                } else {
                    sort = [{
                            field: that.field,
                            dir: dir,
                            compare: compare
                        }];
                }
                dataSource.sort(sort);
            },
            _columns: function () {
                var that = this;
                if (that.options.columns) {
                    that._updateColumnsMenu();
                    that._updateColumnsMenuHandler = proxy(that._updateColumnsMenu, that);
                    that.owner.bind([
                        'columnHide',
                        'columnShow'
                    ], that._updateColumnsMenuHandler);
                    that._updateColumnsLockedStateHandler = proxy(that._updateColumnsLockedState, that);
                    that.owner.bind([
                        'columnUnlock',
                        'columnLock'
                    ], that._updateColumnsLockedStateHandler);
                    that.menu.bind(SELECT, function (e) {
                        var item = $(e.item), input, column, columns = grep(leafColumns(that.owner.columns), function (col) {
                                var result = true, title = trim(col.title || '');
                                if (col.menu === false || !col.field && !title.length) {
                                    result = false;
                                }
                                return result;
                            });
                        if (that._isMobile) {
                            e.preventDefault();
                        }
                        if (!item.parent().closest('li.k-columns-item')[0]) {
                            return;
                        }
                        input = item.find(':checkbox');
                        if (input.attr('disabled')) {
                            return;
                        }
                        column = columns[item.index()];
                        if (column.hidden === true) {
                            that.owner.showColumn(column);
                        } else {
                            that.owner.hideColumn(column);
                        }
                    });
                }
            },
            _updateColumnsMenu: function () {
                var idx, length, current, checked, locked;
                var fieldAttr = kendo.attr('field'), lockedAttr = kendo.attr('locked'), columnsInMenu = grep(leafColumns(this.owner.columns), function (col) {
                        var result = true, title = trim(col.title || '');
                        if (col.menu === false || !col.field && !title.length) {
                            result = false;
                        }
                        return result;
                    }), visibleFields = grep(this._ownerColumns(), function (field) {
                        return !field.hidden && field.matchesMedia !== false;
                    }), visibleDataFields = grep(visibleFields, function (field) {
                        return field.originalField;
                    }), lockedCount = grep(visibleDataFields, function (col) {
                        return col.locked === true;
                    }).length, nonLockedCount = grep(visibleDataFields, function (col) {
                        return col.locked !== true;
                    }).length, columnsNotInMenu = grep(this.owner.columns, function (col) {
                        return col.menu === false;
                    }), hiddenColumnsNotInMenu = grep(columnsNotInMenu, function (col) {
                        return col.hidden;
                    });
                this.wrapper.find('[role=\'menuitemcheckbox\']').attr('aria-checked', false);
                var checkboxes = this.wrapper.find('.k-columns-item input[' + fieldAttr + ']').prop('disabled', false).prop('checked', false);
                var switchWidget;
                for (idx = 0, length = checkboxes.length; idx < length; idx++) {
                    current = checkboxes.eq(idx);
                    locked = current.attr(lockedAttr) === 'true';
                    checked = false;
                    switchWidget = current.data('kendoSwitch');
                    checked = !columnsInMenu[idx].hidden && columnsInMenu[idx].matchesMedia !== false;
                    current.prop('checked', checked);
                    if (switchWidget) {
                        switchWidget.enable(true);
                        switchWidget.check(checked);
                    }
                    current.closest('[role=\'menuitemcheckbox\']').attr('aria-checked', checked);
                    if (checked) {
                        if (lockedCount == 1 && locked) {
                            current.prop('disabled', true);
                            if (switchWidget) {
                                switchWidget.enable(false);
                            }
                        }
                        if ((columnsNotInMenu.length === 0 || columnsNotInMenu.length === hiddenColumnsNotInMenu.length) && nonLockedCount == 1 && !locked) {
                            current.prop('disabled', true);
                            if (switchWidget) {
                                switchWidget.enable(false);
                            }
                        }
                    }
                }
            },
            _updateColumnsLockedState: function () {
                var idx, length, current, column;
                var fieldAttr = kendo.attr('field');
                var lockedAttr = kendo.attr('locked');
                var columns = toHash(this._ownerColumns(), 'field');
                var checkboxes = this.wrapper.find('.k-columns-item input[type=checkbox]');
                for (idx = 0, length = checkboxes.length; idx < length; idx++) {
                    current = checkboxes.eq(idx);
                    column = columns[current.attr(fieldAttr)];
                    if (column) {
                        current.attr(lockedAttr, column.locked);
                    }
                }
                this._updateColumnsMenu();
            },
            _filter: function () {
                var that = this, widget = FILTERMENU, options = that.options;
                if (options.filterable !== false) {
                    if (options.filterable.multi) {
                        widget = 'kendoFilterMultiCheck';
                        if (options.filterable.dataSource) {
                            options.filterable.checkSource = options.filterable.dataSource;
                            delete options.filterable.dataSource;
                        }
                    }
                    that.filterMenu = that.wrapper.find('.k-filterable')[widget](extend(true, {}, {
                        appendToElement: true,
                        dataSource: options.dataSource,
                        values: options.values,
                        field: that.field,
                        title: that.title,
                        change: function (e) {
                            if (that.trigger('filtering', {
                                    filter: e.filter,
                                    field: e.field
                                })) {
                                e.preventDefault();
                            }
                        }
                    }, options.filterable)).data(widget);
                    if (that._isMobile) {
                        that.menu.bind(SELECT, function (e) {
                            var item = $(e.item);
                            if (item.hasClass('k-filter-item')) {
                                that.pane.navigate(that.filterMenu.view, that.options.animations.left);
                            }
                        });
                    }
                }
            },
            _lockColumns: function () {
                var that = this;
                that.menu.bind(SELECT, function (e) {
                    var item = $(e.item);
                    if (item.hasClass('k-lock')) {
                        that.owner.lockColumn(that.field);
                        if (!that._isMobile) {
                            that.close();
                        }
                    } else if (item.hasClass('k-unlock')) {
                        that.owner.unlockColumn(that.field);
                        if (!that._isMobile) {
                            that.close();
                        }
                    }
                });
            },
            _updateLockedColumns: function () {
                var field = this.field;
                var columns = this.owner.columns;
                var column = grep(columns, function (column) {
                    return column.field == field || column.title == field;
                })[0];
                if (!column) {
                    return;
                }
                var locked = column.locked === true;
                var length = grep(columns, function (column) {
                    return !column.hidden && (column.locked && locked || !column.locked && !locked);
                }).length;
                var lockItem = this.wrapper.find('.k-lock').removeClass('k-state-disabled');
                var unlockItem = this.wrapper.find('.k-unlock').removeClass('k-state-disabled');
                if (locked || length == 1) {
                    lockItem.addClass('k-state-disabled');
                }
                if (!locked || length == 1) {
                    unlockItem.addClass('k-state-disabled');
                }
                this._updateColumnsLockedState();
            },
            refresh: function () {
                var that = this, sort = that.options.dataSource.sort() || [], descriptor, field = that.field, idx, length;
                that.wrapper.find('.k-sort-asc, .k-sort-desc').removeClass(ACTIVE);
                for (idx = 0, length = sort.length; idx < length; idx++) {
                    descriptor = sort[idx];
                    if (field == descriptor.field) {
                        that.wrapper.find('.k-sort-' + descriptor.dir).addClass(ACTIVE);
                    }
                }
                that.link[that._filterExist(that.dataSource.filter()) ? 'addClass' : 'removeClass']('k-state-active');
            },
            _filterExist: function (filters) {
                var found = false;
                var filter;
                if (!filters) {
                    return;
                }
                filters = filters.filters;
                for (var idx = 0, length = filters.length; idx < length; idx++) {
                    filter = filters[idx];
                    if (filter.field == this.field) {
                        found = true;
                    } else if (filter.filters) {
                        found = found || this._filterExist(filter);
                    }
                }
                return found;
            }
        });
        var template = '<ul id="#=uid#">' + '#if(sortable){#' + '<li class="k-item k-sort-asc"><span class="k-link"><span class="k-icon k-i-sort-asc-sm"></span>${messages.sortAscending}</span></li>' + '<li class="k-item k-sort-desc"><span class="k-link"><span class="k-icon k-i-sort-desc-sm"></span>${messages.sortDescending}</span></li>' + '#if(showColumns || filterable){#' + '<li class="k-separator" role="presentation"></li>' + '#}#' + '#}#' + '#if(showColumns){#' + '<li class="k-item k-columns-item" aria-haspopup="true"><span class="k-link"><span class="k-icon k-i-columns"></span>${messages.columns}</span><ul>' + '#for (var idx = 0; idx < columns.length; idx++) {#' + '<li role="menuitemcheckbox" aria-checked="false" #=columns[idx].matchesMedia === false ? "style=\'display:none;\'" : ""#><input type="checkbox" title="#=columns[idx].title#" data-#=ns#field="#=columns[idx].field.replace(/"/g,"&\\#34;")#" data-#=ns#index="#=columns[idx].index#" data-#=ns#locked="#=columns[idx].locked#"/>#=columns[idx].title#</li>' + '#}#' + '</ul></li>' + '#if(filterable || lockedColumns){#' + '<li class="k-separator" role="presentation"></li>' + '#}#' + '#}#' + '#if(filterable){#' + '<li class="k-item k-filter-item" aria-haspopup="true"><span class="k-link"><span class="k-icon k-i-filter"></span>${messages.filter}</span><ul>' + '<li><div class="k-filterable"></div></li>' + '</ul></li>' + '#if(lockedColumns){#' + '<li class="k-separator" role="presentation"></li>' + '#}#' + '#}#' + '#if(lockedColumns){#' + '<li class="k-item k-lock"><span class="k-link"><span class="k-icon k-i-lock"></span>${messages.lock}</span></li>' + '<li class="k-item k-unlock"><span class="k-link"><span class="k-icon k-i-unlock"></span>${messages.unlock}</span></li>' + '#}#' + '</ul>';
        var mobileTemplate = '<div data-#=ns#role="view" class="k-grid-column-menu">' + '<div data-#=ns#role="header" class="k-header">' + '<a href="\\#" class="k-header-cancel k-link" title="#=messages.cancel#" ' + 'aria-label="#=messages.cancel#"><span class="k-icon k-i-arrow-chevron-left"></span></a>' + '${messages.settings}' + '<a href="\\#" class="k-header-done k-link" title="#=messages.done#" ' + 'aria-label="#=messages.done#"><span class="k-icon k-i-check"></span></a>' + '</div>' + '<div class="k-column-menu k-mobile-list">' + '<ul>' + '<li>' + '<span class="k-list-title">#=messages.column#: ${title}</span>' + '<ul>' + '#if(sortable){#' + '<li id="#=kendo.guid()#" class="k-item k-sort-asc"><span class="k-link"><span class="k-icon k-i-sort-asc-sm"></span><span class="k-item-title">${messages.sortAscending}</span></span></li>' + '<li id="#=kendo.guid()#" class="k-item k-sort-desc"><span class="k-link"><span class="k-icon k-i-sort-desc-sm"></span><span class="k-item-title">${messages.sortDescending}</span></span></li>' + '#}#' + '#if(lockedColumns){#' + '<li id="#=kendo.guid()#" class="k-item k-lock"><span class="k-link"><span class="k-icon k-i-lock"></span><span class="k-item-title">${messages.lock}</span></span></li>' + '<li id="#=kendo.guid()#" class="k-item k-unlock"><span class="k-link"><span class="k-icon k-i-unlock"></span><span class="k-item-title">${messages.unlock}</span></span></li>' + '#}#' + '#if(filterable){#' + '<li id="#=kendo.guid()#" class="k-item k-filter-item">' + '<span class="k-link k-filterable">' + '<span class="k-icon k-i-filter"></span>' + '<span class="k-item-title">${messages.filter}</span></span>' + '</li>' + '#}#' + '</ul>' + '</li>' + '#if(showColumns){#' + '<li class="k-columns-item"><span class="k-list-title">${messages.columnVisibility}</span>' + '<ul>' + '#for (var idx = 0; idx < columns.length; idx++) {#' + '<li id="#=kendo.guid()#" class="k-item">' + '<span class="k-item-title">' + '#=columns[idx].title#' + '</span>' + '<input type="checkbox" title="#=columns[idx].title#" ' + ' data-#=ns#field="#=columns[idx].field.replace(/"/g,"&\\#34;")#"' + ' data-#=ns#index="#=columns[idx].index#"' + ' data-#=ns#locked="#=columns[idx].locked#"/>' + '</li>' + '#}#' + '</ul>' + '</li>' + '#}#' + '<li class="k-item k-clear-wrap">' + '<span class="k-label k-clear" title="#=messages.clear#" ' + 'aria-label="#=messages.clear#">#=messages.clear#</span>' + '</li>' + '</ul>' + '</div>' + '</div>';
        var MobileMenu = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that._createCheckBoxes();
                that.element.on('click' + NS, 'li.k-item:not(.k-separator):not(.k-state-disabled):not(:has(.k-switch))', '_click');
            },
            events: [SELECT],
            _click: function (e) {
                var that = this;
                if (!$(e.target).is('[type=checkbox]')) {
                    e.preventDefault();
                }
                if ($(e.target).hasClass('k-clear')) {
                    that._cancelChanges(true);
                    return;
                }
                if ($(e.target).hasClass('k-filterable')) {
                    that._cancelChanges(true);
                    that.trigger(SELECT, { item: e.currentTarget });
                    return;
                }
                that._updateSelectedItems(e.currentTarget);
            },
            _updateSelectedItems: function (el) {
                var that = this;
                var item = $(el);
                var state = that.options.columnMenu.view.state || { columns: {} };
                var id = item.prop('id');
                if (item.hasClass('k-filter-item')) {
                    return;
                }
                if (state[id]) {
                    state[id] = false;
                } else {
                    state[id] = true;
                }
                if (item.hasClass('k-sort-asc') || item.hasClass('k-sort-desc')) {
                    var dir;
                    var otherItem;
                    var otherItemId;
                    if (item.hasClass('k-sort-asc')) {
                        dir = 'asc';
                        otherItem = that.element.find('.k-sort-desc');
                    } else {
                        dir = 'desc';
                        otherItem = that.element.find('.k-sort-asc');
                    }
                    otherItemId = otherItem.prop('id');
                    if (dir === state.initialSort && !item.hasClass('k-state-selected')) {
                        state[id] = false;
                    }
                    if (state[otherItemId]) {
                        state[otherItemId] = false;
                    }
                    otherItem.removeClass(ACTIVE);
                }
                if (item.hasClass(ACTIVE)) {
                    item.removeClass(ACTIVE);
                } else {
                    item.addClass(ACTIVE);
                }
            },
            _cancelChanges: function (force) {
                var that = this;
                var menu = that.options.columnMenu;
                var view = menu.view;
                var state = view.state || { columns: {} };
                var columns = state.columns;
                that.element.find('.' + ACTIVE).removeClass(ACTIVE);
                menu.refresh();
                if (force) {
                    var selectedItems = [];
                    for (var key in columns) {
                        if (columns.hasOwnProperty(key)) {
                            if (columns[key] === true) {
                                var item = view.element.find('#' + key);
                                selectedItems.push(item[0]);
                            }
                        }
                    }
                    for (var i = selectedItems.length - 1; i >= 0; i--) {
                        that.trigger(SELECT, { item: selectedItems[i] });
                    }
                    if (menu.options.lockedColumns) {
                        menu._updateLockedColumns();
                    }
                }
                that.options.columnMenu.view.state = { columns: {} };
            },
            _applyChanges: function () {
                var that = this;
                var view = that.options.columnMenu.view;
                var state = view.state || { columns: {} };
                for (var key in state) {
                    if (state.hasOwnProperty(key)) {
                        if (key !== 'initialSort' && key !== 'columns' && state[key] === true) {
                            var item = view.element.find('#' + key);
                            if (item.hasClass(ACTIVE)) {
                                item.removeClass(ACTIVE);
                            } else {
                                item.addClass(ACTIVE);
                            }
                            that.trigger(SELECT, { item: item[0] });
                        }
                    }
                }
            },
            _createCheckBoxes: function () {
                var that = this;
                that.element.find('.k-columns-item').find('[type=\'checkbox\']').kendoSwitch({
                    messages: {
                        checked: '',
                        unchecked: ''
                    },
                    change: function (e) {
                        var item = e.sender.element.closest('.k-item');
                        var state = that.options.columnMenu.view.state || { columns: {} };
                        var id = item.prop('id');
                        if (state.columns[id]) {
                            state.columns[id] = false;
                        } else {
                            state.columns[id] = true;
                        }
                        that.trigger(SELECT, { item: item });
                    }
                });
            },
            _destroyCheckBoxes: function () {
                var that = this;
                var elements = that.element.find('.k-columns-item').find('[type=\'checkbox\']');
                var switchWidget;
                for (var i = 0; i < elements.length; i++) {
                    switchWidget = elements.eq(i).data('kendoSwitch');
                    if (switchWidget) {
                        switchWidget.destroy();
                    }
                }
            },
            close: function () {
                this.options.pane.navigate('');
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.element.off(NS);
                that._destroyCheckBoxes();
            }
        });
        ui.plugin(ColumnMenu);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.columnsorter', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'columnsorter',
        name: 'Column Sorter',
        category: 'framework',
        depends: ['core'],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var ui = kendo.ui;
        var Widget = ui.Widget;
        var DIR = 'dir';
        var ASC = 'asc';
        var SINGLE = 'single';
        var FIELD = 'field';
        var DESC = 'desc';
        var sorterNS = '.kendoColumnSorter';
        var TLINK = '.k-link';
        var ARIASORT = 'aria-sort';
        var proxy = $.proxy;
        var ColumnSorter = Widget.extend({
            init: function (element, options) {
                var that = this, link;
                Widget.fn.init.call(that, element, options);
                that._refreshHandler = proxy(that.refresh, that);
                that.dataSource = that.options.dataSource.bind('change', that._refreshHandler);
                that.directions = that.options.initialDirection === ASC ? [
                    ASC,
                    DESC
                ] : [
                    DESC,
                    ASC
                ];
                link = that.element.find(TLINK);
                if (!link[0]) {
                    link = that.element.wrapInner('<a class="k-link" href="#"/>').find(TLINK);
                }
                that.link = link;
                that.element.on('click' + sorterNS, proxy(that._click, that));
            },
            options: {
                name: 'ColumnSorter',
                mode: SINGLE,
                allowUnsort: true,
                compare: null,
                filter: '',
                initialDirection: ASC,
                showIndexes: false
            },
            events: ['change'],
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.element.off(sorterNS);
                that.dataSource.unbind('change', that._refreshHandler);
                that._refreshHandler = that.element = that.link = that.dataSource = null;
            },
            refresh: function () {
                var that = this, sort = that.dataSource.sort() || [], idx, length, descriptor, dir, element = that.element, field = element.attr(kendo.attr(FIELD)), headerIndex, sortOrder, leafCells;
                element.removeAttr(kendo.attr(DIR));
                element.removeAttr(ARIASORT);
                for (idx = 0, length = sort.length; idx < length; idx++) {
                    descriptor = sort[idx];
                    if (field == descriptor.field) {
                        element.attr(kendo.attr(DIR), descriptor.dir);
                        sortOrder = idx + 1;
                    }
                }
                dir = element.attr(kendo.attr(DIR));
                if (element.is('th')) {
                    var table = element.closest('table');
                    if (table.parent().hasClass('k-grid-header-wrap')) {
                        table = table.closest('.k-grid').find('.k-grid-content > table');
                    } else if (table.parent().hasClass('k-grid-header-locked')) {
                        table = table.closest('.k-grid').find('.k-grid-content-locked > table');
                    } else if (!table.parent().hasClass('k-grid')) {
                        table = null;
                    }
                    if (table) {
                        if (element.attr(kendo.attr('index'))) {
                            leafCells = leafDataCells(element.closest('.k-grid-header'));
                            headerIndex = leafCells.index(element);
                        } else {
                            headerIndex = element.parent().children(':visible').index(element);
                        }
                        element.toggleClass('k-sorted', dir !== undefined);
                        table.children('colgroup').children(':not(.k-group-col):not(.k-hierarchy-col)').eq(headerIndex).toggleClass('k-sorted', dir !== undefined);
                    }
                }
                element.find('.k-i-sort-asc-sm,.k-i-sort-desc-sm,.k-sort-order').remove();
                if (dir === ASC) {
                    $('<span class="k-icon k-i-sort-asc-sm" />').appendTo(that.link);
                    element.attr(ARIASORT, 'ascending');
                } else if (dir === DESC) {
                    $('<span class="k-icon k-i-sort-desc-sm" />').appendTo(that.link);
                    element.attr(ARIASORT, 'descending');
                }
                if (that.options.showIndexes && sort.length > 1 && sortOrder) {
                    $('<span class="k-sort-order" />').html(sortOrder).appendTo(that.link);
                }
            },
            _toggleSortDirection: function (dir) {
                var directions = this.directions;
                if (dir === directions[directions.length - 1] && this.options.allowUnsort) {
                    return undefined;
                }
                return directions[0] === dir ? directions[1] : directions[0];
            },
            _click: function (e) {
                var that = this, element = that.element, field = element.attr(kendo.attr(FIELD)), dir = element.attr(kendo.attr(DIR)), options = that.options, compare = that.options.compare === null ? undefined : that.options.compare, sort = that.dataSource.sort() || [], idx, length;
                e.preventDefault();
                if (options.filter && !element.is(options.filter)) {
                    return;
                }
                dir = this._toggleSortDirection(dir);
                if (this.trigger('change', {
                        sort: {
                            field: field,
                            dir: dir,
                            compare: compare
                        }
                    })) {
                    return;
                }
                if (options.mode === SINGLE) {
                    sort = [{
                            field: field,
                            dir: dir,
                            compare: compare
                        }];
                } else if (options.mode === 'multiple') {
                    for (idx = 0, length = sort.length; idx < length; idx++) {
                        if (sort[idx].field === field) {
                            sort.splice(idx, 1);
                            break;
                        }
                    }
                    sort.push({
                        field: field,
                        dir: dir,
                        compare: compare
                    });
                }
                if (this.dataSource.options.endless) {
                    this.dataSource.options.endless = null;
                    element.closest('.k-grid').getKendoGrid()._endlessPageSize = that.dataSource.options.pageSize;
                    this.dataSource.pageSize(that.dataSource.options.pageSize);
                }
                this.dataSource.sort(sort);
            }
        });
        function leafDataCells(container) {
            var rows = container.find('tr:not(.k-filter-row)');
            var filter = function () {
                var el = $(this);
                return !el.hasClass('k-group-cell') && !el.hasClass('k-hierarchy-cell');
            };
            var cells = $();
            if (rows.length > 1) {
                cells = rows.find('th:visible').filter(filter).filter(function () {
                    return this.rowSpan > 1;
                });
            }
            cells = cells.add(rows.last().find('th:visible').filter(filter));
            var indexAttr = kendo.attr('index');
            cells.sort(function (a, b) {
                a = $(a);
                b = $(b);
                var indexA = a.attr(indexAttr);
                var indexB = b.attr(indexAttr);
                if (indexA === undefined) {
                    indexA = $(a).index();
                }
                if (indexB === undefined) {
                    indexB = $(b).index();
                }
                indexA = parseInt(indexA, 10);
                indexB = parseInt(indexB, 10);
                return indexA > indexB ? 1 : indexA < indexB ? -1 : 0;
            });
            return cells;
        }
        ui.plugin(ColumnSorter);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.editable', [
        'kendo.datepicker',
        'kendo.numerictextbox',
        'kendo.validator',
        'kendo.binder'
    ], f);
}(function () {
    var __meta__ = {
        id: 'editable',
        name: 'Editable',
        category: 'framework',
        depends: [
            'datepicker',
            'numerictextbox',
            'validator',
            'binder'
        ],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, extend = $.extend, oldIE = kendo.support.browser.msie && kendo.support.browser.version < 9, isFunction = kendo.isFunction, isPlainObject = $.isPlainObject, inArray = $.inArray, POINT = '.', support = kendo.support, AUTOCOMPLETEVALUE = support.browser.chrome ? 'disabled' : 'off', nameSpecialCharRegExp = /("|\%|'|\[|\]|\$|\.|\,|\:|\;|\+|\*|\&|\!|\#|\(|\)|<|>|\=|\?|\@|\^|\{|\}|\~|\/|\||`)/g, ERRORTEMPLATE = '<div class="k-widget k-tooltip k-tooltip-validation" style="margin:0.5em"><span class="k-icon k-i-warning"> </span>' + '#=message#<div class="k-callout k-callout-n"></div></div>', CHANGE = 'change';
        var EQUAL_SET = 'equalSet';
        var specialRules = [
            'url',
            'email',
            'number',
            'date',
            'boolean'
        ];
        function fieldType(field) {
            field = field != null ? field : '';
            return field.type || $.type(field) || 'string';
        }
        function convertToValueBinding(container) {
            container.find(':input:not(:button, .k-combobox .k-input, [' + kendo.attr('role') + '=listbox], [' + kendo.attr('role') + '=upload], [' + kendo.attr('skip') + '], [type=file])').each(function () {
                var bindAttr = kendo.attr('bind'), binding = this.getAttribute(bindAttr) || '', bindingName = this.type === 'checkbox' || this.type === 'radio' ? 'checked:' : 'value:', fieldName = this.name;
                if (binding.indexOf(bindingName) === -1 && fieldName) {
                    binding += (binding.length ? ',' : '') + bindingName + fieldName;
                    $(this).attr(bindAttr, binding);
                }
            });
        }
        function createAttributes(options) {
            var field = (options.model.fields || options.model)[options.field], type = fieldType(field), validation = field ? field.validation : {}, ruleName, DATATYPE = kendo.attr('type'), BINDING = kendo.attr('bind'), rule, attr = {
                    name: options.field,
                    title: options.title ? options.title : options.field
                };
            for (ruleName in validation) {
                rule = validation[ruleName];
                if (inArray(ruleName, specialRules) >= 0) {
                    attr[DATATYPE] = ruleName;
                } else if (!isFunction(rule)) {
                    var culture = kendo.getCulture();
                    if (typeof rule === 'number' && culture.name.length) {
                        var numberFormat = culture.numberFormat;
                        var stringRule = rule.toString().replace(POINT, numberFormat[POINT]);
                        attr[ruleName] = stringRule;
                    } else {
                        attr[ruleName] = isPlainObject(rule) ? rule.value || ruleName : rule;
                    }
                }
                attr[kendo.attr(ruleName + '-msg')] = rule.message;
                attr.autocomplete = AUTOCOMPLETEVALUE;
            }
            if (inArray(type, specialRules) >= 0) {
                attr[DATATYPE] = type;
            }
            attr[BINDING] = (type === 'boolean' ? 'checked:' : 'value:') + options.field;
            return attr;
        }
        function addIdAttribute(container, attr) {
            var id = container.attr('id');
            if (id) {
                attr.id = id;
                container.removeAttr('id');
            }
            return attr;
        }
        function convertItems(items) {
            var idx, length, item, value, text, result;
            if (items && items.length) {
                result = [];
                for (idx = 0, length = items.length; idx < length; idx++) {
                    item = items[idx];
                    text = item.text || item.value || item;
                    value = item.value == null ? item.text || item : item.value;
                    result[idx] = {
                        text: text,
                        value: value
                    };
                }
            }
            return result;
        }
        var editors = {
            'number': function (container, options) {
                var attr = createAttributes(options);
                $('<input type="text"/>').attr(attr).appendTo(container).kendoNumericTextBox({ format: options.format });
                $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
            },
            'date': function (container, options) {
                var attr = createAttributes(options), format = options.format;
                if (format) {
                    format = kendo._extractFormat(format);
                }
                attr[kendo.attr('format')] = format;
                $('<input type="text"/>').attr(attr).appendTo(container).kendoDatePicker({ format: options.format });
                $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
            },
            'string': function (container, options) {
                var attr = createAttributes(options);
                $('<input type="text" class="k-textbox"/>').attr(attr).appendTo(container);
            },
            'boolean': function (container, options) {
                var attr = createAttributes(options);
                $('<input type="checkbox" />').attr(attr).appendTo(container);
            },
            'values': function (container, options) {
                var attr = createAttributes(options);
                var items = kendo.stringify(convertItems(options.values));
                $('<select ' + kendo.attr('text-field') + '="text"' + kendo.attr('value-field') + '="value"' + kendo.attr('source') + '=\'' + (items ? items.replace(/\'/g, '&apos;') : items) + '\'' + kendo.attr('role') + '="dropdownlist"/>').attr(attr).appendTo(container);
                $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
            }
        };
        var mobileEditors = {
            'number': function (container, options) {
                var attr = createAttributes(options);
                attr = addIdAttribute(container, attr);
                $('<input type="number"/>').attr(attr).appendTo(container);
            },
            'date': function (container, options) {
                var attr = createAttributes(options);
                attr = addIdAttribute(container, attr);
                $('<input type="date"/>').attr(attr).appendTo(container);
            },
            'string': function (container, options) {
                var attr = createAttributes(options);
                attr = addIdAttribute(container, attr);
                $('<input type="text" />').attr(attr).appendTo(container);
            },
            'boolean': function (container, options) {
                var attr = createAttributes(options);
                attr = addIdAttribute(container, attr);
                $('<input type="checkbox" />').attr(attr).appendTo(container);
            },
            'values': function (container, options) {
                var attr = createAttributes(options);
                var items = options.values;
                var select = $('<select />');
                attr = addIdAttribute(container, attr);
                for (var index in items) {
                    $('<option value="' + items[index].value + '">' + items[index].text + '</option>').appendTo(select);
                }
                select.attr(attr).appendTo(container);
            }
        };
        function addValidationRules(modelField, rules) {
            var validation = modelField ? modelField.validation || {} : {}, rule, descriptor;
            for (rule in validation) {
                descriptor = validation[rule];
                if (isPlainObject(descriptor) && descriptor.value) {
                    descriptor = descriptor.value;
                }
                if (isFunction(descriptor)) {
                    rules[rule] = descriptor;
                }
            }
        }
        var Editable = Widget.extend({
            init: function (element, options) {
                var that = this;
                if (options.target) {
                    options.$angular = options.target.options.$angular;
                    if (options.target.pane) {
                        that._isMobile = true;
                    }
                }
                Widget.fn.init.call(that, element, options);
                that._validateProxy = $.proxy(that._validate, that);
                that.refresh();
            },
            events: [CHANGE],
            options: {
                name: 'Editable',
                editors: editors,
                mobileEditors: mobileEditors,
                clearContainer: true,
                errorTemplate: ERRORTEMPLATE,
                skipFocus: false
            },
            editor: function (field, modelField) {
                var that = this, editors = that._isMobile ? mobileEditors : that.options.editors, isObject = isPlainObject(field), fieldName = isObject ? field.field : field, model = that.options.model || {}, isValuesEditor = isObject && field.values, type = isValuesEditor ? 'values' : fieldType(modelField), isCustomEditor = isObject && field.editor, editor = isCustomEditor ? field.editor : editors[type], container = that.element.find('[' + kendo.attr('container-for') + '=' + fieldName.replace(nameSpecialCharRegExp, '\\$1') + ']');
                editor = editor ? editor : editors.string;
                if (isCustomEditor && typeof field.editor === 'string') {
                    editor = function (container) {
                        container.append(field.editor);
                    };
                }
                container = container.length ? container : that.element;
                editor(container, extend(true, {}, isObject ? field : { field: fieldName }, { model: model }));
            },
            _validate: function (e) {
                var that = this, input, value = e.value, preventChangeTrigger = that._validationEventInProgress, values = {}, bindAttribute = kendo.attr('bind'), fieldName = e.field.replace(nameSpecialCharRegExp, '\\$1'), bindingRegex = new RegExp('(value|checked)\\s*:\\s*' + fieldName + '\\s*(,|$)');
                values[e.field] = e.value;
                input = $(':input[' + bindAttribute + '*="' + fieldName + '"]', that.element).filter('[' + kendo.attr('validate') + '!=\'false\']').filter(function () {
                    return bindingRegex.test($(this).attr(bindAttribute));
                });
                if (input.length > 1) {
                    input = input.filter(function () {
                        var element = $(this);
                        return !element.is(':radio') || element.val() == value;
                    });
                }
                try {
                    that._validationEventInProgress = true;
                    if (!that.validatable.validateInput(input) || !preventChangeTrigger && that.trigger(CHANGE, { values: values })) {
                        e.preventDefault();
                    }
                } finally {
                    that._validationEventInProgress = false;
                }
            },
            end: function () {
                return this.validatable.validate();
            },
            destroy: function () {
                var that = this;
                that.angular('cleanup', function () {
                    return { elements: that.element };
                });
                Widget.fn.destroy.call(that);
                that.options.model.unbind('set', that._validateProxy);
                that.options.model.unbind(EQUAL_SET, that._validateProxy);
                kendo.unbind(that.element);
                if (that.validatable) {
                    that.validatable.destroy();
                }
                kendo.destroy(that.element);
                that.element.removeData('kendoValidator');
                if (that.element.is('[' + kendo.attr('role') + '=editable]')) {
                    that.element.removeAttr(kendo.attr('role'));
                }
            },
            refresh: function () {
                var that = this, idx, length, fields = that.options.fields || [], container = that.options.clearContainer ? that.element.empty() : that.element, model = that.options.model || {}, rules = {}, field, isObject, fieldName, modelField, modelFields;
                if (!$.isArray(fields)) {
                    fields = [fields];
                }
                for (idx = 0, length = fields.length; idx < length; idx++) {
                    field = fields[idx];
                    isObject = isPlainObject(field);
                    fieldName = isObject ? field.field : field;
                    modelField = (model.fields || model)[fieldName];
                    addValidationRules(modelField, rules);
                    that.editor(field, modelField);
                }
                if (that.options.target) {
                    that.angular('compile', function () {
                        return {
                            elements: container,
                            data: container.map(function () {
                                return { dataItem: model };
                            })
                        };
                    });
                }
                if (!length) {
                    modelFields = model.fields || model;
                    for (fieldName in modelFields) {
                        addValidationRules(modelFields[fieldName], rules);
                    }
                }
                convertToValueBinding(container);
                if (that.validatable) {
                    that.validatable.destroy();
                }
                kendo.bind(container, that.options.model);
                that.options.model.unbind('set', that._validateProxy);
                that.options.model.bind('set', that._validateProxy);
                that.options.model.unbind(EQUAL_SET, that._validateProxy);
                that.options.model.bind(EQUAL_SET, that._validateProxy);
                that.validatable = new kendo.ui.Validator(container, {
                    validateOnBlur: false,
                    errorTemplate: that.options.errorTemplate || undefined,
                    rules: rules
                });
                if (!that.options.skipFocus) {
                    var focusable = container.find(':kendoFocusable').eq(0).focus();
                    if (oldIE) {
                        focusable.focus();
                    }
                }
            }
        });
        ui.plugin(Editable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.window', [
        'kendo.draganddrop',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'window',
        name: 'Window',
        category: 'web',
        description: 'The Window widget displays content in a modal or non-modal HTML window.',
        depends: [
            'draganddrop',
            'popup'
        ],
        features: [{
                id: 'window-fx',
                name: 'Animation',
                description: 'Support for animation',
                depends: ['fx']
            }]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, TabKeyTrap = kendo.ui.Popup.TabKeyTrap, Draggable = kendo.ui.Draggable, isPlainObject = $.isPlainObject, activeElement = kendo._activeElement, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, proxy = $.proxy, extend = $.extend, each = $.each, template = kendo.template, BODY = 'body', templates, NS = '.kendoWindow', MODAL_NS = '.kendoWindowModal', KWINDOW = '.k-window', KWINDOWTITLE = '.k-window-title', KWINDOWTITLEBAR = KWINDOWTITLE + 'bar', KWINDOWCONTENT = '.k-window-content', KDIALOGCONTENT = '.k-dialog-content', KWINDOWRESIZEHANDLES = '.k-resize-handle', KOVERLAY = '.k-overlay', KCONTENTFRAME = 'k-content-frame', LOADING = 'k-i-loading', KHOVERSTATE = 'k-state-hover', KFOCUSEDSTATE = 'k-state-focused', MAXIMIZEDSTATE = 'k-window-maximized', VISIBLE = ':visible', HIDDEN = 'hidden', CURSOR = 'cursor', OPEN = 'open', ACTIVATE = 'activate', DEACTIVATE = 'deactivate', CLOSE = 'close', REFRESH = 'refresh', MINIMIZE = 'minimize', MAXIMIZE = 'maximize', RESIZESTART = 'resizeStart', RESIZE = 'resize', RESIZEEND = 'resizeEnd', DRAGSTART = 'dragstart', DRAGEND = 'dragend', ERROR = 'error', OVERFLOW = 'overflow', DATADOCOVERFLOWRULE = 'original-overflow-rule', ZINDEX = 'zIndex', MINIMIZE_MAXIMIZE = '.k-window-actions .k-i-window-minimize,.k-window-actions .k-i-window-maximize', KPIN = '.k-i-pin', KUNPIN = '.k-i-unpin', PIN_UNPIN = KPIN + ',' + KUNPIN, TITLEBAR_BUTTONS = '.k-window-titlebar .k-window-action', REFRESHICON = '.k-window-titlebar .k-i-refresh', WINDOWEVENTSHANDLED = 'WindowEventsHandled', zero = /^0[a-z]*$/i, isLocalUrl = kendo.isLocalUrl, SIZE = {
                small: 'k-window-sm',
                medium: 'k-window-md',
                large: 'k-window-lg'
            };
        function defined(x) {
            return typeof x != 'undefined';
        }
        function toInt(element, property) {
            return parseInt(element.css(property), 10) || 0;
        }
        function constrain(value, low, high) {
            var normalizedValue;
            if (value && isNaN(value) && value.toString().indexOf('px') < 0) {
                normalizedValue = value;
            } else {
                normalizedValue = Math.max(Math.min(parseInt(value, 10), high === Infinity ? high : parseInt(high, 10)), low === -Infinity ? low : parseInt(low, 10));
            }
            return normalizedValue;
        }
        function executableScript() {
            return !this.type || this.type.toLowerCase().indexOf('script') >= 0;
        }
        function getPosition(elem) {
            var result = {
                    top: elem.offsetTop,
                    left: elem.offsetLeft
                }, parent = elem.offsetParent;
            while (parent) {
                result.top += parent.offsetTop;
                result.left += parent.offsetLeft;
                var parentOverflowX = $(parent).css('overflowX');
                var parentOverflowY = $(parent).css('overflowY');
                if (parentOverflowY === 'auto' || parentOverflowY === 'scroll') {
                    result.top -= parent.scrollTop;
                }
                if (parentOverflowX === 'auto' || parentOverflowX === 'scroll') {
                    result.left -= parent.scrollLeft;
                }
                parent = parent.offsetParent;
            }
            return result;
        }
        var Window = Widget.extend({
            init: function (element, options) {
                var that = this, wrapper, offset = {}, visibility, display, position, isVisible = false, content, windowContent, windowFrame, globalWindow, suppressActions = options && options.actions && !options.actions.length, id;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                position = options.position;
                element = that.element;
                content = options.content;
                globalWindow = $(window);
                if (suppressActions) {
                    options.actions = [];
                }
                that.appendTo = $(options.appendTo);
                that.containment = options.draggable.containment ? $(options.draggable.containment).first() : null;
                if (content && !isPlainObject(content)) {
                    content = options.content = { url: content };
                }
                element.find('script').filter(executableScript).remove();
                if (!element.parent().is(that.appendTo) && !that.containment && (position.top === undefined || position.left === undefined)) {
                    if (element.is(VISIBLE)) {
                        offset = element.offset();
                        isVisible = true;
                    } else {
                        visibility = element.css('visibility');
                        display = element.css('display');
                        element.css({
                            visibility: HIDDEN,
                            display: ''
                        });
                        offset = element.offset();
                        element.css({
                            visibility: visibility,
                            display: display
                        });
                    }
                    if (position.top === undefined) {
                        position.top = offset.top;
                    }
                    if (position.left === undefined) {
                        position.left = offset.left;
                    }
                }
                if (!defined(options.visible) || options.visible === null) {
                    options.visible = element.is(VISIBLE);
                }
                wrapper = that.wrapper = element.closest(KWINDOW);
                if (!element.is('.k-content') || !wrapper[0]) {
                    element.addClass('k-window-content k-content');
                    that._createWindow(element, options);
                    wrapper = that.wrapper = element.closest(KWINDOW);
                    that.title(that.options.title);
                    that._dimensions();
                }
                that.minTop = that.minLeft = -Infinity;
                that.maxTop = that.maxLeft = Infinity;
                that._position();
                if (content) {
                    that.refresh(content);
                }
                if (options.visible) {
                    that.toFront();
                }
                windowContent = wrapper.children(KWINDOWCONTENT);
                that._tabindex(windowContent);
                if (options.visible && options.modal) {
                    that._overlay(wrapper.is(VISIBLE)).css({ opacity: 0.5 });
                }
                wrapper.on('mouseenter' + NS, TITLEBAR_BUTTONS, proxy(that._buttonEnter, that)).on('mouseleave' + NS, TITLEBAR_BUTTONS, proxy(that._buttonLeave, that)).on('click' + NS, '> ' + TITLEBAR_BUTTONS, proxy(that._windowActionHandler, that)).on('keydown' + NS, proxy(that._keydown, that)).on('focus' + NS, proxy(that._focus, that)).on('blur' + NS, proxy(that._blur, that));
                windowContent.on('keydown' + NS, proxy(that._keydown, that)).on('focus' + NS, proxy(that._focus, that)).on('blur' + NS, proxy(that._blur, that));
                windowFrame = windowContent.find('.' + KCONTENTFRAME)[0];
                if (windowFrame && !globalWindow.data(WINDOWEVENTSHANDLED)) {
                    globalWindow.on('blur' + NS, function () {
                        var element = $(document.activeElement).parent(KWINDOWCONTENT);
                        if (element.length) {
                            var windowInstance = kendo.widgetInstance(element);
                            windowInstance._focus();
                        }
                    });
                    globalWindow.on('focus' + NS, function () {
                        $(KWINDOWCONTENT).not(KDIALOGCONTENT).each(function (i, element) {
                            kendo.widgetInstance($(element))._blur();
                        });
                    });
                    globalWindow.data(WINDOWEVENTSHANDLED, true);
                }
                this._resizable();
                this._draggable();
                if (options.pinned && this.wrapper.is(':visible')) {
                    that.pin();
                }
                id = element.attr('id');
                if (id) {
                    id = id + '_wnd_title';
                    wrapper.children(KWINDOWTITLEBAR).children(KWINDOWTITLE).attr('id', id);
                    windowContent.attr({
                        'role': 'dialog',
                        'aria-labelledby': id
                    });
                }
                wrapper.add(wrapper.children('.k-resize-handle,' + KWINDOWTITLEBAR)).on('mousedown' + NS, proxy(that.toFront, that));
                that.touchScroller = kendo.touchScroller(element);
                that._resizeHandler = proxy(that._onDocumentResize, that);
                that._marker = kendo.guid().substring(0, 8);
                $(window).on('resize' + NS + that._marker, that._resizeHandler);
                if (options.visible) {
                    that.trigger(OPEN);
                    that.trigger(ACTIVATE);
                }
                kendo.notify(that);
                if (this.options.modal) {
                    this._tabKeyTrap = new TabKeyTrap(wrapper);
                    this._tabKeyTrap.trap();
                    this._tabKeyTrap.shouldTrap = function () {
                        return windowContent.data('isFront');
                    };
                }
            },
            _buttonEnter: function (e) {
                $(e.currentTarget).addClass(KHOVERSTATE);
            },
            _buttonLeave: function (e) {
                $(e.currentTarget).removeClass(KHOVERSTATE);
            },
            _focus: function () {
                this.wrapper.addClass(KFOCUSEDSTATE);
            },
            _blur: function () {
                this.wrapper.removeClass(KFOCUSEDSTATE);
            },
            _dimensions: function () {
                var wrapper = this.wrapper;
                var options = this.options;
                var width = options.width;
                var height = options.height;
                var maxHeight = options.maxHeight;
                var sizeClass = options.size;
                var dimensions = [
                    'minWidth',
                    'minHeight',
                    'maxWidth',
                    'maxHeight'
                ];
                var contentBoxSizing = wrapper.css('box-sizing') == 'content-box';
                var lrBorderWidth = contentBoxSizing ? toInt(wrapper, 'border-left-width') + toInt(wrapper, 'border-right-width') : 0;
                var tbBorderWidth = contentBoxSizing ? toInt(wrapper, 'border-top-width') + toInt(wrapper, 'border-bottom-width') : 0;
                var paddingTop = contentBoxSizing ? toInt(wrapper, 'padding-top') : 0;
                if (this.containment && !this._isPinned) {
                    this._updateBoundaries();
                    options.maxHeight = Math.min(this.containment.height - (tbBorderWidth + paddingTop), maxHeight);
                    options.maxWidth = Math.min(this.containment.width - lrBorderWidth, options.maxWidth);
                }
                for (var i = 0; i < dimensions.length; i++) {
                    var value = options[dimensions[i]] || '';
                    if (value != Infinity) {
                        wrapper.css(dimensions[i], value);
                    }
                }
                if (maxHeight != Infinity) {
                    this.element.css('maxHeight', maxHeight);
                }
                if (width) {
                    wrapper.width(constrain(width, options.minWidth, options.maxWidth));
                } else {
                    wrapper.width('');
                }
                if (height) {
                    wrapper.height(constrain(height, options.minHeight, options.maxHeight));
                } else {
                    wrapper.height('');
                }
                if (!options.visible) {
                    wrapper.hide();
                }
                if (sizeClass && SIZE[sizeClass]) {
                    wrapper.addClass(SIZE[sizeClass]);
                }
            },
            _position: function () {
                var wrapper = this.wrapper, position = this.options.position;
                this._updateBoundaries();
                if (this.containment) {
                    position.top = Math.min(this.minTop + (position.top || 0), this.maxTop);
                    position.left = Math.min(this.minLeft + (position.left || 0), this.maxLeft);
                }
                if (position.top === 0) {
                    position.top = position.top.toString();
                }
                if (position.left === 0) {
                    position.left = position.left.toString();
                }
                wrapper.css({
                    top: position.top || '',
                    left: position.left || ''
                });
            },
            _updateBoundaries: function () {
                var containment = this.containment;
                if (!containment) {
                    return null;
                }
                containment.width = containment.innerWidth();
                containment.height = containment.innerHeight();
                if (parseInt(containment.width, 10) > containment[0].clientWidth) {
                    containment.width -= kendo.support.scrollbar();
                }
                if (parseInt(containment.height, 10) > containment[0].clientHeight) {
                    containment.height -= kendo.support.scrollbar();
                }
                containment.position = getPosition(containment[0]);
                if (this._isPinned) {
                    this.minTop = this.minLeft = -Infinity;
                    this.maxTop = this.maxLeft = Infinity;
                } else {
                    this.minTop = containment.scrollTop();
                    this.minLeft = containment.scrollLeft();
                    this.maxLeft = this.minLeft + containment.width - outerWidth(this.wrapper, true);
                    this.maxTop = this.minTop + containment.height - outerHeight(this.wrapper, true);
                }
            },
            _animationOptions: function (id) {
                var animation = this.options.animation;
                var basicAnimation = {
                    open: { effects: {} },
                    close: {
                        hide: true,
                        effects: {}
                    }
                };
                return animation && animation[id] || basicAnimation[id];
            },
            _resize: function () {
                kendo.resize(this.element.children());
            },
            _resizable: function () {
                var resizable = this.options.resizable;
                var wrapper = this.wrapper;
                if (this.resizing) {
                    wrapper.off('dblclick' + NS).children(KWINDOWRESIZEHANDLES).remove();
                    this.resizing.destroy();
                    this.resizing = null;
                }
                if (resizable) {
                    wrapper.on('dblclick' + NS, KWINDOWTITLEBAR, proxy(function (e) {
                        if (!$(e.target).closest('.k-window-action').length) {
                            this.toggleMaximization();
                        }
                    }, this));
                    each('n e s w se sw ne nw'.split(' '), function (index, handler) {
                        wrapper.append(templates.resizeHandle(handler));
                    });
                    this.resizing = new WindowResizing(this);
                }
                wrapper = null;
            },
            _draggable: function () {
                var draggable = this.options.draggable;
                if (this.dragging) {
                    this.dragging.destroy();
                    this.dragging = null;
                }
                if (draggable) {
                    this.dragging = new WindowDragging(this, draggable.dragHandle || KWINDOWTITLEBAR);
                }
            },
            _actions: function () {
                var options = this.options;
                var actions = options.actions;
                var pinned = options.pinned;
                var titlebar = this.wrapper.children(KWINDOWTITLEBAR);
                var container = titlebar.find('.k-window-actions');
                var windowSpecificCommands = [
                    'maximize',
                    'minimize'
                ];
                actions = $.map(actions, function (action) {
                    action = pinned && action.toLowerCase() === 'pin' ? 'unpin' : action;
                    return { name: windowSpecificCommands.indexOf(action.toLowerCase()) > -1 ? 'window-' + action : action };
                });
                container.html(kendo.render(templates.action, actions));
            },
            setOptions: function (options) {
                var that = this;
                var sizeClass = that.options.size;
                var cachedOptions = JSON.parse(JSON.stringify(options));
                extend(options.position, that.options.position);
                extend(options.position, cachedOptions.position);
                Widget.fn.setOptions.call(that, options);
                var scrollable = that.options.scrollable !== false;
                that.restore();
                if (typeof options.title !== 'undefined') {
                    that.title(options.title);
                }
                that.wrapper.removeClass(SIZE[sizeClass]);
                that._dimensions();
                that._position();
                that._resizable();
                that._draggable();
                that._actions();
                if (typeof options.modal !== 'undefined') {
                    var visible = that.options.visible !== false;
                    that._enableDocumentScrolling();
                    that._overlay(options.modal && visible);
                }
                that.element.css(OVERFLOW, scrollable ? '' : 'hidden');
            },
            events: [
                OPEN,
                ACTIVATE,
                DEACTIVATE,
                CLOSE,
                MINIMIZE,
                MAXIMIZE,
                REFRESH,
                RESIZESTART,
                RESIZE,
                RESIZEEND,
                DRAGSTART,
                DRAGEND,
                ERROR
            ],
            options: {
                name: 'Window',
                animation: {
                    open: {
                        effects: {
                            zoom: { direction: 'in' },
                            fade: { direction: 'in' }
                        },
                        duration: 350
                    },
                    close: {
                        effects: {
                            zoom: {
                                direction: 'out',
                                properties: { scale: 0.7 }
                            },
                            fade: { direction: 'out' }
                        },
                        duration: 350,
                        hide: true
                    }
                },
                title: '',
                actions: ['Close'],
                autoFocus: true,
                modal: false,
                size: 'auto',
                resizable: true,
                draggable: true,
                minWidth: 90,
                minHeight: 50,
                maxWidth: Infinity,
                maxHeight: Infinity,
                pinned: false,
                scrollable: true,
                position: {},
                content: null,
                visible: null,
                height: null,
                width: null,
                appendTo: 'body',
                isMaximized: false,
                isMinimized: false
            },
            _closable: function () {
                return $.inArray('close', $.map(this.options.actions, function (x) {
                    return x.toLowerCase();
                })) > -1;
            },
            _keydown: function (e) {
                var that = this, options = that.options, keys = kendo.keys, keyCode = e.keyCode, wrapper = that.wrapper, offset, handled, distance = 10, isMaximized = options.isMaximized, isMinimized = options.isMinimized, newWidth, newHeight, w, h;
                if (keyCode == keys.ESC && that._closable()) {
                    e.stopPropagation();
                    that._close(false);
                }
                if (e.target != e.currentTarget || that._closing) {
                    return;
                }
                if (e.altKey && keyCode == 82) {
                    that.refresh();
                }
                if (e.altKey && keyCode == 80) {
                    if (that.options.pinned) {
                        that.unpin();
                    } else {
                        that.pin();
                    }
                }
                if (e.altKey && keyCode == keys.UP) {
                    if (isMinimized) {
                        that.restore();
                        that.element.focus();
                    } else if (!isMaximized) {
                        that.maximize();
                        that.element.focus();
                    }
                } else if (e.altKey && keyCode == keys.DOWN) {
                    if (!isMinimized && !isMaximized) {
                        that.minimize();
                        that.wrapper.focus();
                    } else if (isMaximized) {
                        that.restore();
                        that.element.focus();
                    }
                }
                offset = kendo.getOffset(wrapper);
                if (that.containment && !that._isPinned) {
                    offset = that.options.position;
                }
                if (options.draggable && !e.ctrlKey && !e.altKey && !isMaximized) {
                    that._updateBoundaries();
                    if (keyCode == keys.UP) {
                        offset.top = constrain(offset.top - distance, that.minTop, that.maxTop);
                        handled = wrapper.css('top', offset.top);
                    } else if (keyCode == keys.DOWN) {
                        offset.top = constrain(offset.top + distance, that.minTop, that.maxTop);
                        handled = wrapper.css('top', offset.top);
                    } else if (keyCode == keys.LEFT) {
                        offset.left = constrain(offset.left - distance, that.minLeft, that.maxLeft);
                        handled = wrapper.css('left', offset.left);
                    } else if (keyCode == keys.RIGHT) {
                        offset.left = constrain(offset.left + distance, that.minLeft, that.maxLeft);
                        handled = wrapper.css('left', offset.left);
                    }
                }
                if (options.resizable && e.ctrlKey && !isMaximized && !isMinimized) {
                    if (keyCode == keys.UP) {
                        handled = true;
                        newHeight = wrapper.height() - distance;
                    } else if (keyCode == keys.DOWN) {
                        handled = true;
                        if (that.containment && !that._isPinned) {
                            newHeight = Math.min(wrapper.height() + distance, that.containment.height - offset.top - toInt(wrapper, 'padding-top') - toInt(wrapper, 'borderBottomWidth') - toInt(wrapper, 'borderTopWidth'));
                        } else {
                            newHeight = wrapper.height() + distance;
                        }
                    }
                    if (keyCode == keys.LEFT) {
                        handled = true;
                        newWidth = wrapper.width() - distance;
                    } else if (keyCode == keys.RIGHT) {
                        handled = true;
                        if (that.containment && !that._isPinned) {
                            newWidth = Math.min(wrapper.width() + distance, that.containment.width - offset.left - toInt(wrapper, 'borderLeftWidth') - toInt(wrapper, 'borderRightWidth'));
                        } else {
                            newWidth = wrapper.width() + distance;
                        }
                    }
                    if (handled) {
                        w = constrain(newWidth, options.minWidth, options.maxWidth);
                        h = constrain(newHeight, options.minHeight, options.maxHeight);
                        if (!isNaN(w)) {
                            wrapper.width(w);
                            that.options.width = w + 'px';
                        }
                        if (!isNaN(h)) {
                            wrapper.height(h);
                            that.options.height = h + 'px';
                        }
                        that.resize();
                    }
                }
                if (handled) {
                    e.preventDefault();
                }
            },
            _overlay: function (visible) {
                var overlay = this.containment ? this.containment.children(KOVERLAY) : this.appendTo.children(KOVERLAY), wrapper = this.wrapper;
                if (!overlay.length) {
                    overlay = $('<div class=\'k-overlay\' />');
                }
                overlay.insertBefore(wrapper[0]).toggle(visible).css(ZINDEX, parseInt(wrapper.css(ZINDEX), 10) - 1);
                if (this.options.modal.preventScroll && !this.containment) {
                    this._stopDocumentScrolling();
                }
                return overlay;
            },
            _actionForIcon: function (icon) {
                var iconClass = /\bk-i(-\w+)+\b/.exec(icon[0].className)[0];
                return {
                    'k-i-close': '_close',
                    'k-i-window-maximize': 'maximize',
                    'k-i-window-minimize': 'minimize',
                    'k-i-window-restore': 'restore',
                    'k-i-refresh': 'refresh',
                    'k-i-pin': 'pin',
                    'k-i-unpin': 'unpin'
                }[iconClass];
            },
            _windowActionHandler: function (e) {
                if (this._closing) {
                    return;
                }
                var icon = $(e.target).closest('.k-window-action').find('.k-icon');
                var action = this._actionForIcon(icon);
                if (action) {
                    e.preventDefault();
                    this[action]();
                    return false;
                }
            },
            _modals: function () {
                var that = this;
                var zStack = $(KWINDOW).filter(function () {
                    var dom = $(this);
                    var object = that._object(dom);
                    var options = object && object.options;
                    return options && options.modal && options.visible && options.appendTo === that.options.appendTo && dom.is(VISIBLE);
                }).sort(function (a, b) {
                    return +$(a).css('zIndex') - +$(b).css('zIndex');
                });
                that = null;
                return zStack;
            },
            _object: function (element) {
                var content = element.children(KWINDOWCONTENT);
                var widget = kendo.widgetInstance(content);
                if (widget) {
                    return widget;
                }
                return undefined;
            },
            center: function () {
                var that = this, position = that.options.position, wrapper = that.wrapper, documentWindow = $(window), scrollTop = 0, scrollLeft = 0, newTop, newLeft;
                if (that.options.isMaximized) {
                    return that;
                }
                if (that.options.pinned && !that._isPinned) {
                    that.pin();
                }
                if (!that.options.pinned) {
                    scrollTop = documentWindow.scrollTop();
                    scrollLeft = documentWindow.scrollLeft();
                }
                if (this.containment && !that.options.pinned) {
                    newTop = this.minTop + (this.maxTop - this.minTop) / 2;
                    newLeft = this.minLeft + (this.maxLeft - this.minLeft) / 2;
                } else {
                    that._scrollIsAppended = true;
                    newLeft = scrollLeft + Math.max(0, (documentWindow.width() - wrapper.width()) / 2);
                    newTop = scrollTop + Math.max(0, (documentWindow.height() - wrapper.height() - toInt(wrapper, 'paddingTop')) / 2);
                }
                wrapper.css({
                    left: newLeft,
                    top: newTop
                });
                position.top = newTop;
                position.left = newLeft;
                return that;
            },
            title: function (title) {
                var that = this, value, encoded = true, wrapper = that.wrapper, titleBar = wrapper.children(KWINDOWTITLEBAR), titleElement = titleBar.children(KWINDOWTITLE), titleBarHeight, display, visibility;
                if (!arguments.length) {
                    return titleElement.html();
                }
                if ($.isPlainObject(title)) {
                    value = typeof title.text !== 'undefined' ? title.text : '';
                    encoded = title.encoded !== false;
                } else {
                    value = title;
                }
                if (value === false) {
                    wrapper.addClass('k-window-titleless');
                    titleBar.remove();
                } else {
                    if (!titleBar.length) {
                        wrapper.prepend(templates.titlebar({ title: encoded ? kendo.htmlEncode(value) : value }));
                        that._actions();
                        titleBar = wrapper.children(KWINDOWTITLEBAR);
                    } else {
                        titleElement.html(encoded ? kendo.htmlEncode(value) : value);
                    }
                    visibility = wrapper.css('visibility');
                    display = wrapper.css('display');
                    if (visibility === HIDDEN) {
                        wrapper.css({ display: '' });
                        titleBarHeight = parseInt(outerHeight(titleBar), 10);
                        wrapper.css({ display: display });
                    } else {
                        wrapper.css({
                            visibility: HIDDEN,
                            display: ''
                        });
                        titleBarHeight = parseInt(outerHeight(titleBar), 10);
                        wrapper.css({
                            visibility: visibility,
                            display: display
                        });
                    }
                    wrapper.css('padding-top', titleBarHeight);
                    titleBar.css('margin-top', -titleBarHeight);
                }
                that.options.title = value;
                return that;
            },
            content: function (html, data) {
                var content = this.wrapper.children(KWINDOWCONTENT), scrollContainer = content.children('.km-scroll-container');
                content = scrollContainer[0] ? scrollContainer : content;
                if (!defined(html)) {
                    return content.html();
                }
                this.angular('cleanup', function () {
                    return { elements: content.children() };
                });
                kendo.destroy(this.element.children());
                content.empty().html(html);
                this.angular('compile', function () {
                    var a = [];
                    for (var i = content.length; --i >= 0;) {
                        a.push({ dataItem: data });
                    }
                    return {
                        elements: content.children(),
                        data: a
                    };
                });
                return this;
            },
            open: function () {
                var that = this, wrapper = that.wrapper, options = that.options, showOptions = this._animationOptions('open'), contentElement = wrapper.children(KWINDOWCONTENT), overlay, otherModalsVisible, containmentContext = this.containment && !that._isPinned, doc = containmentContext ? this.containment : $(document);
                if (!that.trigger(OPEN)) {
                    if (that._closing) {
                        wrapper.kendoStop(true, true);
                    }
                    that._closing = false;
                    that.toFront();
                    if (options.autoFocus) {
                        that.element.focus();
                    }
                    options.visible = true;
                    if (options.modal) {
                        otherModalsVisible = !!that._modals().length;
                        overlay = that._overlay(otherModalsVisible);
                        overlay.kendoStop(true, true);
                        if (showOptions.duration && kendo.effects.Fade && !otherModalsVisible) {
                            var overlayFx = kendo.fx(overlay).fadeIn();
                            overlayFx.duration(showOptions.duration || 0);
                            overlayFx.endValue(0.5);
                            overlayFx.play();
                        } else {
                            overlay.css('opacity', 0.5);
                        }
                        overlay.show();
                        $(window).on('focus' + MODAL_NS, function () {
                            if (contentElement.data('isFront') && !$(document.activeElement).closest(contentElement).length) {
                                that.element.focus();
                            }
                        });
                    }
                    if (!wrapper.is(VISIBLE)) {
                        contentElement.css(OVERFLOW, HIDDEN);
                        wrapper.show().kendoStop().kendoAnimate({
                            effects: showOptions.effects,
                            duration: showOptions.duration,
                            complete: proxy(this._activate, this)
                        });
                    }
                }
                if (options.isMaximized) {
                    that._containerScrollTop = doc.scrollTop();
                    that._containerScrollLeft = doc.scrollLeft();
                    that._stopDocumentScrolling();
                }
                if (this.options.pinned && !this._isPinned) {
                    this.pin();
                }
                return that;
            },
            _activate: function () {
                var scrollable = this.options.scrollable !== false;
                if (this.options.autoFocus) {
                    this.element.focus();
                }
                this.element.css(OVERFLOW, scrollable ? '' : 'hidden');
                kendo.resize(this.element.children());
                this.trigger(ACTIVATE);
            },
            _removeOverlay: function (suppressAnimation) {
                var modals = this._modals();
                var options = this.options;
                var hideOverlay = options.modal && !modals.length;
                var overlay = options.modal ? this._overlay(true) : $(undefined);
                var hideOptions = this._animationOptions('close');
                if (hideOverlay) {
                    if (!suppressAnimation && hideOptions.duration && kendo.effects.Fade) {
                        var overlayFx = kendo.fx(overlay).fadeOut();
                        overlayFx.duration(hideOptions.duration || 0);
                        overlayFx.startValue(0.5);
                        overlayFx.play();
                    } else {
                        this._overlay(false).remove();
                    }
                    if (options.modal.preventScroll) {
                        this._enableDocumentScrolling();
                    }
                } else if (modals.length) {
                    this._object(modals.last())._overlay(true);
                    if (options.modal.preventScroll) {
                        this._stopDocumentScrolling();
                    }
                }
            },
            _close: function (systemTriggered) {
                var that = this, wrapper = that.wrapper, options = that.options, showOptions = this._animationOptions('open'), hideOptions = this._animationOptions('close'), containmentContext = this.containment && !that._isPinned, doc = containmentContext ? this.containment : $(document), defaultPrevented;
                if (that._closing) {
                    return;
                }
                defaultPrevented = that.trigger(CLOSE, { userTriggered: !systemTriggered });
                that._closing = !defaultPrevented;
                if (wrapper.is(VISIBLE) && !defaultPrevented) {
                    options.visible = false;
                    $(KWINDOW).each(function (i, element) {
                        var contentElement = $(element).children(KWINDOWCONTENT);
                        if (element != wrapper && contentElement.find('> .' + KCONTENTFRAME).length > 0) {
                            contentElement.children(KOVERLAY).remove();
                        }
                    });
                    this._removeOverlay();
                    wrapper.kendoStop().kendoAnimate({
                        effects: hideOptions.effects || showOptions.effects,
                        reverse: hideOptions.reverse === true,
                        duration: hideOptions.duration,
                        complete: proxy(this._deactivate, this)
                    });
                    $(window).off(MODAL_NS);
                }
                if (that.options.isMaximized) {
                    that._enableDocumentScrolling();
                    if (that._containerScrollTop && that._containerScrollTop > 0) {
                        doc.scrollTop(that._containerScrollTop);
                    }
                    if (that._containerScrollLeft && that._containerScrollLeft > 0) {
                        doc.scrollLeft(that._containerScrollLeft);
                    }
                }
            },
            _deactivate: function () {
                var that = this;
                that.wrapper.hide().css('opacity', '');
                that.trigger(DEACTIVATE);
                if (that.options.modal) {
                    var lastModal = that._object(that._modals().last());
                    if (lastModal) {
                        lastModal.toFront();
                    }
                }
            },
            close: function () {
                this._close(true);
                return this;
            },
            _actionable: function (element) {
                return $(element).is(TITLEBAR_BUTTONS + ',' + TITLEBAR_BUTTONS + ' .k-icon,:input,a');
            },
            _shouldFocus: function (target) {
                var active = activeElement(), element = this.element;
                return this.options.autoFocus && !$(active).is(element) && !this._actionable(target) && (!element.find(active).length || !element.find(target).length);
            },
            toFront: function (e) {
                var that = this, wrapper = that.wrapper, currentWindow = wrapper[0], containmentContext = that.containment && !that._isPinned, zIndex = +wrapper.css(ZINDEX), originalZIndex = zIndex, target = e && e.target || null;
                $(KWINDOW).each(function (i, element) {
                    var windowObject = $(element), zIndexNew = windowObject.css(ZINDEX), contentElement = windowObject.children(KWINDOWCONTENT);
                    if (!isNaN(zIndexNew)) {
                        zIndex = Math.max(+zIndexNew, zIndex);
                    }
                    contentElement.data('isFront', element == currentWindow);
                    if (element != currentWindow && contentElement.find('> .' + KCONTENTFRAME).length > 0) {
                        contentElement.append(templates.overlay);
                    }
                });
                if (!wrapper[0].style.zIndex || originalZIndex < zIndex) {
                    wrapper.css(ZINDEX, zIndex + 2);
                }
                that.element.find('> .k-overlay').remove();
                if (that._shouldFocus(target)) {
                    if (that.isMinimized()) {
                        that.wrapper.focus();
                    } else if ($(target).is(KOVERLAY)) {
                        setTimeout(function () {
                            that.element.focus();
                        });
                    } else {
                        that.element.focus();
                    }
                    var scrollTop = containmentContext ? that.containment.scrollTop() : $(window).scrollTop(), windowTop = parseInt(wrapper.position().top, 10);
                    if (!that.options.pinned && windowTop > 0 && windowTop < scrollTop) {
                        if (scrollTop > 0) {
                            $(window).scrollTop(windowTop);
                        } else {
                            wrapper.css('top', scrollTop);
                        }
                    }
                }
                wrapper = null;
                return that;
            },
            toggleMaximization: function () {
                if (this._closing) {
                    return this;
                }
                return this[this.options.isMaximized ? 'restore' : 'maximize']();
            },
            restore: function () {
                var that = this;
                var options = that.options;
                var minHeight = options.minHeight;
                var restoreOptions = that.restoreOptions;
                var shouldRestrictTop;
                var container = that.containment && !that._isPinned ? that.containment : $(document);
                if (!options.isMaximized && !options.isMinimized) {
                    return that;
                }
                if (minHeight && minHeight != Infinity) {
                    that.wrapper.css('min-height', minHeight);
                }
                if (restoreOptions && !options.isMaximized) {
                    restoreOptions.height = constrain(restoreOptions.height, that.options.minHeight, that.options.maxHeight);
                    shouldRestrictTop = options.position.top + parseInt(restoreOptions.height, 10) > that.maxTop;
                    if (shouldRestrictTop) {
                        options.position.top = constrain(options.position.top, that.minTop, that.maxTop - parseInt(restoreOptions.height, 10));
                        extend(restoreOptions, {
                            left: options.position.left,
                            top: options.position.top
                        });
                    }
                }
                that.wrapper.css({
                    position: options.pinned ? 'fixed' : 'absolute',
                    left: restoreOptions.left,
                    top: restoreOptions.top,
                    width: restoreOptions.width,
                    height: restoreOptions.height
                }).removeClass(MAXIMIZEDSTATE).find('.k-window-content,.k-resize-handle').show().end().find('.k-window-titlebar .k-i-window-restore').parent().remove().end().end().find(MINIMIZE_MAXIMIZE).parent().show().end().end().find(PIN_UNPIN).parent().show();
                if (options.isMaximized) {
                    that.wrapper.find('.k-i-window-maximize').parent().focus();
                } else if (options.isMinimized) {
                    that.wrapper.find('.k-i-window-minimize').parent().focus();
                }
                that.options.width = restoreOptions.width;
                that.options.height = restoreOptions.height;
                if (!that.options.modal.preventScroll) {
                    that._enableDocumentScrolling();
                }
                if (that._containerScrollTop && that._containerScrollTop > 0) {
                    container.scrollTop(that._containerScrollTop);
                }
                if (that._containerScrollLeft && that._containerScrollLeft > 0) {
                    container.scrollLeft(that._containerScrollLeft);
                }
                options.isMaximized = options.isMinimized = false;
                that.wrapper.removeAttr('tabindex');
                that.wrapper.removeAttr('aria-labelled-by');
                that.resize();
                return that;
            },
            _sizingAction: function (actionId, callback) {
                var that = this, wrapper = that.wrapper, style = wrapper[0].style, options = that.options;
                if (options.isMaximized || options.isMinimized) {
                    return that;
                }
                that.restoreOptions = {
                    width: style.width,
                    height: style.height
                };
                wrapper.children(KWINDOWRESIZEHANDLES).hide().end().children(KWINDOWTITLEBAR).find(MINIMIZE_MAXIMIZE).parent().hide().eq(0).before(templates.action({ name: 'window-restore' }));
                callback.call(that);
                that.wrapper.children(KWINDOWTITLEBAR).find(PIN_UNPIN).parent().toggle(actionId !== 'maximize');
                that.trigger(actionId);
                wrapper.find('.k-i-window-restore').parent().focus();
                return that;
            },
            maximize: function () {
                this._sizingAction('maximize', function () {
                    var that = this, wrapper = that.wrapper, containmentContext = this.containment && !that._isPinned, position = wrapper.position(), doc = $(document);
                    extend(that.restoreOptions, {
                        left: position.left + (containmentContext ? this.containment.scrollLeft() : 0),
                        top: position.top + (containmentContext ? this.containment.scrollTop() : 0)
                    });
                    this._containerScrollTop = containmentContext ? this.containment.scrollTop() : doc.scrollTop();
                    this._containerScrollLeft = containmentContext ? this.containment.scrollLeft() : doc.scrollLeft();
                    that._stopDocumentScrolling();
                    wrapper.css({
                        top: containmentContext ? this.containment.scrollTop() : 0,
                        left: containmentContext ? this.containment.scrollLeft() : 0,
                        position: containmentContext ? 'absolute' : 'fixed'
                    }).addClass(MAXIMIZEDSTATE);
                    that.options.isMaximized = true;
                    that._onDocumentResize();
                });
                return this;
            },
            _stopDocumentScrolling: function () {
                var that = this;
                var containment = that.containment;
                if (containment && !that._isPinned) {
                    that._storeOverflowRule(containment);
                    containment.css(OVERFLOW, HIDDEN);
                    that.wrapper.css({
                        maxWidth: containment.innerWidth(),
                        maxHeight: containment.innerHeight()
                    });
                    return;
                }
                var $body = $('body');
                that._storeOverflowRule($body);
                $body.css(OVERFLOW, HIDDEN);
                var $html = $('html');
                that._storeOverflowRule($html);
                $html.css(OVERFLOW, HIDDEN);
            },
            _enableDocumentScrolling: function () {
                var that = this;
                var containment = that.containment;
                if (containment && !that._isPinned) {
                    that._restoreOverflowRule(containment);
                    that.wrapper.css({
                        maxWidth: containment.width,
                        maxHeight: containment.height
                    });
                    return;
                }
                that._restoreOverflowRule($(document.body));
                that._restoreOverflowRule($('html'));
            },
            _storeOverflowRule: function ($element) {
                if (this._isOverflowStored($element)) {
                    return;
                }
                var overflowRule = $element.get(0).style.overflow;
                if (typeof overflowRule === 'string') {
                    $element.data(DATADOCOVERFLOWRULE, overflowRule);
                }
            },
            _isOverflowStored: function ($element) {
                return typeof $element.data(DATADOCOVERFLOWRULE) === 'string';
            },
            _restoreOverflowRule: function ($element) {
                var overflowRule = $element.data(DATADOCOVERFLOWRULE);
                if (overflowRule !== null && overflowRule !== undefined) {
                    $element.css(OVERFLOW, overflowRule);
                    $element.removeData(DATADOCOVERFLOWRULE);
                } else {
                    $element.css(OVERFLOW, '');
                }
            },
            isMaximized: function () {
                return this.options.isMaximized;
            },
            minimize: function () {
                this._sizingAction('minimize', function () {
                    var that = this;
                    that.wrapper.css({
                        height: '',
                        minHeight: ''
                    });
                    that.element.hide();
                    that.options.isMinimized = true;
                });
                this.wrapper.attr('tabindex', 0);
                this.wrapper.attr('aria-labelled-by', this.element.attr('aria-labelled-by'));
                this._updateBoundaries();
                return this;
            },
            isMinimized: function () {
                return this.options.isMinimized;
            },
            pin: function () {
                var that = this, win = $(window), wrapper = that.wrapper, options = that.options, position = options.position, top = this.containment ? getPosition(wrapper[0]).top + toInt(this.containment, 'borderTopWidth') : toInt(wrapper, 'top'), left = this.containment ? getPosition(wrapper[0]).left + toInt(this.containment, 'borderLeftWidth') : toInt(wrapper, 'left');
                if (!that.options.isMaximized) {
                    position.top = top;
                    position.left = left;
                    if (that._scrollIsAppended && (!this.containment || this.containment.css('position') !== 'fixed')) {
                        position.top -= win.scrollTop();
                        position.left -= win.scrollLeft();
                        that._scrollIsAppended = false;
                    }
                    wrapper.css(extend(position, { position: 'fixed' }));
                    wrapper.children(KWINDOWTITLEBAR).find(KPIN).addClass('k-i-unpin').removeClass('k-i-pin');
                    that._isPinned = true;
                    that.options.pinned = true;
                    if (this.containment) {
                        options.maxWidth = options.maxHeight = Infinity;
                        wrapper.css({
                            maxWidth: '',
                            maxHeight: ''
                        });
                    }
                }
            },
            unpin: function () {
                var that = this, win = $(window), wrapper = that.wrapper, options = that.options, position = that.options.position, containment = that.containment, top = parseInt(wrapper.css('top'), 10) + win.scrollTop(), left = parseInt(wrapper.css('left'), 10) + win.scrollLeft();
                if (!that.options.isMaximized) {
                    that._isPinned = false;
                    that._scrollIsAppended = true;
                    that.options.pinned = false;
                    if (containment) {
                        that._updateBoundaries();
                        options.maxWidth = Math.min(containment.width, options.maxWidth);
                        options.maxHeight = Math.min(containment.height - toInt(wrapper, 'padding-top'), options.maxHeight);
                        wrapper.css({
                            maxWidth: options.maxWidth,
                            maxHeight: options.maxHeight
                        });
                        if (top < containment.position.top) {
                            top = that.minTop;
                        } else if (top > containment.position.top + containment.height) {
                            top = that.maxTop;
                        } else {
                            top = top + containment.scrollTop() - (containment.position.top + toInt(containment, 'border-top-width'));
                        }
                        if (left < containment.position.left) {
                            left = that.minLeft;
                        } else if (left > containment.position.left + containment.width) {
                            left = that.maxLeft;
                        } else {
                            left = left + containment.scrollLeft() - (containment.position.left + toInt(containment, 'border-left-width'));
                        }
                    }
                    position.top = constrain(top, that.minTop, that.maxTop);
                    position.left = constrain(left, that.minLeft, that.maxLeft);
                    wrapper.css(extend(position, { position: '' }));
                    wrapper.children(KWINDOWTITLEBAR).find(KUNPIN).addClass('k-i-pin').removeClass('k-i-unpin');
                }
            },
            _onDocumentResize: function () {
                var that = this, wrapper = that.wrapper, wnd = $(window), zoomLevel = kendo.support.zoomLevel(), contentBoxSizing = wrapper.css('box-sizing') == 'content-box', w, h;
                if (!that.options.isMaximized) {
                    return;
                }
                var lrBorderWidth = contentBoxSizing ? toInt(wrapper, 'border-left-width') + toInt(wrapper, 'border-right-width') : 0;
                var tbBorderWidth = contentBoxSizing ? toInt(wrapper, 'border-top-width') + toInt(wrapper, 'border-bottom-width') : 0;
                var paddingTop = contentBoxSizing ? toInt(wrapper, 'padding-top') : 0;
                if (that.containment && !that._isPinned) {
                    w = that.containment.innerWidth() - lrBorderWidth;
                    h = that.containment.innerHeight() - (tbBorderWidth + paddingTop);
                } else {
                    w = wnd.width() / zoomLevel - lrBorderWidth;
                    h = wnd.height() / zoomLevel - (tbBorderWidth + paddingTop);
                }
                wrapper.css({
                    width: w,
                    height: h
                });
                that.options.width = w;
                that.options.height = h;
                that.resize();
            },
            refresh: function (options) {
                var that = this, initOptions = that.options, element = $(that.element), iframe, showIframe, url;
                if (!isPlainObject(options)) {
                    options = { url: options };
                }
                options = extend({}, initOptions.content, options);
                showIframe = defined(initOptions.iframe) ? initOptions.iframe : options.iframe;
                url = options.url;
                if (url) {
                    if (!defined(showIframe)) {
                        showIframe = !isLocalUrl(url);
                    }
                    if (!showIframe) {
                        that._ajaxRequest(options);
                    } else {
                        iframe = element.find('.' + KCONTENTFRAME)[0];
                        if (iframe) {
                            iframe.src = url || iframe.src;
                        } else {
                            element.html(templates.contentFrame(extend({}, initOptions, { content: options })));
                        }
                        element.find('.' + KCONTENTFRAME).unbind('load' + NS).on('load' + NS, proxy(this._triggerRefresh, this));
                    }
                } else {
                    if (options.template) {
                        that.content(template(options.template)({}));
                    }
                    that.trigger(REFRESH);
                }
                element.toggleClass('k-window-iframecontent', !!showIframe);
                return that;
            },
            _triggerRefresh: function () {
                this.trigger(REFRESH);
            },
            _ajaxComplete: function () {
                clearTimeout(this._loadingIconTimeout);
                this.wrapper.find(REFRESHICON).removeClass(LOADING);
            },
            _ajaxError: function (xhr, status) {
                this.trigger(ERROR, {
                    status: status,
                    xhr: xhr
                });
            },
            _ajaxSuccess: function (contentTemplate) {
                return function (data) {
                    var html = data;
                    if (contentTemplate) {
                        html = template(contentTemplate)(data || {});
                    }
                    this.content(html, data);
                    this.element.prop('scrollTop', 0);
                    this.trigger(REFRESH);
                };
            },
            _showLoading: function () {
                this.wrapper.find(REFRESHICON).addClass(LOADING);
            },
            _ajaxRequest: function (options) {
                this._loadingIconTimeout = setTimeout(proxy(this._showLoading, this), 100);
                $.ajax(extend({
                    type: 'GET',
                    dataType: 'html',
                    cache: false,
                    error: proxy(this._ajaxError, this),
                    complete: proxy(this._ajaxComplete, this),
                    success: proxy(this._ajaxSuccess(options.template), this)
                }, options));
            },
            _destroy: function () {
                if (this.resizing) {
                    this.resizing.destroy();
                }
                if (this.dragging) {
                    this.dragging.destroy();
                }
                this.wrapper.off(NS).children(KWINDOWCONTENT).off(NS).end().find('.k-resize-handle,.k-window-titlebar').off(NS);
                $(window).off('resize' + NS + this._marker);
                $(window).off(MODAL_NS);
                $(window).off(NS);
                clearTimeout(this._loadingIconTimeout);
                Widget.fn.destroy.call(this);
                this.unbind(undefined);
                kendo.destroy(this.wrapper);
                this._removeOverlay(true);
            },
            destroy: function () {
                this._destroy();
                this.wrapper.empty().remove();
                this.wrapper = this.appendTo = this.element = $();
            },
            _createWindow: function () {
                var contentHtml = this.element, options = this.options, iframeSrcAttributes, wrapper, isRtl = kendo.support.isRtl(contentHtml);
                if (options.scrollable === false) {
                    contentHtml.css('overflow', 'hidden');
                }
                wrapper = $(templates.wrapper(options));
                iframeSrcAttributes = contentHtml.find('iframe:not(.k-content)').map(function () {
                    var src = this.getAttribute('src');
                    this.src = '';
                    return src;
                });
                wrapper.toggleClass('k-rtl', isRtl).append(contentHtml).find('iframe:not(.k-content)').each(function (index) {
                    this.src = iframeSrcAttributes[index];
                });
                if (this.containment) {
                    this.containment.prepend(wrapper);
                } else if (this.appendTo) {
                    wrapper.appendTo(this.appendTo);
                }
                wrapper.find('.k-window-title').css(isRtl ? 'left' : 'right', outerWidth(wrapper.find('.k-window-actions')) + 10);
                contentHtml.css('visibility', '').show();
                contentHtml.find('[data-role=editor]').each(function () {
                    var editor = $(this).data('kendoEditor');
                    if (editor) {
                        editor.refresh();
                    }
                });
                wrapper = contentHtml = null;
            }
        });
        templates = {
            wrapper: template('<div class=\'k-widget k-window\' />'),
            action: template('<a role=\'button\' href=\'\\#\' class=\'k-button k-bare k-button-icon k-window-action\' aria-label=\'#= name #\'>' + '<span class=\'k-icon k-i-#= name.toLowerCase() #\'></span>' + '</a>'),
            titlebar: template('<div class=\'k-window-titlebar k-header\'>' + '<span class=\'k-window-title\'>#= title #</span>' + '<div class=\'k-window-actions\' />' + '</div>'),
            overlay: '<div class=\'k-overlay\' />',
            contentFrame: template('<iframe frameborder=\'0\' title=\'#= title #\' class=\'' + KCONTENTFRAME + '\' ' + 'src=\'#= content.url #\'>' + 'This page requires frames in order to show content' + '</iframe>'),
            resizeHandle: template('<div class=\'k-resize-handle k-resize-#= data #\'></div>')
        };
        function WindowResizing(wnd) {
            var that = this;
            that.owner = wnd;
            that._preventDragging = false;
            that._draggable = new Draggable(wnd.wrapper, {
                filter: '>' + KWINDOWRESIZEHANDLES,
                group: wnd.wrapper.id + '-resizing',
                dragstart: proxy(that.dragstart, that),
                drag: proxy(that.drag, that),
                dragend: proxy(that.dragend, that)
            });
            that._draggable.userEvents.bind('press', proxy(that.addOverlay, that));
            that._draggable.userEvents.bind('release', proxy(that.removeOverlay, that));
        }
        WindowResizing.prototype = {
            addOverlay: function () {
                this.owner.wrapper.append(templates.overlay);
            },
            removeOverlay: function () {
                this.owner.wrapper.find(KOVERLAY).remove();
            },
            dragstart: function (e) {
                var that = this;
                var wnd = that.owner;
                var wrapper = wnd.wrapper;
                that._preventDragging = wnd.trigger(RESIZESTART);
                if (that._preventDragging) {
                    return;
                }
                that.elementPadding = parseInt(wrapper.css('padding-top'), 10);
                that.initialPosition = kendo.getOffset(wrapper, 'position');
                that.resizeDirection = e.currentTarget.prop('className').replace('k-resize-handle k-resize-', '');
                that.initialSize = {
                    width: wrapper.width(),
                    height: wrapper.height()
                };
                wnd._updateBoundaries();
                that.containerOffset = wnd.containment ? wnd.containment.position : kendo.getOffset(wnd.appendTo, 'position');
                var offsetParent = wrapper.offsetParent();
                if (offsetParent.is('html')) {
                    that.containerOffset.top = that.containerOffset.left = 0;
                } else {
                    var marginTop = offsetParent.css('margin-top');
                    var marginLeft = offsetParent.css('margin-left');
                    var hasMargin = !zero.test(marginTop) || !zero.test(marginLeft);
                    if (hasMargin) {
                        var wrapperPosition = getPosition(wrapper[0]);
                        var relativeElMarginLeft = wrapperPosition.left - that.containerOffset.left - that.initialPosition.left;
                        var relativeElMarginTop = wrapperPosition.top - that.containerOffset.top - that.initialPosition.top;
                        that._relativeElMarginLeft = relativeElMarginLeft > 1 ? relativeElMarginLeft : 0;
                        that._relativeElMarginTop = relativeElMarginTop > 1 ? relativeElMarginTop : 0;
                        that.initialPosition.left += that._relativeElMarginLeft;
                        that.initialPosition.top += that._relativeElMarginTop;
                    }
                }
                wrapper.children(KWINDOWRESIZEHANDLES).not(e.currentTarget).hide();
                $(BODY).css(CURSOR, e.currentTarget.css(CURSOR));
            },
            drag: function (e) {
                if (this._preventDragging) {
                    return;
                }
                var that = this, wnd = that.owner, wrapper = wnd.wrapper, options = wnd.options, position = options.position, direction = that.resizeDirection, containerOffset = that.containerOffset, initialPosition = that.initialPosition, initialSize = that.initialSize, containmentContext = wnd.containment && !wnd._isPinned, rtl = kendo.support.isRtl(wnd.containment), leftRtlOffset = containmentContext && rtl && wnd.containment.innerWidth() > wnd.containment.width ? kendo.support.scrollbar() : 0, scrollOffset = containmentContext ? {
                        top: wnd.containment.scrollTop(),
                        left: wnd.containment.scrollLeft()
                    } : {
                        top: 0,
                        left: 0
                    }, newWidth, newHeight, windowBottom, windowRight, x = Math.max(e.x.location, 0), y = Math.max(e.y.location, 0);
                if (direction.indexOf('e') >= 0) {
                    if (wnd.containment && x - initialSize.width >= wnd.maxLeft - scrollOffset.left + containerOffset.left + leftRtlOffset) {
                        newWidth = wnd.maxLeft + leftRtlOffset - initialPosition.left + initialSize.width - scrollOffset.left;
                    } else {
                        newWidth = x - initialPosition.left - containerOffset.left;
                    }
                    wrapper.width(constrain(newWidth, options.minWidth, options.maxWidth));
                } else if (direction.indexOf('w') >= 0) {
                    windowRight = initialPosition.left + initialSize.width + containerOffset.left;
                    newWidth = constrain(windowRight - x, options.minWidth, options.maxWidth);
                    position.left = windowRight - newWidth - containerOffset.left - leftRtlOffset - (that._relativeElMarginLeft || 0) + scrollOffset.left;
                    if (wnd.containment && position.left <= wnd.minLeft) {
                        position.left = wnd.minLeft;
                        newWidth = constrain(windowRight - leftRtlOffset - position.left - containerOffset.left + scrollOffset.left, options.minWidth, options.maxWidth);
                    }
                    wrapper.css({
                        left: position.left,
                        width: newWidth
                    });
                }
                var newWindowTop = y;
                if (wnd.options.pinned) {
                    newWindowTop -= $(window).scrollTop();
                }
                if (direction.indexOf('s') >= 0) {
                    newHeight = newWindowTop - initialPosition.top - that.elementPadding - containerOffset.top;
                    if (newWindowTop - initialSize.height - that.elementPadding >= wnd.maxTop + containerOffset.top - scrollOffset.top) {
                        newHeight = wnd.maxTop - initialPosition.top + initialSize.height - scrollOffset.top;
                    }
                    wrapper.height(constrain(newHeight, options.minHeight, options.maxHeight));
                } else if (direction.indexOf('n') >= 0) {
                    windowBottom = initialPosition.top + initialSize.height + containerOffset.top;
                    newHeight = constrain(windowBottom - newWindowTop, options.minHeight, options.maxHeight);
                    position.top = windowBottom - newHeight - containerOffset.top - (that._relativeElMarginTop || 0) + scrollOffset.top;
                    if (position.top <= wnd.minTop && wnd.containment) {
                        position.top = wnd.minTop;
                        newHeight = constrain(windowBottom - position.top - containerOffset.top + scrollOffset.top, options.minHeight, options.maxHeight);
                    }
                    wrapper.css({
                        top: position.top,
                        height: newHeight
                    });
                }
                if (newWidth) {
                    wnd.options.width = newWidth + 'px';
                }
                if (newHeight) {
                    wnd.options.height = newHeight + 'px';
                }
                wnd.resize();
            },
            dragend: function (e) {
                if (this._preventDragging) {
                    return;
                }
                var that = this, wnd = that.owner, wrapper = wnd.wrapper;
                wrapper.children(KWINDOWRESIZEHANDLES).not(e.currentTarget).show();
                $(BODY).css(CURSOR, '');
                if (wnd.touchScroller) {
                    wnd.touchScroller.reset();
                }
                if (e.keyCode == 27) {
                    wrapper.css(that.initialPosition).css(that.initialSize);
                }
                wnd.trigger(RESIZEEND);
                return false;
            },
            destroy: function () {
                if (this._draggable) {
                    this._draggable.destroy();
                }
                this._draggable = this.owner = null;
            }
        };
        function WindowDragging(wnd, dragHandle) {
            var that = this;
            that.owner = wnd;
            that._preventDragging = false;
            that._draggable = new Draggable(wnd.wrapper, {
                filter: dragHandle,
                group: wnd.wrapper.id + '-moving',
                dragstart: proxy(that.dragstart, that),
                drag: proxy(that.drag, that),
                dragend: proxy(that.dragend, that),
                dragcancel: proxy(that.dragcancel, that)
            });
            that._draggable.userEvents.stopPropagation = false;
        }
        WindowDragging.prototype = {
            dragstart: function (e) {
                var wnd = this.owner, draggable = wnd.options.draggable, element = wnd.element, actions = element.find('.k-window-actions'), containerOffset = kendo.getOffset(wnd.appendTo);
                this._preventDragging = wnd.trigger(DRAGSTART) || !draggable;
                if (this._preventDragging || wnd.isMaximized()) {
                    return;
                }
                wnd.initialWindowPosition = kendo.getOffset(wnd.wrapper, 'position');
                wnd.initialPointerPosition = {
                    left: wnd.options.position.left,
                    top: wnd.options.position.top
                };
                wnd.startPosition = {
                    left: e.x.client - wnd.initialWindowPosition.left,
                    top: e.y.client - wnd.initialWindowPosition.top
                };
                wnd._updateBoundaries();
                if (!wnd.containment) {
                    if (actions.length > 0) {
                        wnd.minLeft = outerWidth(actions) + parseInt(actions.css('right'), 10) - outerWidth(element);
                    } else {
                        wnd.minLeft = 20 - outerWidth(element);
                    }
                    wnd.minLeft -= containerOffset.left;
                    wnd.minTop = -containerOffset.top;
                }
                wnd.wrapper.append(templates.overlay).children(KWINDOWRESIZEHANDLES).hide();
                $(BODY).css(CURSOR, e.currentTarget.css(CURSOR));
            },
            drag: function (e) {
                var wnd = this.owner;
                var position = wnd.options.position;
                var axis = wnd.options.draggable.axis;
                var left;
                var top;
                if (this._preventDragging || wnd.isMaximized()) {
                    return;
                }
                if (!axis || axis.toLowerCase() === 'x') {
                    left = e.x.client - wnd.startPosition.left;
                    if (wnd.containment && !wnd._isPinned) {
                        left += wnd.containment.scrollLeft();
                    }
                    position.left = constrain(left, wnd.minLeft, wnd.maxLeft);
                }
                if (!axis || axis.toLowerCase() === 'y') {
                    top = e.y.client - wnd.startPosition.top;
                    if (wnd.containment && !wnd._isPinned) {
                        top += wnd.containment.scrollTop();
                    }
                    position.top = constrain(top, wnd.minTop, wnd.maxTop);
                }
                if (kendo.support.transforms) {
                    $(wnd.wrapper).css('transform', 'translate(' + (position.left - wnd.initialPointerPosition.left) + 'px, ' + (position.top - wnd.initialPointerPosition.top) + 'px)');
                } else {
                    $(wnd.wrapper).css(position);
                }
            },
            _finishDrag: function () {
                var wnd = this.owner;
                wnd.wrapper.children(KWINDOWRESIZEHANDLES).toggle(!wnd.options.isMinimized).end().find(KOVERLAY).remove();
                $(BODY).css(CURSOR, '');
            },
            dragcancel: function (e) {
                if (this._preventDragging) {
                    return;
                }
                this._finishDrag();
                e.currentTarget.closest(KWINDOW).css(this.owner.initialWindowPosition);
            },
            dragend: function () {
                var wnd = this.owner;
                if (this._preventDragging || wnd.isMaximized()) {
                    return;
                }
                $(wnd.wrapper).css(wnd.options.position).css('transform', '');
                this._finishDrag();
                wnd.trigger(DRAGEND);
                return false;
            },
            destroy: function () {
                if (this._draggable) {
                    this._draggable.destroy();
                }
                this._draggable = this.owner = null;
            }
        };
        kendo.ui.plugin(Window);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pane', ['kendo.view'], f);
}(function () {
    var __meta__ = {
        id: 'pane',
        name: 'Pane',
        category: 'web',
        description: 'Pane',
        depends: ['view'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, roleSelector = kendo.roleSelector, ui = kendo.ui, Widget = ui.Widget, ViewEngine = kendo.ViewEngine, View = kendo.View, extend = $.extend, NAVIGATE = 'navigate', VIEW_SHOW = 'viewShow', SAME_VIEW_REQUESTED = 'sameViewRequested', OS = kendo.support.mobileOS, SKIP_TRANSITION_ON_BACK_BUTTON = OS.ios && !OS.appMode && OS.flatVersion >= 700, BACK = '#:back';
        var DOT = '.';
        var classNames = {
            pane: 'k-pane',
            paneWrapper: 'k-pane-wrapper',
            collapsiblePane: 'k-collapsible-pane',
            vertical: 'k-vertical'
        };
        var Pane = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element;
                element.addClass(classNames.pane);
                if (that.options.collapsible) {
                    element.addClass(classNames.collapsiblePane);
                }
                this.history = [];
                this.historyCallback = function (url, params, backButtonPressed) {
                    var transition = that.transition;
                    that.transition = null;
                    if (SKIP_TRANSITION_ON_BACK_BUTTON && backButtonPressed) {
                        transition = 'none';
                    }
                    return that.viewEngine.showView(url, transition, params);
                };
                this._historyNavigate = function (url) {
                    if (url === BACK) {
                        if (that.history.length === 1) {
                            return;
                        }
                        that.history.pop();
                        url = that.history[that.history.length - 1];
                    } else {
                        if (url instanceof View) {
                            url = '';
                        }
                        that.history.push(url);
                    }
                    that.historyCallback(url, kendo.parseQueryStringParams(url));
                };
                this._historyReplace = function (url) {
                    var params = kendo.parseQueryStringParams(url);
                    that.history[that.history.length - 1] = url;
                    that.historyCallback(url, params);
                };
                that.viewEngine = new ViewEngine(extend({}, {
                    container: element,
                    transition: options.transition,
                    modelScope: options.modelScope,
                    rootNeeded: !options.initial,
                    serverNavigation: options.serverNavigation,
                    remoteViewURLPrefix: options.root || '',
                    layout: options.layout,
                    $angular: options.$angular,
                    showStart: function () {
                        that.closeActiveDialogs();
                    },
                    after: function () {
                    },
                    viewShow: function (e) {
                        that.trigger(VIEW_SHOW, e);
                    },
                    loadStart: function () {
                    },
                    loadComplete: function () {
                    },
                    sameViewRequested: function () {
                        that.trigger(SAME_VIEW_REQUESTED);
                    },
                    viewTypeDetermined: function (e) {
                        if (!e.remote || !that.options.serverNavigation) {
                            that.trigger(NAVIGATE, { url: e.url });
                        }
                    }
                }, this.options.viewEngine));
                this._setPortraitWidth();
                kendo.onResize(function () {
                    that._setPortraitWidth();
                });
            },
            closeActiveDialogs: function () {
                var dialogs = this.element.find(roleSelector('actionsheet popover modalview')).filter(':visible');
                dialogs.each(function () {
                    kendo.widgetInstance($(this), ui).close();
                });
            },
            navigateToInitial: function () {
                var initial = this.options.initial;
                if (initial) {
                    this.navigate(initial);
                }
                return initial;
            },
            options: {
                name: 'Pane',
                portraitWidth: '',
                transition: '',
                layout: '',
                collapsible: false,
                initial: null,
                modelScope: window
            },
            events: [
                NAVIGATE,
                VIEW_SHOW,
                SAME_VIEW_REQUESTED
            ],
            append: function (html) {
                return this.viewEngine.append(html);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                if (that.viewEngine) {
                    that.viewEngine.destroy();
                }
            },
            navigate: function (url, transition) {
                if (url instanceof View) {
                    url = url.id;
                }
                this.transition = transition;
                this._historyNavigate(url);
            },
            replace: function (url, transition) {
                if (url instanceof View) {
                    url = url.id;
                }
                this.transition = transition;
                this._historyReplace(url);
            },
            view: function () {
                return this.viewEngine.view();
            },
            _setPortraitWidth: function () {
                var width, portraitWidth = this.options.portraitWidth;
                if (portraitWidth) {
                    width = kendo.mobile.application.element.is(DOT + classNames.vertical) ? portraitWidth : 'auto';
                    this.element.css('width', width);
                }
            }
        });
        Pane.wrap = function (element, options) {
            if (!element.is(roleSelector('view'))) {
                element = element.wrap('<div data-' + kendo.ns + 'role="view" data-stretch="true"></div>').parent();
            }
            var paneContainer = element.wrap('<div class="' + classNames.paneWrapper + ' k-widget"><div></div></div>').parent();
            var pane = new Pane(paneContainer, options);
            pane.navigate('');
            return pane;
        };
        kendo.Pane = Pane;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.progressbar', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'progressbar',
        name: 'ProgressBar',
        category: 'web',
        description: 'The ProgressBar offers rich functionality for displaying and tracking progress',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, HORIZONTAL = 'horizontal', VERTICAL = 'vertical', DEFAULTMIN = 0, DEFAULTMAX = 100, DEFAULTVALUE = 0, DEFAULTCHUNKCOUNT = 5, KPROGRESSBAR = 'k-progressbar', KPROGRESSBARREVERSE = 'k-progressbar-reverse', KPROGRESSBARINDETERMINATE = 'k-progressbar-indeterminate', KPROGRESSBARCOMPLETE = 'k-complete', KPROGRESSWRAPPER = 'k-state-selected', KPROGRESSSTATUS = 'k-progress-status', KCOMPLETEDCHUNK = 'k-state-selected', KUPCOMINGCHUNK = 'k-state-default', KSTATEDISABLED = 'k-state-disabled', PROGRESSTYPE = {
                VALUE: 'value',
                PERCENT: 'percent',
                CHUNK: 'chunk'
            }, CHANGE = 'change', COMPLETE = 'complete', BOOLEAN = 'boolean', math = Math, extend = $.extend, proxy = $.proxy, HUNDREDPERCENT = 100, DEFAULTANIMATIONDURATION = 400, PRECISION = 3, templates = { progressStatus: '<span class=\'k-progress-status-wrap\'><span class=\'k-progress-status\'></span></span>' };
        var ProgressBar = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(this, element, options);
                options = that.options;
                that._progressProperty = options.orientation === HORIZONTAL ? 'width' : 'height';
                that._fields();
                options.value = that._validateValue(options.value);
                that._validateType(options.type);
                that._wrapper();
                that._progressAnimation();
                if (options.value !== options.min && options.value !== false) {
                    that._updateProgress();
                }
            },
            setOptions: function (options) {
                var that = this;
                Widget.fn.setOptions.call(that, options);
                if (options.hasOwnProperty('reverse')) {
                    that.wrapper.toggleClass('k-progressbar-reverse', options.reverse);
                }
                if (options.hasOwnProperty('enable')) {
                    that.enable(options.enable);
                }
                that._progressAnimation();
                that._validateValue();
                that._updateProgress();
            },
            events: [
                CHANGE,
                COMPLETE
            ],
            options: {
                name: 'ProgressBar',
                orientation: HORIZONTAL,
                reverse: false,
                min: DEFAULTMIN,
                max: DEFAULTMAX,
                value: DEFAULTVALUE,
                enable: true,
                type: PROGRESSTYPE.VALUE,
                chunkCount: DEFAULTCHUNKCOUNT,
                showStatus: true,
                animation: {}
            },
            _fields: function () {
                var that = this;
                that._isStarted = false;
                that.progressWrapper = that.progressStatus = $();
            },
            _validateType: function (currentType) {
                var isValid = false;
                $.each(PROGRESSTYPE, function (k, type) {
                    if (type === currentType) {
                        isValid = true;
                        return false;
                    }
                });
                if (!isValid) {
                    throw new Error(kendo.format('Invalid ProgressBar type \'{0}\'', currentType));
                }
            },
            _wrapper: function () {
                var that = this;
                var container = that.wrapper = that.element;
                var options = that.options;
                var orientation = options.orientation;
                var initialStatusValue;
                container.addClass('k-widget ' + KPROGRESSBAR);
                container.addClass(KPROGRESSBAR + '-' + (orientation === HORIZONTAL ? HORIZONTAL : VERTICAL));
                if (options.enable === false) {
                    container.addClass(KSTATEDISABLED);
                }
                if (options.reverse) {
                    container.addClass(KPROGRESSBARREVERSE);
                }
                if (options.value === false) {
                    container.addClass(KPROGRESSBARINDETERMINATE);
                }
                if (options.type === PROGRESSTYPE.CHUNK) {
                    that._addChunkProgressWrapper();
                } else {
                    if (options.showStatus) {
                        that.progressStatus = that.wrapper.prepend(templates.progressStatus).find('.' + KPROGRESSSTATUS);
                        initialStatusValue = options.value !== false ? options.value : options.min;
                        if (options.type === PROGRESSTYPE.VALUE) {
                            that.progressStatus.text(initialStatusValue);
                        } else {
                            that.progressStatus.text(that._calculatePercentage(initialStatusValue).toFixed() + '%');
                        }
                    }
                }
            },
            value: function (value) {
                return this._value(value);
            },
            _value: function (value) {
                var that = this;
                var options = that.options;
                var validated;
                if (value === undefined) {
                    return options.value;
                } else {
                    if (typeof value !== BOOLEAN) {
                        value = that._roundValue(value);
                        if (!isNaN(value)) {
                            validated = that._validateValue(value);
                            if (validated !== options.value) {
                                that.wrapper.removeClass(KPROGRESSBARINDETERMINATE);
                                options.value = validated;
                                that._isStarted = true;
                                that._updateProgress();
                            }
                        }
                    } else if (!value) {
                        that.wrapper.addClass(KPROGRESSBARINDETERMINATE);
                        options.value = false;
                    }
                }
            },
            _roundValue: function (value) {
                value = parseFloat(value);
                var power = math.pow(10, PRECISION);
                return math.floor(value * power) / power;
            },
            _validateValue: function (value) {
                var that = this;
                var options = that.options;
                if (value !== false) {
                    if (value <= options.min || value === true) {
                        return options.min;
                    } else if (value >= options.max) {
                        return options.max;
                    }
                } else if (value === false) {
                    return false;
                }
                if (isNaN(that._roundValue(value))) {
                    return options.min;
                }
                return value;
            },
            _updateProgress: function () {
                var that = this;
                var options = that.options;
                var percentage = that._calculatePercentage();
                if (options.type === PROGRESSTYPE.CHUNK) {
                    that._updateChunks(percentage);
                    that._onProgressUpdateAlways(options.value);
                } else {
                    that._updateProgressWrapper(percentage);
                }
            },
            _updateChunks: function (percentage) {
                var that = this;
                var options = that.options;
                var chunkCount = options.chunkCount;
                var percentagesPerChunk = parseInt(HUNDREDPERCENT / chunkCount * 100, 10) / 100;
                var percentageParsed = parseInt(percentage * 100, 10) / 100;
                var completedChunksCount = math.floor(percentageParsed / percentagesPerChunk);
                var completedChunks;
                if (options.orientation === HORIZONTAL && !options.reverse || options.orientation === VERTICAL && options.reverse) {
                    completedChunks = that.wrapper.find('li.k-item:lt(' + completedChunksCount + ')');
                } else {
                    completedChunks = that.wrapper.find('li.k-item:gt(-' + (completedChunksCount + 1) + ')');
                }
                that.wrapper.find('.' + KCOMPLETEDCHUNK).removeClass(KCOMPLETEDCHUNK).addClass(KUPCOMINGCHUNK);
                completedChunks.removeClass(KUPCOMINGCHUNK).addClass(KCOMPLETEDCHUNK);
            },
            _updateProgressWrapper: function (percentage) {
                var that = this;
                var options = that.options;
                var progressWrapper = that.wrapper.find('.' + KPROGRESSWRAPPER);
                var animationDuration = that._isStarted ? that._animation.duration : 0;
                var animationCssOptions = {};
                if (progressWrapper.length === 0) {
                    that._addRegularProgressWrapper();
                }
                animationCssOptions[that._progressProperty] = percentage + '%';
                that.progressWrapper.animate(animationCssOptions, {
                    duration: animationDuration,
                    start: proxy(that._onProgressAnimateStart, that),
                    progress: proxy(that._onProgressAnimate, that),
                    complete: proxy(that._onProgressAnimateComplete, that, options.value),
                    always: proxy(that._onProgressUpdateAlways, that, options.value)
                });
            },
            _onProgressAnimateStart: function () {
                this.progressWrapper.show();
            },
            _onProgressAnimate: function (e) {
                var that = this;
                var options = that.options;
                var progressInPercent = parseFloat(e.elem.style[that._progressProperty], 10);
                var progressStatusWrapSize;
                if (options.showStatus) {
                    progressStatusWrapSize = 10000 / parseFloat(that.progressWrapper[0].style[that._progressProperty]);
                    that.progressWrapper.find('.k-progress-status-wrap').css(that._progressProperty, progressStatusWrapSize + '%');
                }
                if (options.type !== PROGRESSTYPE.CHUNK && progressInPercent <= 98) {
                    that.progressWrapper.removeClass(KPROGRESSBARCOMPLETE);
                }
            },
            _onProgressAnimateComplete: function (currentValue) {
                var that = this;
                var options = that.options;
                var progressWrapperSize = parseFloat(that.progressWrapper[0].style[that._progressProperty]);
                var progressValue;
                if (options.type !== PROGRESSTYPE.CHUNK && progressWrapperSize > 98) {
                    that.progressWrapper.addClass(KPROGRESSBARCOMPLETE);
                }
                if (options.showStatus) {
                    if (options.type === PROGRESSTYPE.VALUE) {
                        progressValue = currentValue;
                    } else if (options.type == PROGRESSTYPE.PERCENT) {
                        progressValue = that._calculatePercentage(currentValue).toFixed() + '%';
                    } else {
                        progressValue = math.floor(that._calculatePercentage(currentValue)) + '%';
                    }
                    that.progressStatus.text(progressValue);
                }
                if (currentValue === options.min) {
                    that.progressWrapper.hide();
                }
            },
            _onProgressUpdateAlways: function (currentValue) {
                var that = this;
                var options = that.options;
                if (that._isStarted) {
                    that.trigger(CHANGE, { value: currentValue });
                }
                if (currentValue === options.max && that._isStarted) {
                    that.trigger(COMPLETE, { value: options.max });
                }
            },
            enable: function (enable) {
                var that = this;
                var options = that.options;
                options.enable = typeof enable === 'undefined' ? true : enable;
                that.wrapper.toggleClass(KSTATEDISABLED, !options.enable);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
            },
            _addChunkProgressWrapper: function () {
                var that = this;
                var options = that.options;
                var container = that.wrapper;
                var chunkSize = HUNDREDPERCENT / options.chunkCount;
                var html = '';
                if (options.chunkCount <= 1) {
                    options.chunkCount = 1;
                }
                html += '<ul class=\'k-reset\'>';
                for (var i = options.chunkCount - 1; i >= 0; i--) {
                    html += '<li class=\'k-item k-state-default\'></li>';
                }
                html += '</ul>';
                container.append(html).find('.k-item').css(that._progressProperty, chunkSize + '%').first().addClass('k-first').end().last().addClass('k-last');
                that._normalizeChunkSize();
            },
            _normalizeChunkSize: function () {
                var that = this;
                var options = that.options;
                var lastChunk = that.wrapper.find('.k-item:last');
                var currentSize = parseFloat(lastChunk[0].style[that._progressProperty]);
                var difference = HUNDREDPERCENT - options.chunkCount * currentSize;
                if (difference > 0) {
                    lastChunk.css(that._progressProperty, currentSize + difference + '%');
                }
            },
            _addRegularProgressWrapper: function () {
                var that = this;
                that.progressWrapper = $('<div class=\'' + KPROGRESSWRAPPER + '\'></div>').appendTo(that.wrapper);
                if (that.options.showStatus) {
                    that.progressWrapper.append(templates.progressStatus);
                    that.progressStatus = that.wrapper.find('.' + KPROGRESSSTATUS);
                }
            },
            _calculateChunkSize: function () {
                var that = this;
                var chunkCount = that.options.chunkCount;
                var chunkContainer = that.wrapper.find('ul.k-reset');
                return (parseInt(chunkContainer.css(that._progressProperty), 10) - (chunkCount - 1)) / chunkCount;
            },
            _calculatePercentage: function (currentValue) {
                var that = this;
                var options = that.options;
                var value = currentValue !== undefined ? currentValue : options.value;
                var min = options.min;
                var max = options.max;
                that._onePercent = math.abs((max - min) / 100);
                return math.abs((value - min) / that._onePercent);
            },
            _progressAnimation: function () {
                var that = this;
                var options = that.options;
                var animation = options.animation;
                if (animation === false) {
                    that._animation = { duration: 0 };
                } else {
                    that._animation = extend({ duration: DEFAULTANIMATIONDURATION }, options.animation);
                }
            }
        });
        kendo.ui.plugin(ProgressBar);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf/pako', ['kendo.core'], f);
}(function () {
    (function () {
        kendo.pdf = kendo.pdf || {};
        kendo.pdf.supportsDeflate = function () {
            return window.pako && typeof window.pako.deflate == 'function';
        };
        kendo.pdf.deflate = function (data) {
            return window.pako.deflate(data);
        };
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf/core', [
        'pdf/pako',
        'kendo.core',
        'kendo.color',
        'kendo.drawing'
    ], f);
}(function () {
    (function (kendo) {
        window.kendo.pdf = window.kendo.pdf || {};
        var support = kendo.support;
        var supportBrowser = support.browser;
        var kendoPdf = kendo.pdf;
        var drawing = kendo.drawing;
        var util = drawing.util;
        var kendoGeometry = kendo.geometry;
        var HAS_TYPED_ARRAYS = typeof Uint8Array !== 'undefined' && kendo.support.browser && (!kendo.support.browser.msie || kendo.support.browser.version > 9);
        var BASE64 = function () {
            var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
            return {
                decode: function (str) {
                    var input = str.replace(/[^A-Za-z0-9\+\/\=]/g, ''), i = 0, n = input.length, output = [];
                    while (i < n) {
                        var enc1 = keyStr.indexOf(input.charAt(i++));
                        var enc2 = keyStr.indexOf(input.charAt(i++));
                        var enc3 = keyStr.indexOf(input.charAt(i++));
                        var enc4 = keyStr.indexOf(input.charAt(i++));
                        var chr1 = enc1 << 2 | enc2 >>> 4;
                        var chr2 = (enc2 & 15) << 4 | enc3 >>> 2;
                        var chr3 = (enc3 & 3) << 6 | enc4;
                        output.push(chr1);
                        if (enc3 != 64) {
                            output.push(chr2);
                        }
                        if (enc4 != 64) {
                            output.push(chr3);
                        }
                    }
                    return output;
                },
                encode: function (bytes) {
                    var i = 0, n = bytes.length;
                    var output = '';
                    while (i < n) {
                        var chr1 = bytes[i++];
                        var chr2 = bytes[i++];
                        var chr3 = bytes[i++];
                        var enc1 = chr1 >>> 2;
                        var enc2 = (chr1 & 3) << 4 | chr2 >>> 4;
                        var enc3 = (chr2 & 15) << 2 | chr3 >>> 6;
                        var enc4 = chr3 & 63;
                        if (i - n == 2) {
                            enc3 = enc4 = 64;
                        } else if (i - n == 1) {
                            enc4 = 64;
                        }
                        output += keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
                    }
                    return output;
                }
            };
        }();
        function BinaryStream(data) {
            var offset = 0, length = 0;
            if (data == null) {
                data = HAS_TYPED_ARRAYS ? new Uint8Array(256) : [];
            } else {
                length = data.length;
            }
            var ensure = HAS_TYPED_ARRAYS ? function (len) {
                if (len >= data.length) {
                    var tmp = new Uint8Array(Math.max(len + 256, data.length * 2));
                    tmp.set(data, 0);
                    data = tmp;
                }
            } : function () {
            };
            var get = HAS_TYPED_ARRAYS ? function () {
                return new Uint8Array(data.buffer, 0, length);
            } : function () {
                return data;
            };
            var write = HAS_TYPED_ARRAYS ? function (bytes) {
                if (typeof bytes == 'string') {
                    return writeString(bytes);
                }
                var len = bytes.length;
                ensure(offset + len);
                data.set(bytes, offset);
                offset += len;
                if (offset > length) {
                    length = offset;
                }
            } : function (bytes) {
                if (typeof bytes == 'string') {
                    return writeString(bytes);
                }
                for (var i = 0; i < bytes.length; ++i) {
                    writeByte(bytes[i]);
                }
            };
            var slice = HAS_TYPED_ARRAYS ? function (start, length) {
                if (data.buffer.slice) {
                    return new Uint8Array(data.buffer.slice(start, start + length));
                } else {
                    var x = new Uint8Array(length);
                    x.set(new Uint8Array(data.buffer, start, length));
                    return x;
                }
            } : function (start, length) {
                return data.slice(start, start + length);
            };
            function eof() {
                return offset >= length;
            }
            function readByte() {
                return offset < length ? data[offset++] : 0;
            }
            function writeByte(b) {
                ensure(offset);
                data[offset++] = b & 255;
                if (offset > length) {
                    length = offset;
                }
            }
            function readShort() {
                return readByte() << 8 | readByte();
            }
            function writeShort(w) {
                writeByte(w >> 8);
                writeByte(w);
            }
            function readShort_() {
                var w = readShort();
                return w >= 32768 ? w - 65536 : w;
            }
            function writeShort_(w) {
                writeShort(w < 0 ? w + 65536 : w);
            }
            function readLong() {
                return readShort() * 65536 + readShort();
            }
            function writeLong(w) {
                writeShort(w >>> 16 & 65535);
                writeShort(w & 65535);
            }
            function readLong_() {
                var w = readLong();
                return w >= 2147483648 ? w - 4294967296 : w;
            }
            function writeLong_(w) {
                writeLong(w < 0 ? w + 4294967296 : w);
            }
            function readFixed() {
                return readLong() / 65536;
            }
            function writeFixed(f) {
                writeLong(Math.round(f * 65536));
            }
            function readFixed_() {
                return readLong_() / 65536;
            }
            function writeFixed_(f) {
                writeLong_(Math.round(f * 65536));
            }
            function read(len) {
                return times(len, readByte);
            }
            function readString(len) {
                return String.fromCharCode.apply(String, read(len));
            }
            function writeString(str) {
                for (var i = 0; i < str.length; ++i) {
                    writeByte(str.charCodeAt(i));
                }
            }
            function times(n, reader) {
                for (var ret = new Array(n), i = 0; i < n; ++i) {
                    ret[i] = reader();
                }
                return ret;
            }
            var stream = {
                eof: eof,
                readByte: readByte,
                writeByte: writeByte,
                readShort: readShort,
                writeShort: writeShort,
                readLong: readLong,
                writeLong: writeLong,
                readFixed: readFixed,
                writeFixed: writeFixed,
                readShort_: readShort_,
                writeShort_: writeShort_,
                readLong_: readLong_,
                writeLong_: writeLong_,
                readFixed_: readFixed_,
                writeFixed_: writeFixed_,
                read: read,
                write: write,
                readString: readString,
                writeString: writeString,
                times: times,
                get: get,
                slice: slice,
                offset: function (pos) {
                    if (pos != null) {
                        offset = pos;
                        return stream;
                    }
                    return offset;
                },
                skip: function (nbytes) {
                    offset += nbytes;
                },
                toString: function () {
                    throw new Error('FIX CALLER.  BinaryStream is no longer convertible to string!');
                },
                length: function () {
                    return length;
                },
                saveExcursion: function (f) {
                    var pos = offset;
                    try {
                        return f();
                    } finally {
                        offset = pos;
                    }
                },
                writeBase64: function (base64) {
                    if (window.atob) {
                        writeString(window.atob(base64));
                    } else {
                        write(BASE64.decode(base64));
                    }
                },
                base64: function () {
                    return BASE64.encode(get());
                }
            };
            return stream;
        }
        function ucs2decode(string) {
            var output = [], counter = 0, length = string.length, value, extra;
            while (counter < length) {
                value = string.charCodeAt(counter++);
                if (value >= 55296 && value <= 56319 && counter < length) {
                    extra = string.charCodeAt(counter++);
                    if ((extra & 64512) == 56320) {
                        output.push(((value & 1023) << 10) + (extra & 1023) + 65536);
                    } else {
                        output.push(value);
                        counter--;
                    }
                } else {
                    output.push(value);
                }
            }
            return output;
        }
        function ucs2encode(array) {
            return array.map(function (value) {
                var output = '';
                if (value > 65535) {
                    value -= 65536;
                    output += String.fromCharCode(value >>> 10 & 1023 | 55296);
                    value = 56320 | value & 1023;
                }
                output += String.fromCharCode(value);
                return output;
            }).join('');
        }
        function atobUint8Array(base64) {
            var data = window.atob(base64);
            var result = new Uint8Array(data.length);
            for (var idx = 0; idx < data.length; idx++) {
                result[idx] = data.charCodeAt(idx);
            }
            return result;
        }
        function createUint8Array(data) {
            var result = new Uint8Array(data.length);
            for (var idx = 0; idx < data.length; idx++) {
                result[idx] = data[idx];
            }
            return result;
        }
        function base64ToUint8Array(base64) {
            if (window.atob) {
                return atobUint8Array(base64);
            }
            return createUint8Array(BASE64.decode(base64));
        }
        function hasOwnProperty$1(obj, key) {
            return Object.prototype.hasOwnProperty.call(obj, key);
        }
        function sortedKeys(obj) {
            return Object.keys(obj).sort(function (a, b) {
                return a - b;
            }).map(parseFloat);
        }
        function Directory(data) {
            this.raw = data;
            this.scalerType = data.readLong();
            this.tableCount = data.readShort();
            this.searchRange = data.readShort();
            this.entrySelector = data.readShort();
            this.rangeShift = data.readShort();
            var tables = this.tables = {};
            for (var i = 0; i < this.tableCount; ++i) {
                var entry = {
                    tag: data.readString(4),
                    checksum: data.readLong(),
                    offset: data.readLong(),
                    length: data.readLong()
                };
                tables[entry.tag] = entry;
            }
        }
        Directory.prototype = {
            readTable: function (name, Ctor) {
                var def = this.tables[name];
                if (!def) {
                    throw new Error('Table ' + name + ' not found in directory');
                }
                return this[name] = def.table = new Ctor(this, def);
            },
            render: function (tables) {
                var this$1 = this;
                var tableCount = Object.keys(tables).length;
                var maxpow2 = Math.pow(2, Math.floor(Math.log(tableCount) / Math.LN2));
                var searchRange = maxpow2 * 16;
                var entrySelector = Math.floor(Math.log(maxpow2) / Math.LN2);
                var rangeShift = tableCount * 16 - searchRange;
                var out = BinaryStream();
                out.writeLong(this.scalerType);
                out.writeShort(tableCount);
                out.writeShort(searchRange);
                out.writeShort(entrySelector);
                out.writeShort(rangeShift);
                var directoryLength = tableCount * 16;
                var offset = out.offset() + directoryLength;
                var headOffset = null;
                var tableData = BinaryStream();
                for (var tag in tables) {
                    if (hasOwnProperty$1(tables, tag)) {
                        var table = tables[tag];
                        out.writeString(tag);
                        out.writeLong(this$1.checksum(table));
                        out.writeLong(offset);
                        out.writeLong(table.length);
                        tableData.write(table);
                        if (tag == 'head') {
                            headOffset = offset;
                        }
                        offset += table.length;
                        while (offset % 4) {
                            tableData.writeByte(0);
                            offset++;
                        }
                    }
                }
                out.write(tableData.get());
                var sum = this.checksum(out.get());
                var adjustment = 2981146554 - sum;
                out.offset(headOffset + 8);
                out.writeLong(adjustment);
                return out.get();
            },
            checksum: function (data) {
                data = BinaryStream(data);
                var sum = 0;
                while (!data.eof()) {
                    sum += data.readLong();
                }
                return sum & 4294967295;
            }
        };
        function deftable(methods) {
            function Ctor(file, def) {
                this.definition = def;
                this.length = def.length;
                this.offset = def.offset;
                this.file = file;
                this.rawData = file.raw;
                this.parse(file.raw);
            }
            Ctor.prototype.raw = function () {
                return this.rawData.slice(this.offset, this.length);
            };
            for (var i in methods) {
                if (hasOwnProperty$1(methods, i)) {
                    Ctor[i] = Ctor.prototype[i] = methods[i];
                }
            }
            return Ctor;
        }
        var HeadTable = deftable({
            parse: function (data) {
                data.offset(this.offset);
                this.version = data.readLong();
                this.revision = data.readLong();
                this.checkSumAdjustment = data.readLong();
                this.magicNumber = data.readLong();
                this.flags = data.readShort();
                this.unitsPerEm = data.readShort();
                this.created = data.read(8);
                this.modified = data.read(8);
                this.xMin = data.readShort_();
                this.yMin = data.readShort_();
                this.xMax = data.readShort_();
                this.yMax = data.readShort_();
                this.macStyle = data.readShort();
                this.lowestRecPPEM = data.readShort();
                this.fontDirectionHint = data.readShort_();
                this.indexToLocFormat = data.readShort_();
                this.glyphDataFormat = data.readShort_();
            },
            render: function (indexToLocFormat) {
                var out = BinaryStream();
                out.writeLong(this.version);
                out.writeLong(this.revision);
                out.writeLong(0);
                out.writeLong(this.magicNumber);
                out.writeShort(this.flags);
                out.writeShort(this.unitsPerEm);
                out.write(this.created);
                out.write(this.modified);
                out.writeShort_(this.xMin);
                out.writeShort_(this.yMin);
                out.writeShort_(this.xMax);
                out.writeShort_(this.yMax);
                out.writeShort(this.macStyle);
                out.writeShort(this.lowestRecPPEM);
                out.writeShort_(this.fontDirectionHint);
                out.writeShort_(indexToLocFormat);
                out.writeShort_(this.glyphDataFormat);
                return out.get();
            }
        });
        var LocaTable = deftable({
            parse: function (data) {
                data.offset(this.offset);
                var format = this.file.head.indexToLocFormat;
                if (format === 0) {
                    this.offsets = data.times(this.length / 2, function () {
                        return 2 * data.readShort();
                    });
                } else {
                    this.offsets = data.times(this.length / 4, data.readLong);
                }
            },
            offsetOf: function (id) {
                return this.offsets[id];
            },
            lengthOf: function (id) {
                return this.offsets[id + 1] - this.offsets[id];
            },
            render: function (offsets) {
                var out = BinaryStream();
                var needsLongFormat = offsets[offsets.length - 1] > 65535;
                for (var i = 0; i < offsets.length; ++i) {
                    if (needsLongFormat) {
                        out.writeLong(offsets[i]);
                    } else {
                        out.writeShort(offsets[i] / 2);
                    }
                }
                return {
                    format: needsLongFormat ? 1 : 0,
                    table: out.get()
                };
            }
        });
        var HheaTable = deftable({
            parse: function (data) {
                data.offset(this.offset);
                this.version = data.readLong();
                this.ascent = data.readShort_();
                this.descent = data.readShort_();
                this.lineGap = data.readShort_();
                this.advanceWidthMax = data.readShort();
                this.minLeftSideBearing = data.readShort_();
                this.minRightSideBearing = data.readShort_();
                this.xMaxExtent = data.readShort_();
                this.caretSlopeRise = data.readShort_();
                this.caretSlopeRun = data.readShort_();
                this.caretOffset = data.readShort_();
                data.skip(4 * 2);
                this.metricDataFormat = data.readShort_();
                this.numOfLongHorMetrics = data.readShort();
            },
            render: function (ids) {
                var out = BinaryStream();
                out.writeLong(this.version);
                out.writeShort_(this.ascent);
                out.writeShort_(this.descent);
                out.writeShort_(this.lineGap);
                out.writeShort(this.advanceWidthMax);
                out.writeShort_(this.minLeftSideBearing);
                out.writeShort_(this.minRightSideBearing);
                out.writeShort_(this.xMaxExtent);
                out.writeShort_(this.caretSlopeRise);
                out.writeShort_(this.caretSlopeRun);
                out.writeShort_(this.caretOffset);
                out.write([
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0
                ]);
                out.writeShort_(this.metricDataFormat);
                out.writeShort(ids.length);
                return out.get();
            }
        });
        var MaxpTable = deftable({
            parse: function (data) {
                data.offset(this.offset);
                this.version = data.readLong();
                this.numGlyphs = data.readShort();
                this.maxPoints = data.readShort();
                this.maxContours = data.readShort();
                this.maxComponentPoints = data.readShort();
                this.maxComponentContours = data.readShort();
                this.maxZones = data.readShort();
                this.maxTwilightPoints = data.readShort();
                this.maxStorage = data.readShort();
                this.maxFunctionDefs = data.readShort();
                this.maxInstructionDefs = data.readShort();
                this.maxStackElements = data.readShort();
                this.maxSizeOfInstructions = data.readShort();
                this.maxComponentElements = data.readShort();
                this.maxComponentDepth = data.readShort();
            },
            render: function (glyphIds) {
                var out = BinaryStream();
                out.writeLong(this.version);
                out.writeShort(glyphIds.length);
                out.writeShort(this.maxPoints);
                out.writeShort(this.maxContours);
                out.writeShort(this.maxComponentPoints);
                out.writeShort(this.maxComponentContours);
                out.writeShort(this.maxZones);
                out.writeShort(this.maxTwilightPoints);
                out.writeShort(this.maxStorage);
                out.writeShort(this.maxFunctionDefs);
                out.writeShort(this.maxInstructionDefs);
                out.writeShort(this.maxStackElements);
                out.writeShort(this.maxSizeOfInstructions);
                out.writeShort(this.maxComponentElements);
                out.writeShort(this.maxComponentDepth);
                return out.get();
            }
        });
        var HmtxTable = deftable({
            parse: function (data) {
                data.offset(this.offset);
                var dir = this.file, hhea = dir.hhea;
                this.metrics = data.times(hhea.numOfLongHorMetrics, function () {
                    return {
                        advance: data.readShort(),
                        lsb: data.readShort_()
                    };
                });
                var lsbCount = dir.maxp.numGlyphs - dir.hhea.numOfLongHorMetrics;
                this.leftSideBearings = data.times(lsbCount, data.readShort_);
            },
            forGlyph: function (id) {
                var metrics = this.metrics;
                var n = metrics.length;
                if (id < n) {
                    return metrics[id];
                }
                return {
                    advance: metrics[n - 1].advance,
                    lsb: this.leftSideBearings[id - n]
                };
            },
            render: function (glyphIds) {
                var this$1 = this;
                var out = BinaryStream();
                for (var i = 0; i < glyphIds.length; ++i) {
                    var m = this$1.forGlyph(glyphIds[i]);
                    out.writeShort(m.advance);
                    out.writeShort_(m.lsb);
                }
                return out.get();
            }
        });
        var GlyfTable = function () {
            function SimpleGlyph(raw) {
                this.raw = raw;
            }
            SimpleGlyph.prototype = {
                compound: false,
                render: function () {
                    return this.raw.get();
                }
            };
            var ARG_1_AND_2_ARE_WORDS = 1;
            var WE_HAVE_A_SCALE = 8;
            var MORE_COMPONENTS = 32;
            var WE_HAVE_AN_X_AND_Y_SCALE = 64;
            var WE_HAVE_A_TWO_BY_TWO = 128;
            function CompoundGlyph(data) {
                this.raw = data;
                var ids = this.glyphIds = [];
                var offsets = this.idOffsets = [];
                while (true) {
                    var flags = data.readShort();
                    offsets.push(data.offset());
                    ids.push(data.readShort());
                    if (!(flags & MORE_COMPONENTS)) {
                        break;
                    }
                    data.skip(flags & ARG_1_AND_2_ARE_WORDS ? 4 : 2);
                    if (flags & WE_HAVE_A_TWO_BY_TWO) {
                        data.skip(8);
                    } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
                        data.skip(4);
                    } else if (flags & WE_HAVE_A_SCALE) {
                        data.skip(2);
                    }
                }
            }
            CompoundGlyph.prototype = {
                compound: true,
                render: function (old2new) {
                    var this$1 = this;
                    var out = BinaryStream(this.raw.get());
                    for (var i = 0; i < this.glyphIds.length; ++i) {
                        var id = this$1.glyphIds[i];
                        out.offset(this$1.idOffsets[i]);
                        out.writeShort(old2new[id]);
                    }
                    return out.get();
                }
            };
            return deftable({
                parse: function () {
                    this.cache = {};
                },
                glyphFor: function (id) {
                    var cache = this.cache;
                    if (hasOwnProperty$1(cache, id)) {
                        return cache[id];
                    }
                    var loca = this.file.loca;
                    var length = loca.lengthOf(id);
                    if (length === 0) {
                        return cache[id] = null;
                    }
                    var data = this.rawData;
                    var offset = this.offset + loca.offsetOf(id);
                    var raw = BinaryStream(data.slice(offset, length));
                    var numberOfContours = raw.readShort_();
                    var xMin = raw.readShort_();
                    var yMin = raw.readShort_();
                    var xMax = raw.readShort_();
                    var yMax = raw.readShort_();
                    var glyph = cache[id] = numberOfContours == -1 ? new CompoundGlyph(raw) : new SimpleGlyph(raw);
                    glyph.numberOfContours = numberOfContours;
                    glyph.xMin = xMin;
                    glyph.yMin = yMin;
                    glyph.xMax = xMax;
                    glyph.yMax = yMax;
                    return glyph;
                },
                render: function (glyphs, oldIds, old2new) {
                    var out = BinaryStream(), offsets = [];
                    for (var i = 0; i < oldIds.length; ++i) {
                        var id = oldIds[i];
                        var glyph = glyphs[id];
                        offsets.push(out.offset());
                        if (glyph) {
                            out.write(glyph.render(old2new));
                        }
                    }
                    offsets.push(out.offset());
                    return {
                        table: out.get(),
                        offsets: offsets
                    };
                }
            });
        }();
        var NameTable = function () {
            function NameEntry(text, entry) {
                this.text = text;
                this.length = text.length;
                this.platformID = entry.platformID;
                this.platformSpecificID = entry.platformSpecificID;
                this.languageID = entry.languageID;
                this.nameID = entry.nameID;
            }
            return deftable({
                parse: function (data) {
                    data.offset(this.offset);
                    data.readShort();
                    var count = data.readShort();
                    var stringOffset = this.offset + data.readShort();
                    var nameRecords = data.times(count, function () {
                        return {
                            platformID: data.readShort(),
                            platformSpecificID: data.readShort(),
                            languageID: data.readShort(),
                            nameID: data.readShort(),
                            length: data.readShort(),
                            offset: data.readShort() + stringOffset
                        };
                    });
                    var strings = this.strings = {};
                    for (var i = 0; i < nameRecords.length; ++i) {
                        var rec = nameRecords[i];
                        data.offset(rec.offset);
                        var text = data.readString(rec.length);
                        if (!strings[rec.nameID]) {
                            strings[rec.nameID] = [];
                        }
                        strings[rec.nameID].push(new NameEntry(text, rec));
                    }
                    this.postscriptEntry = strings[6][0];
                    this.postscriptName = this.postscriptEntry.text.replace(/[^\x20-\x7F]/g, '');
                },
                render: function (psName) {
                    var this$1 = this;
                    var strings = this.strings;
                    var strCount = 0;
                    for (var i in strings) {
                        if (hasOwnProperty$1(strings, i)) {
                            strCount += strings[i].length;
                        }
                    }
                    var out = BinaryStream();
                    var strTable = BinaryStream();
                    out.writeShort(0);
                    out.writeShort(strCount);
                    out.writeShort(6 + 12 * strCount);
                    for (i in strings) {
                        if (hasOwnProperty$1(strings, i)) {
                            var list = i == 6 ? [new NameEntry(psName, this$1.postscriptEntry)] : strings[i];
                            for (var j = 0; j < list.length; ++j) {
                                var str = list[j];
                                out.writeShort(str.platformID);
                                out.writeShort(str.platformSpecificID);
                                out.writeShort(str.languageID);
                                out.writeShort(str.nameID);
                                out.writeShort(str.length);
                                out.writeShort(strTable.offset());
                                strTable.writeString(str.text);
                            }
                        }
                    }
                    out.write(strTable.get());
                    return out.get();
                }
            });
        }();
        var PostTable = function () {
            var POSTSCRIPT_GLYPHS = '.notdef .null nonmarkingreturn space exclam quotedbl numbersign dollar percent ampersand quotesingle parenleft parenright asterisk plus comma hyphen period slash zero one two three four five six seven eight nine colon semicolon less equal greater question at A B C D E F G H I J K L M N O P Q R S T U V W X Y Z bracketleft backslash bracketright asciicircum underscore grave a b c d e f g h i j k l m n o p q r s t u v w x y z braceleft bar braceright asciitilde Adieresis Aring Ccedilla Eacute Ntilde Odieresis Udieresis aacute agrave acircumflex adieresis atilde aring ccedilla eacute egrave ecircumflex edieresis iacute igrave icircumflex idieresis ntilde oacute ograve ocircumflex odieresis otilde uacute ugrave ucircumflex udieresis dagger degree cent sterling section bullet paragraph germandbls registered copyright trademark acute dieresis notequal AE Oslash infinity plusminus lessequal greaterequal yen mu partialdiff summation product pi integral ordfeminine ordmasculine Omega ae oslash questiondown exclamdown logicalnot radical florin approxequal Delta guillemotleft guillemotright ellipsis nonbreakingspace Agrave Atilde Otilde OE oe endash emdash quotedblleft quotedblright quoteleft quoteright divide lozenge ydieresis Ydieresis fraction currency guilsinglleft guilsinglright fi fl daggerdbl periodcentered quotesinglbase quotedblbase perthousand Acircumflex Ecircumflex Aacute Edieresis Egrave Iacute Icircumflex Idieresis Igrave Oacute Ocircumflex apple Ograve Uacute Ucircumflex Ugrave dotlessi circumflex tilde macron breve dotaccent ring cedilla hungarumlaut ogonek caron Lslash lslash Scaron scaron Zcaron zcaron brokenbar Eth eth Yacute yacute Thorn thorn minus multiply onesuperior twosuperior threesuperior onehalf onequarter threequarters franc Gbreve gbreve Idotaccent Scedilla scedilla Cacute cacute Ccaron ccaron dcroat'.split(/\s+/g);
            return deftable({
                parse: function (data) {
                    var this$1 = this;
                    data.offset(this.offset);
                    this.format = data.readLong();
                    this.italicAngle = data.readFixed_();
                    this.underlinePosition = data.readShort_();
                    this.underlineThickness = data.readShort_();
                    this.isFixedPitch = data.readLong();
                    this.minMemType42 = data.readLong();
                    this.maxMemType42 = data.readLong();
                    this.minMemType1 = data.readLong();
                    this.maxMemType1 = data.readLong();
                    var numberOfGlyphs;
                    switch (this.format) {
                    case 65536:
                    case 196608:
                        break;
                    case 131072:
                        numberOfGlyphs = data.readShort();
                        this.glyphNameIndex = data.times(numberOfGlyphs, data.readShort);
                        this.names = [];
                        var limit = this.offset + this.length;
                        while (data.offset() < limit) {
                            this$1.names.push(data.readString(data.readByte()));
                        }
                        break;
                    case 151552:
                        numberOfGlyphs = data.readShort();
                        this.offsets = data.read(numberOfGlyphs);
                        break;
                    case 262144:
                        this.map = data.times(this.file.maxp.numGlyphs, data.readShort);
                        break;
                    }
                },
                glyphFor: function (code) {
                    switch (this.format) {
                    case 65536:
                        return POSTSCRIPT_GLYPHS[code] || '.notdef';
                    case 131072:
                        var index = this.glyphNameIndex[code];
                        if (index < POSTSCRIPT_GLYPHS.length) {
                            return POSTSCRIPT_GLYPHS[index];
                        }
                        return this.names[index - POSTSCRIPT_GLYPHS.length] || '.notdef';
                    case 151552:
                    case 196608:
                        return '.notdef';
                    case 262144:
                        return this.map[code] || 65535;
                    }
                },
                render: function (mapping) {
                    var this$1 = this;
                    if (this.format == 196608) {
                        return this.raw();
                    }
                    var out = BinaryStream(this.rawData.slice(this.offset, 32));
                    out.writeLong(131072);
                    out.offset(32);
                    var indexes = [];
                    var strings = [];
                    for (var i = 0; i < mapping.length; ++i) {
                        var id = mapping[i];
                        var post = this$1.glyphFor(id);
                        var index = POSTSCRIPT_GLYPHS.indexOf(post);
                        if (index >= 0) {
                            indexes.push(index);
                        } else {
                            indexes.push(POSTSCRIPT_GLYPHS.length + strings.length);
                            strings.push(post);
                        }
                    }
                    out.writeShort(mapping.length);
                    for (i = 0; i < indexes.length; ++i) {
                        out.writeShort(indexes[i]);
                    }
                    for (i = 0; i < strings.length; ++i) {
                        out.writeByte(strings[i].length);
                        out.writeString(strings[i]);
                    }
                    return out.get();
                }
            });
        }();
        var CmapTable = function () {
            function CmapEntry(data, offset, codeMap) {
                var self = this;
                self.platformID = data.readShort();
                self.platformSpecificID = data.readShort();
                self.offset = offset + data.readLong();
                data.saveExcursion(function () {
                    var code;
                    data.offset(self.offset);
                    self.format = data.readShort();
                    switch (self.format) {
                    case 0:
                        self.length = data.readShort();
                        self.language = data.readShort();
                        for (var i = 0; i < 256; ++i) {
                            codeMap[i] = data.readByte();
                        }
                        break;
                    case 4:
                        self.length = data.readShort();
                        self.language = data.readShort();
                        var segCount = data.readShort() / 2;
                        data.skip(6);
                        var endCode = data.times(segCount, data.readShort);
                        data.skip(2);
                        var startCode = data.times(segCount, data.readShort);
                        var idDelta = data.times(segCount, data.readShort_);
                        var idRangeOffset = data.times(segCount, data.readShort);
                        var count = (self.length + self.offset - data.offset()) / 2;
                        var glyphIds = data.times(count, data.readShort);
                        for (i = 0; i < segCount; ++i) {
                            var start = startCode[i], end = endCode[i];
                            for (code = start; code <= end; ++code) {
                                var glyphId;
                                if (idRangeOffset[i] === 0) {
                                    glyphId = code + idDelta[i];
                                } else {
                                    var index = idRangeOffset[i] / 2 - (segCount - i) + (code - start);
                                    glyphId = glyphIds[index] || 0;
                                    if (glyphId !== 0) {
                                        glyphId += idDelta[i];
                                    }
                                }
                                codeMap[code] = glyphId & 65535;
                            }
                        }
                        break;
                    case 6:
                        self.length = data.readShort();
                        self.language = data.readShort();
                        code = data.readShort();
                        var length = data.readShort();
                        while (length-- > 0) {
                            codeMap[code++] = data.readShort();
                        }
                        break;
                    case 12:
                        data.readShort();
                        self.length = data.readLong();
                        self.language = data.readLong();
                        var ngroups = data.readLong();
                        while (ngroups-- > 0) {
                            code = data.readLong();
                            var endCharCode = data.readLong();
                            var glyphCode = data.readLong();
                            while (code <= endCharCode) {
                                codeMap[code++] = glyphCode++;
                            }
                        }
                        break;
                    default:
                        if (window.console) {
                            window.console.error('Unhandled CMAP format: ' + self.format);
                        }
                    }
                });
            }
            function renderCharmap(ncid2ogid, ogid2ngid) {
                var codes = sortedKeys(ncid2ogid);
                var startCodes = [];
                var endCodes = [];
                var last = null;
                var diff = null;
                function new_gid(charcode) {
                    return ogid2ngid[ncid2ogid[charcode]];
                }
                for (var i = 0; i < codes.length; ++i) {
                    var code = codes[i];
                    var gid = new_gid(code);
                    var delta = gid - code;
                    if (last == null || delta !== diff) {
                        if (last) {
                            endCodes.push(last);
                        }
                        startCodes.push(code);
                        diff = delta;
                    }
                    last = code;
                }
                if (last) {
                    endCodes.push(last);
                }
                endCodes.push(65535);
                startCodes.push(65535);
                var segCount = startCodes.length;
                var segCountX2 = segCount * 2;
                var searchRange = 2 * Math.pow(2, Math.floor(Math.log(segCount) / Math.LN2));
                var entrySelector = Math.log(searchRange / 2) / Math.LN2;
                var rangeShift = segCountX2 - searchRange;
                var deltas = [];
                var rangeOffsets = [];
                var glyphIds = [];
                for (i = 0; i < segCount; ++i) {
                    var startCode = startCodes[i];
                    var endCode = endCodes[i];
                    if (startCode == 65535) {
                        deltas.push(0);
                        rangeOffsets.push(0);
                        break;
                    }
                    var startGlyph = new_gid(startCode);
                    if (startCode - startGlyph >= 32768) {
                        deltas.push(0);
                        rangeOffsets.push(2 * (glyphIds.length + segCount - i));
                        for (var j = startCode; j <= endCode; ++j) {
                            glyphIds.push(new_gid(j));
                        }
                    } else {
                        deltas.push(startGlyph - startCode);
                        rangeOffsets.push(0);
                    }
                }
                var out = BinaryStream();
                out.writeShort(3);
                out.writeShort(1);
                out.writeLong(12);
                out.writeShort(4);
                out.writeShort(16 + segCount * 8 + glyphIds.length * 2);
                out.writeShort(0);
                out.writeShort(segCountX2);
                out.writeShort(searchRange);
                out.writeShort(entrySelector);
                out.writeShort(rangeShift);
                endCodes.forEach(out.writeShort);
                out.writeShort(0);
                startCodes.forEach(out.writeShort);
                deltas.forEach(out.writeShort_);
                rangeOffsets.forEach(out.writeShort);
                glyphIds.forEach(out.writeShort);
                return out.get();
            }
            return deftable({
                parse: function (data) {
                    var self = this;
                    var offset = self.offset;
                    data.offset(offset);
                    self.codeMap = {};
                    self.version = data.readShort();
                    var tableCount = data.readShort();
                    self.tables = data.times(tableCount, function () {
                        return new CmapEntry(data, offset, self.codeMap);
                    });
                },
                render: function (ncid2ogid, ogid2ngid) {
                    var out = BinaryStream();
                    out.writeShort(0);
                    out.writeShort(1);
                    out.write(renderCharmap(ncid2ogid, ogid2ngid));
                    return out.get();
                }
            });
        }();
        var OS2Table = deftable({
            parse: function (data) {
                data.offset(this.offset);
                this.version = data.readShort();
                this.averageCharWidth = data.readShort_();
                this.weightClass = data.readShort();
                this.widthClass = data.readShort();
                this.type = data.readShort();
                this.ySubscriptXSize = data.readShort_();
                this.ySubscriptYSize = data.readShort_();
                this.ySubscriptXOffset = data.readShort_();
                this.ySubscriptYOffset = data.readShort_();
                this.ySuperscriptXSize = data.readShort_();
                this.ySuperscriptYSize = data.readShort_();
                this.ySuperscriptXOffset = data.readShort_();
                this.ySuperscriptYOffset = data.readShort_();
                this.yStrikeoutSize = data.readShort_();
                this.yStrikeoutPosition = data.readShort_();
                this.familyClass = data.readShort_();
                this.panose = data.times(10, data.readByte);
                this.charRange = data.times(4, data.readLong);
                this.vendorID = data.readString(4);
                this.selection = data.readShort();
                this.firstCharIndex = data.readShort();
                this.lastCharIndex = data.readShort();
                if (this.version > 0) {
                    this.ascent = data.readShort_();
                    this.descent = data.readShort_();
                    this.lineGap = data.readShort_();
                    this.winAscent = data.readShort();
                    this.winDescent = data.readShort();
                    this.codePageRange = data.times(2, data.readLong);
                    if (this.version > 1) {
                        this.xHeight = data.readShort();
                        this.capHeight = data.readShort();
                        this.defaultChar = data.readShort();
                        this.breakChar = data.readShort();
                        this.maxContext = data.readShort();
                    }
                }
            },
            render: function () {
                return this.raw();
            }
        });
        var subsetTag = 100000;
        function nextSubsetTag() {
            var ret = '', n = String(subsetTag);
            for (var i = 0; i < n.length; ++i) {
                ret += String.fromCharCode(n.charCodeAt(i) - 48 + 65);
            }
            ++subsetTag;
            return ret;
        }
        function Subfont(font) {
            this.font = font;
            this.subset = {};
            this.unicodes = {};
            this.ogid2ngid = { 0: 0 };
            this.ngid2ogid = { 0: 0 };
            this.ncid2ogid = {};
            this.next = this.firstChar = 1;
            this.nextGid = 1;
            this.psName = nextSubsetTag() + '+' + this.font.psName;
        }
        Subfont.prototype = {
            use: function (ch) {
                var self = this;
                if (typeof ch == 'string') {
                    return ucs2decode(ch).reduce(function (ret, code) {
                        return ret + String.fromCharCode(self.use(code));
                    }, '');
                }
                var code = self.unicodes[ch];
                if (!code) {
                    code = self.next++;
                    self.subset[code] = ch;
                    self.unicodes[ch] = code;
                    var old_gid = self.font.cmap.codeMap[ch];
                    if (old_gid) {
                        self.ncid2ogid[code] = old_gid;
                        if (self.ogid2ngid[old_gid] == null) {
                            var new_gid = self.nextGid++;
                            self.ogid2ngid[old_gid] = new_gid;
                            self.ngid2ogid[new_gid] = old_gid;
                        }
                    }
                }
                return code;
            },
            encodeText: function (text) {
                return this.use(text);
            },
            glyphIds: function () {
                return sortedKeys(this.ogid2ngid);
            },
            glyphsFor: function (glyphIds, result) {
                var this$1 = this;
                if (!result) {
                    result = {};
                }
                for (var i = 0; i < glyphIds.length; ++i) {
                    var id = glyphIds[i];
                    if (!result[id]) {
                        var glyph = result[id] = this$1.font.glyf.glyphFor(id);
                        if (glyph && glyph.compound) {
                            this$1.glyphsFor(glyph.glyphIds, result);
                        }
                    }
                }
                return result;
            },
            render: function () {
                var this$1 = this;
                var glyphs = this.glyphsFor(this.glyphIds());
                for (var old_gid in glyphs) {
                    if (hasOwnProperty$1(glyphs, old_gid)) {
                        old_gid = parseInt(old_gid, 10);
                        if (this$1.ogid2ngid[old_gid] == null) {
                            var new_gid = this$1.nextGid++;
                            this$1.ogid2ngid[old_gid] = new_gid;
                            this$1.ngid2ogid[new_gid] = old_gid;
                        }
                    }
                }
                var new_gid_ids = sortedKeys(this.ngid2ogid);
                var old_gid_ids = new_gid_ids.map(function (id) {
                    return this.ngid2ogid[id];
                }, this);
                var font = this.font;
                var glyf = font.glyf.render(glyphs, old_gid_ids, this.ogid2ngid);
                var loca = font.loca.render(glyf.offsets);
                this.lastChar = this.next - 1;
                var tables = {
                    'cmap': CmapTable.render(this.ncid2ogid, this.ogid2ngid),
                    'glyf': glyf.table,
                    'loca': loca.table,
                    'hmtx': font.hmtx.render(old_gid_ids),
                    'hhea': font.hhea.render(old_gid_ids),
                    'maxp': font.maxp.render(old_gid_ids),
                    'post': font.post.render(old_gid_ids),
                    'name': font.name.render(this.psName),
                    'head': font.head.render(loca.format),
                    'OS/2': font.os2.render()
                };
                return this.font.directory.render(tables);
            },
            cidToGidMap: function () {
                var this$1 = this;
                var out = BinaryStream(), len = 0;
                for (var cid = this.firstChar; cid < this.next; ++cid) {
                    while (len < cid) {
                        out.writeShort(0);
                        len++;
                    }
                    var old_gid = this$1.ncid2ogid[cid];
                    if (old_gid) {
                        var new_gid = this$1.ogid2ngid[old_gid];
                        out.writeShort(new_gid);
                    } else {
                        out.writeShort(0);
                    }
                    len++;
                }
                return out.get();
            }
        };
        function TTFFont(rawData, name) {
            var self = this;
            var data = self.contents = BinaryStream(rawData);
            if (data.readString(4) == 'ttcf') {
                var offset;
                var parse = function () {
                    data.offset(offset);
                    self.parse();
                };
                if (!name) {
                    throw new Error('Must specify a name for TTC files');
                }
                data.readLong();
                var numFonts = data.readLong();
                for (var i = 0; i < numFonts; ++i) {
                    offset = data.readLong();
                    data.saveExcursion(parse);
                    if (self.psName == name) {
                        return;
                    }
                }
                throw new Error('Font ' + name + ' not found in collection');
            } else {
                data.offset(0);
                self.parse();
            }
        }
        TTFFont.prototype = {
            parse: function () {
                var dir = this.directory = new Directory(this.contents);
                this.head = dir.readTable('head', HeadTable);
                this.loca = dir.readTable('loca', LocaTable);
                this.hhea = dir.readTable('hhea', HheaTable);
                this.maxp = dir.readTable('maxp', MaxpTable);
                this.hmtx = dir.readTable('hmtx', HmtxTable);
                this.glyf = dir.readTable('glyf', GlyfTable);
                this.name = dir.readTable('name', NameTable);
                this.post = dir.readTable('post', PostTable);
                this.cmap = dir.readTable('cmap', CmapTable);
                this.os2 = dir.readTable('OS/2', OS2Table);
                this.psName = this.name.postscriptName;
                this.ascent = this.os2.ascent || this.hhea.ascent;
                this.descent = this.os2.descent || this.hhea.descent;
                this.lineGap = this.os2.lineGap || this.hhea.lineGap;
                this.scale = 1000 / this.head.unitsPerEm;
            },
            widthOfGlyph: function (glyph) {
                return this.hmtx.forGlyph(glyph).advance * this.scale;
            },
            makeSubset: function () {
                return new Subfont(this);
            }
        };
        var browser = kendo.support.browser;
        var NL = '\n';
        var RESOURCE_COUNTER = 0;
        var PAPER_SIZE = {
            a0: [
                2383.94,
                3370.39
            ],
            a1: [
                1683.78,
                2383.94
            ],
            a2: [
                1190.55,
                1683.78
            ],
            a3: [
                841.89,
                1190.55
            ],
            a4: [
                595.28,
                841.89
            ],
            a5: [
                419.53,
                595.28
            ],
            a6: [
                297.64,
                419.53
            ],
            a7: [
                209.76,
                297.64
            ],
            a8: [
                147.4,
                209.76
            ],
            a9: [
                104.88,
                147.4
            ],
            a10: [
                73.7,
                104.88
            ],
            b0: [
                2834.65,
                4008.19
            ],
            b1: [
                2004.09,
                2834.65
            ],
            b2: [
                1417.32,
                2004.09
            ],
            b3: [
                1000.63,
                1417.32
            ],
            b4: [
                708.66,
                1000.63
            ],
            b5: [
                498.9,
                708.66
            ],
            b6: [
                354.33,
                498.9
            ],
            b7: [
                249.45,
                354.33
            ],
            b8: [
                175.75,
                249.45
            ],
            b9: [
                124.72,
                175.75
            ],
            b10: [
                87.87,
                124.72
            ],
            c0: [
                2599.37,
                3676.54
            ],
            c1: [
                1836.85,
                2599.37
            ],
            c2: [
                1298.27,
                1836.85
            ],
            c3: [
                918.43,
                1298.27
            ],
            c4: [
                649.13,
                918.43
            ],
            c5: [
                459.21,
                649.13
            ],
            c6: [
                323.15,
                459.21
            ],
            c7: [
                229.61,
                323.15
            ],
            c8: [
                161.57,
                229.61
            ],
            c9: [
                113.39,
                161.57
            ],
            c10: [
                79.37,
                113.39
            ],
            executive: [
                521.86,
                756
            ],
            folio: [
                612,
                936
            ],
            legal: [
                612,
                1008
            ],
            letter: [
                612,
                792
            ],
            tabloid: [
                792,
                1224
            ]
        };
        function makeOutput() {
            var indentLevel = 0, output = BinaryStream();
            function out() {
                var arguments$1 = arguments;
                for (var i = 0; i < arguments.length; ++i) {
                    var x = arguments$1[i];
                    if (x === undefined) {
                        throw new Error('Cannot output undefined to PDF');
                    } else if (x instanceof PDFValue) {
                        x.beforeRender(out);
                        x.render(out);
                    } else if (isArray(x)) {
                        renderArray(x, out);
                    } else if (isDate(x)) {
                        renderDate(x, out);
                    } else if (typeof x == 'number') {
                        if (isNaN(x)) {
                            throw new Error('Cannot output NaN to PDF');
                        }
                        var num = x.toFixed(7);
                        if (num.indexOf('.') >= 0) {
                            num = num.replace(/\.?0+$/, '');
                        }
                        if (num == '-0') {
                            num = '0';
                        }
                        output.writeString(num);
                    } else if (/string|boolean/.test(typeof x)) {
                        output.writeString(String(x));
                    } else if (typeof x.get == 'function') {
                        output.write(x.get());
                    } else if (typeof x == 'object') {
                        if (!x) {
                            output.writeString('null');
                        } else {
                            out(new PDFDictionary(x));
                        }
                    }
                }
            }
            out.writeData = function (data) {
                output.write(data);
            };
            out.withIndent = function (f) {
                ++indentLevel;
                f(out);
                --indentLevel;
            };
            out.indent = function () {
                out(NL, pad('', indentLevel * 2, '  '));
                out.apply(null, arguments);
            };
            out.offset = function () {
                return output.offset();
            };
            out.toString = function () {
                throw new Error('FIX CALLER');
            };
            out.get = function () {
                return output.get();
            };
            out.stream = function () {
                return output;
            };
            return out;
        }
        function wrapObject(value, id) {
            var beforeRender = value.beforeRender;
            var renderValue = value.render;
            value.beforeRender = function () {
            };
            value.render = function (out) {
                out(id, ' 0 R');
            };
            value.renderFull = function (out) {
                value._offset = out.offset();
                out(id, ' 0 obj ');
                beforeRender.call(value, out);
                renderValue.call(value, out);
                out(' endobj');
            };
        }
        function getPaperOptions(getOption) {
            if (typeof getOption != 'function') {
                var options = getOption;
                getOption = function (key, def) {
                    return key in options ? options[key] : def;
                };
            }
            var paperSize = getOption('paperSize', PAPER_SIZE.a4);
            if (!paperSize) {
                return {};
            }
            if (typeof paperSize == 'string') {
                paperSize = PAPER_SIZE[paperSize.toLowerCase()];
                if (paperSize == null) {
                    throw new Error('Unknown paper size');
                }
            }
            paperSize[0] = unitsToPoints(paperSize[0]);
            paperSize[1] = unitsToPoints(paperSize[1]);
            if (getOption('landscape', false)) {
                paperSize = [
                    Math.max(paperSize[0], paperSize[1]),
                    Math.min(paperSize[0], paperSize[1])
                ];
            }
            var margin = getOption('margin');
            if (margin) {
                if (typeof margin == 'string' || typeof margin == 'number') {
                    margin = unitsToPoints(margin, 0);
                    margin = {
                        left: margin,
                        top: margin,
                        right: margin,
                        bottom: margin
                    };
                } else {
                    margin = {
                        left: unitsToPoints(margin.left, 0),
                        top: unitsToPoints(margin.top, 0),
                        right: unitsToPoints(margin.right, 0),
                        bottom: unitsToPoints(margin.bottom, 0)
                    };
                }
                if (getOption('addMargin')) {
                    paperSize[0] += margin.left + margin.right;
                    paperSize[1] += margin.top + margin.bottom;
                }
            }
            return {
                paperSize: paperSize,
                margin: margin
            };
        }
        function PDFDocument(options) {
            var self = this;
            var out = makeOutput();
            var objcount = 0;
            var objects = [];
            function getOption(name, defval) {
                return options && options[name] != null ? options[name] : defval;
            }
            self.getOption = getOption;
            self.attach = function (value) {
                if (objects.indexOf(value) < 0) {
                    wrapObject(value, ++objcount);
                    objects.push(value);
                }
                return value;
            };
            self.pages = [];
            self.FONTS = {};
            self.IMAGES = {};
            self.GRAD_COL_FUNCTIONS = {};
            self.GRAD_OPC_FUNCTIONS = {};
            self.GRAD_COL = {};
            self.GRAD_OPC = {};
            var catalog = self.attach(new PDFCatalog());
            var pageTree = self.attach(new PDFPageTree());
            if (getOption('autoPrint')) {
                var nameTree = {};
                nameTree.JavaScript = new PDFDictionary({
                    Names: [
                        new PDFString('JS'),
                        self.attach(new PDFDictionary({
                            S: _('JavaScript'),
                            JS: new PDFString('print(true);')
                        }))
                    ]
                });
                catalog.props.Names = new PDFDictionary(nameTree);
            }
            catalog.setPages(pageTree);
            var info = self.attach(new PDFDictionary({
                Producer: new PDFString(getOption('producer', 'Kendo UI PDF Generator')),
                Title: new PDFString(getOption('title', '')),
                Author: new PDFString(getOption('author', '')),
                Subject: new PDFString(getOption('subject', '')),
                Keywords: new PDFString(getOption('keywords', '')),
                Creator: new PDFString(getOption('creator', 'Kendo UI PDF Generator')),
                CreationDate: getOption('date', new Date())
            }));
            self.addPage = function (options) {
                var paperOptions = getPaperOptions(function (name, defval) {
                    return options && options[name] != null ? options[name] : defval;
                });
                var paperSize = paperOptions.paperSize;
                var margin = paperOptions.margin;
                var contentWidth = paperSize[0];
                var contentHeight = paperSize[1];
                if (margin) {
                    contentWidth -= margin.left + margin.right;
                    contentHeight -= margin.top + margin.bottom;
                }
                var content = new PDFStream(makeOutput(), null, true);
                var props = {
                    Contents: self.attach(content),
                    Parent: pageTree,
                    MediaBox: [
                        0,
                        0,
                        paperSize[0],
                        paperSize[1]
                    ]
                };
                var page = new PDFPage(self, props);
                page._content = content;
                pageTree.addPage(self.attach(page));
                page.transform(1, 0, 0, -1, 0, paperSize[1]);
                if (margin) {
                    page.translate(margin.left, margin.top);
                    page.rect(0, 0, contentWidth, contentHeight);
                    page.clip();
                }
                self.pages.push(page);
                return page;
            };
            self.render = function () {
                var i;
                out('%PDF-1.4', NL, '%ÂÁÚÏÎ', NL, NL);
                for (i = 0; i < objects.length; ++i) {
                    objects[i].renderFull(out);
                    out(NL, NL);
                }
                var xrefOffset = out.offset();
                out('xref', NL, 0, ' ', objects.length + 1, NL);
                out('0000000000 65535 f ', NL);
                for (i = 0; i < objects.length; ++i) {
                    out(zeropad(objects[i]._offset, 10), ' 00000 n ', NL);
                }
                out(NL);
                out('trailer', NL);
                out(new PDFDictionary({
                    Size: objects.length + 1,
                    Root: catalog,
                    Info: info
                }), NL, NL);
                out('startxref', NL, xrefOffset, NL);
                out('%%EOF', NL);
                return out.stream().offset(0);
            };
        }
        var FONT_CACHE = {
            'Times-Roman': true,
            'Times-Bold': true,
            'Times-Italic': true,
            'Times-BoldItalic': true,
            'Helvetica': true,
            'Helvetica-Bold': true,
            'Helvetica-Oblique': true,
            'Helvetica-BoldOblique': true,
            'Courier': true,
            'Courier-Bold': true,
            'Courier-Oblique': true,
            'Courier-BoldOblique': true,
            'Symbol': true,
            'ZapfDingbats': true
        };
        function loadBinary(url, cont) {
            var m;
            if (browser.msie && (m = /^data:.*?;base64,/i.exec(url))) {
                cont(base64ToUint8Array(url.substr(m[0].length)));
                return;
            }
            function error() {
                if (window.console) {
                    if (window.console.error) {
                        window.console.error('Cannot load URL: %s', url);
                    } else {
                        window.console.log('Cannot load URL: %s', url);
                    }
                }
                cont(null);
            }
            var req = new XMLHttpRequest();
            req.open('GET', url, true);
            if (HAS_TYPED_ARRAYS) {
                req.responseType = 'arraybuffer';
            }
            req.onload = function () {
                if (req.status == 200 || req.status == 304) {
                    if (HAS_TYPED_ARRAYS) {
                        cont(new Uint8Array(req.response));
                    } else {
                        cont(new window.VBArray(req.responseBody).toArray());
                    }
                } else {
                    error();
                }
            };
            req.onerror = error;
            req.send(null);
        }
        function loadFont(url, cont) {
            var font = FONT_CACHE[url];
            if (font) {
                cont(font);
            } else {
                loadBinary(url, function (data) {
                    if (data == null) {
                        throw new Error('Cannot load font from ' + url);
                    } else {
                        var font = new TTFFont(data);
                        FONT_CACHE[url] = font;
                        cont(font);
                    }
                });
            }
        }
        var IMAGE_CACHE = {};
        function clearImageCache() {
            IMAGE_CACHE = {};
        }
        function loadImage(url, size, cont) {
            var img = IMAGE_CACHE[url], bloburl, blob;
            if (img) {
                cont(img);
            } else {
                img = new Image();
                if (!/^data:/i.test(url)) {
                    img.crossOrigin = 'Anonymous';
                }
                if (HAS_TYPED_ARRAYS && !/^data:/i.test(url)) {
                    var xhr = new XMLHttpRequest();
                    xhr.onload = function () {
                        blob = xhr.response;
                        bloburl = URL.createObjectURL(blob);
                        _load(bloburl);
                    };
                    xhr.onerror = _onerror;
                    xhr.open('GET', url, true);
                    xhr.responseType = 'blob';
                    xhr.send();
                } else {
                    _load(url);
                }
            }
            function _load(url) {
                img.src = url;
                if (img.complete && !browser.msie) {
                    _onload();
                } else {
                    img.onload = _onload;
                    img.onerror = _onerror;
                }
            }
            function _trycanvas() {
                if (!size) {
                    size = {
                        width: img.width,
                        height: img.height
                    };
                }
                var canvas = document.createElement('canvas');
                canvas.width = size.width;
                canvas.height = size.height;
                var ctx = canvas.getContext('2d');
                ctx.drawImage(img, 0, 0, size.width, size.height);
                var imgdata;
                try {
                    imgdata = ctx.getImageData(0, 0, size.width, size.height);
                } catch (ex) {
                    _onerror();
                    return;
                } finally {
                    if (bloburl) {
                        URL.revokeObjectURL(bloburl);
                    }
                }
                var hasAlpha = false, rgb = BinaryStream(), alpha = BinaryStream();
                var rawbytes = imgdata.data;
                var i = 0;
                while (i < rawbytes.length) {
                    rgb.writeByte(rawbytes[i++]);
                    rgb.writeByte(rawbytes[i++]);
                    rgb.writeByte(rawbytes[i++]);
                    var a = rawbytes[i++];
                    if (a < 255) {
                        hasAlpha = true;
                    }
                    alpha.writeByte(a);
                }
                if (hasAlpha) {
                    img = new PDFRawImage(size.width, size.height, rgb, alpha);
                } else {
                    var data = canvas.toDataURL('image/jpeg');
                    data = data.substr(data.indexOf(';base64,') + 8);
                    var stream = BinaryStream();
                    stream.writeBase64(data);
                    img = new PDFJpegImage(stream);
                }
                cont(IMAGE_CACHE[url] = img);
            }
            function _onerror() {
                cont(IMAGE_CACHE[url] = 'ERROR');
            }
            function _onload() {
                if (size) {
                    if (size.width >= img.width || size.height >= img.height) {
                        size = null;
                    }
                }
                if (!size && blob && /^image\/jpe?g$/i.test(blob.type)) {
                    var reader = new FileReader();
                    reader.onload = function () {
                        try {
                            var img = new PDFJpegImage(BinaryStream(new Uint8Array(this.result)));
                            URL.revokeObjectURL(bloburl);
                            cont(IMAGE_CACHE[url] = img);
                        } catch (ex) {
                            _trycanvas();
                        }
                    };
                    reader.readAsArrayBuffer(blob);
                } else {
                    _trycanvas();
                }
            }
        }
        function manyLoader(loadOne) {
            return function (urls, callback) {
                var n = urls.length, i = n;
                if (n === 0) {
                    return callback();
                }
                function next() {
                    if (--n === 0) {
                        callback();
                    }
                }
                while (i-- > 0) {
                    loadOne(urls[i], next);
                }
            };
        }
        var loadFonts = manyLoader(loadFont);
        var loadImages = function (images, callback) {
            var urls = Object.keys(images), n = urls.length;
            if (n === 0) {
                return callback();
            }
            function next() {
                if (--n === 0) {
                    callback();
                }
            }
            urls.forEach(function (url) {
                loadImage(url, images[url], next);
            });
        };
        PDFDocument.prototype = {
            loadFonts: loadFonts,
            loadImages: loadImages,
            getFont: function (url) {
                var font = this.FONTS[url];
                if (!font) {
                    font = FONT_CACHE[url];
                    if (!font) {
                        throw new Error('Font ' + url + ' has not been loaded');
                    }
                    if (font === true) {
                        font = this.attach(new PDFStandardFont(url));
                    } else {
                        font = this.attach(new PDFFont(this, font));
                    }
                    this.FONTS[url] = font;
                }
                return font;
            },
            getImage: function (url) {
                var img = this.IMAGES[url];
                if (!img) {
                    img = IMAGE_CACHE[url];
                    if (!img) {
                        throw new Error('Image ' + url + ' has not been loaded');
                    }
                    if (img === 'ERROR') {
                        return null;
                    }
                    img = this.IMAGES[url] = this.attach(img.asStream(this));
                }
                return img;
            },
            getOpacityGS: function (opacity, forStroke) {
                var id = parseFloat(opacity).toFixed(3);
                opacity = parseFloat(id);
                id += forStroke ? 'S' : 'F';
                var cache = this._opacityGSCache || (this._opacityGSCache = {});
                var gs = cache[id];
                if (!gs) {
                    var props = { Type: _('ExtGState') };
                    if (forStroke) {
                        props.CA = opacity;
                    } else {
                        props.ca = opacity;
                    }
                    gs = this.attach(new PDFDictionary(props));
                    gs._resourceName = _('GS' + ++RESOURCE_COUNTER);
                    cache[id] = gs;
                }
                return gs;
            },
            dict: function (props) {
                return new PDFDictionary(props);
            },
            name: function (str) {
                return _(str);
            },
            stream: function (props, content) {
                return new PDFStream(content, props);
            }
        };
        function pad(str, len, ch) {
            while (str.length < len) {
                str = ch + str;
            }
            return str;
        }
        function zeropad(n, len) {
            return pad(String(n), len, '0');
        }
        function hasOwnProperty(obj, key) {
            return Object.prototype.hasOwnProperty.call(obj, key);
        }
        var isArray = Array.isArray || function (obj) {
            return obj instanceof Array;
        };
        function isDate(obj) {
            return obj instanceof Date;
        }
        function renderArray(a, out) {
            out('[');
            if (a.length > 0) {
                out.withIndent(function () {
                    for (var i = 0; i < a.length; ++i) {
                        if (i > 0 && i % 8 === 0) {
                            out.indent(a[i]);
                        } else {
                            out(' ', a[i]);
                        }
                    }
                });
            }
            out(' ]');
        }
        function renderDate(date, out) {
            out('(D:', zeropad(date.getUTCFullYear(), 4), zeropad(date.getUTCMonth() + 1, 2), zeropad(date.getUTCDate(), 2), zeropad(date.getUTCHours(), 2), zeropad(date.getUTCMinutes(), 2), zeropad(date.getUTCSeconds(), 2), 'Z)');
        }
        function mm2pt(mm) {
            return mm * (72 / 25.4);
        }
        function cm2pt(cm) {
            return mm2pt(cm * 10);
        }
        function in2pt(inch) {
            return inch * 72;
        }
        function unitsToPoints(x, def) {
            if (typeof x == 'number') {
                return x;
            }
            if (typeof x == 'string') {
                var m;
                m = /^\s*([0-9.]+)\s*(mm|cm|in|pt)\s*$/.exec(x);
                if (m) {
                    var num = parseFloat(m[1]);
                    if (!isNaN(num)) {
                        if (m[2] == 'pt') {
                            return num;
                        }
                        return {
                            'mm': mm2pt,
                            'cm': cm2pt,
                            'in': in2pt
                        }[m[2]](num);
                    }
                }
            }
            if (def != null) {
                return def;
            }
            throw new Error('Can\'t parse unit: ' + x);
        }
        function PDFValue() {
        }
        PDFValue.prototype.beforeRender = function () {
        };
        function defclass(Ctor, proto, Base) {
            if (!Base) {
                Base = PDFValue;
            }
            Ctor.prototype = new Base();
            for (var i in proto) {
                if (hasOwnProperty(proto, i)) {
                    Ctor.prototype[i] = proto[i];
                }
            }
            return Ctor;
        }
        var PDFString = defclass(function PDFString(value) {
            this.value = value;
        }, {
            render: function (out) {
                var txt = '', val = this.value;
                for (var i = 0; i < val.length; ++i) {
                    txt += String.fromCharCode(val.charCodeAt(i) & 255);
                }
                out('(', txt.replace(/([\(\)\\])/g, '\\$1'), ')');
            },
            toString: function () {
                return this.value;
            }
        });
        var PDFHexString = defclass(function PDFHexString(value) {
            this.value = value;
        }, {
            render: function (out) {
                var this$1 = this;
                out('<');
                for (var i = 0; i < this.value.length; ++i) {
                    out(zeropad(this$1.value.charCodeAt(i).toString(16), 4));
                }
                out('>');
            }
        }, PDFString);
        var PDFName = defclass(function PDFName(name) {
            this.name = name;
        }, {
            render: function (out) {
                out('/' + this.escape());
            },
            escape: function () {
                return this.name.replace(/[^\x21-\x7E]/g, function (c) {
                    return '#' + zeropad(c.charCodeAt(0).toString(16), 2);
                });
            },
            toString: function () {
                return this.name;
            }
        });
        var PDFName_cache = {};
        PDFName.get = _;
        function _(name) {
            if (hasOwnProperty(PDFName_cache, name)) {
                return PDFName_cache[name];
            }
            return PDFName_cache[name] = new PDFName(name);
        }
        var PDFDictionary = defclass(function PDFDictionary(props) {
            this.props = props;
        }, {
            render: function (out) {
                var props = this.props, empty = true;
                out('<<');
                out.withIndent(function () {
                    for (var i in props) {
                        if (hasOwnProperty(props, i) && !/^_/.test(i)) {
                            empty = false;
                            out.indent(_(i), ' ', props[i]);
                        }
                    }
                });
                if (!empty) {
                    out.indent();
                }
                out('>>');
            }
        });
        var PDFStream = defclass(function PDFStream(data, props, compress) {
            if (typeof data == 'string') {
                var tmp = BinaryStream();
                tmp.write(data);
                data = tmp;
            }
            this.data = data;
            this.props = props || {};
            this.compress = compress;
        }, {
            render: function (out) {
                var data = this.data.get(), props = this.props;
                if (this.compress && kendoPdf.supportsDeflate()) {
                    if (!props.Filter) {
                        props.Filter = [];
                    } else if (!(props.Filter instanceof Array)) {
                        props.Filter = [props.Filter];
                    }
                    props.Filter.unshift(_('FlateDecode'));
                    data = kendoPdf.deflate(data);
                }
                props.Length = data.length;
                out(new PDFDictionary(props), ' stream', NL);
                out.writeData(data);
                out(NL, 'endstream');
            }
        });
        var PDFCatalog = defclass(function PDFCatalog() {
            this.props = { Type: _('Catalog') };
        }, {
            setPages: function (pagesObj) {
                this.props.Pages = pagesObj;
            }
        }, PDFDictionary);
        var PDFPageTree = defclass(function PDFPageTree() {
            this.props = {
                Type: _('Pages'),
                Kids: [],
                Count: 0
            };
        }, {
            addPage: function (pageObj) {
                this.props.Kids.push(pageObj);
                this.props.Count++;
            }
        }, PDFDictionary);
        var SOF_CODES = [
            192,
            193,
            194,
            195,
            197,
            198,
            199,
            201,
            202,
            203,
            205,
            206,
            207
        ];
        function PDFJpegImage(data) {
            data.offset(0);
            var width, height, colorSpace, bitsPerComponent;
            var soi = data.readShort();
            if (soi != 65496) {
                throw new Error('Invalid JPEG image');
            }
            while (!data.eof()) {
                var ff = data.readByte();
                if (ff != 255) {
                    throw new Error('Invalid JPEG image');
                }
                var marker = data.readByte();
                var length = data.readShort();
                if (SOF_CODES.indexOf(marker) >= 0) {
                    bitsPerComponent = data.readByte();
                    height = data.readShort();
                    width = data.readShort();
                    colorSpace = data.readByte();
                    break;
                }
                data.skip(length - 2);
            }
            if (colorSpace == null) {
                throw new Error('Invalid JPEG image');
            }
            var props = {
                Type: _('XObject'),
                Subtype: _('Image'),
                Width: width,
                Height: height,
                BitsPerComponent: bitsPerComponent,
                Filter: _('DCTDecode')
            };
            switch (colorSpace) {
            case 1:
                props.ColorSpace = _('DeviceGray');
                break;
            case 3:
                props.ColorSpace = _('DeviceRGB');
                break;
            case 4:
                props.ColorSpace = _('DeviceCMYK');
                props.Decode = [
                    1,
                    0,
                    1,
                    0,
                    1,
                    0,
                    1,
                    0
                ];
                break;
            }
            this.asStream = function () {
                data.offset(0);
                var stream = new PDFStream(data, props);
                stream._resourceName = _('I' + ++RESOURCE_COUNTER);
                return stream;
            };
        }
        function PDFRawImage(width, height, rgb, alpha) {
            this.asStream = function (pdf) {
                var mask = new PDFStream(alpha, {
                    Type: _('XObject'),
                    Subtype: _('Image'),
                    Width: width,
                    Height: height,
                    BitsPerComponent: 8,
                    ColorSpace: _('DeviceGray')
                }, true);
                var stream = new PDFStream(rgb, {
                    Type: _('XObject'),
                    Subtype: _('Image'),
                    Width: width,
                    Height: height,
                    BitsPerComponent: 8,
                    ColorSpace: _('DeviceRGB'),
                    SMask: pdf.attach(mask)
                }, true);
                stream._resourceName = _('I' + ++RESOURCE_COUNTER);
                return stream;
            };
        }
        var PDFStandardFont = defclass(function PDFStandardFont(name) {
            this.props = {
                Type: _('Font'),
                Subtype: _('Type1'),
                BaseFont: _(name)
            };
            this._resourceName = _('F' + ++RESOURCE_COUNTER);
        }, {
            encodeText: function (str) {
                return new PDFString(String(str));
            }
        }, PDFDictionary);
        var PDFFont = defclass(function PDFFont(pdf, font, props) {
            props = this.props = props || {};
            props.Type = _('Font');
            props.Subtype = _('Type0');
            props.Encoding = _('Identity-H');
            this._pdf = pdf;
            this._font = font;
            this._sub = font.makeSubset();
            this._resourceName = _('F' + ++RESOURCE_COUNTER);
            var head = font.head;
            this.name = font.psName;
            var scale = this.scale = font.scale;
            this.bbox = [
                head.xMin * scale,
                head.yMin * scale,
                head.xMax * scale,
                head.yMax * scale
            ];
            this.italicAngle = font.post.italicAngle;
            this.ascent = font.ascent * scale;
            this.descent = font.descent * scale;
            this.lineGap = font.lineGap * scale;
            this.capHeight = font.os2.capHeight || this.ascent;
            this.xHeight = font.os2.xHeight || 0;
            this.stemV = 0;
            this.familyClass = (font.os2.familyClass || 0) >> 8;
            this.isSerif = this.familyClass >= 1 && this.familyClass <= 7;
            this.isScript = this.familyClass == 10;
            this.flags = (font.post.isFixedPitch ? 1 : 0) | (this.isSerif ? 1 << 1 : 0) | (this.isScript ? 1 << 3 : 0) | (this.italicAngle !== 0 ? 1 << 6 : 0) | 1 << 5;
        }, {
            encodeText: function (text) {
                return new PDFHexString(this._sub.encodeText(String(text)));
            },
            getTextWidth: function (fontSize, text) {
                var this$1 = this;
                var width = 0, codeMap = this._font.cmap.codeMap;
                for (var i = 0; i < text.length; ++i) {
                    var glyphId = codeMap[text.charCodeAt(i)];
                    width += this$1._font.widthOfGlyph(glyphId || 0);
                }
                return width * fontSize / 1000;
            },
            beforeRender: function () {
                var self = this;
                var sub = self._sub;
                var data = sub.render();
                var fontStream = new PDFStream(BinaryStream(data), { Length1: data.length }, true);
                var descriptor = self._pdf.attach(new PDFDictionary({
                    Type: _('FontDescriptor'),
                    FontName: _(self._sub.psName),
                    FontBBox: self.bbox,
                    Flags: self.flags,
                    StemV: self.stemV,
                    ItalicAngle: self.italicAngle,
                    Ascent: self.ascent,
                    Descent: self.descent,
                    CapHeight: self.capHeight,
                    XHeight: self.xHeight,
                    FontFile2: self._pdf.attach(fontStream)
                }));
                var cmap = sub.ncid2ogid;
                var firstChar = sub.firstChar;
                var lastChar = sub.lastChar;
                var charWidths = [];
                (function loop(i, chunk) {
                    if (i <= lastChar) {
                        var gid = cmap[i];
                        if (gid == null) {
                            loop(i + 1);
                        } else {
                            if (!chunk) {
                                charWidths.push(i, chunk = []);
                            }
                            chunk.push(self._font.widthOfGlyph(gid));
                            loop(i + 1, chunk);
                        }
                    }
                }(firstChar));
                var descendant = new PDFDictionary({
                    Type: _('Font'),
                    Subtype: _('CIDFontType2'),
                    BaseFont: _(self._sub.psName),
                    CIDSystemInfo: new PDFDictionary({
                        Registry: new PDFString('Adobe'),
                        Ordering: new PDFString('Identity'),
                        Supplement: 0
                    }),
                    FontDescriptor: descriptor,
                    FirstChar: firstChar,
                    LastChar: lastChar,
                    DW: Math.round(self._font.widthOfGlyph(0)),
                    W: charWidths,
                    CIDToGIDMap: self._pdf.attach(self._makeCidToGidMap())
                });
                var dict = self.props;
                dict.BaseFont = _(self._sub.psName);
                dict.DescendantFonts = [self._pdf.attach(descendant)];
                var unimap = new PDFToUnicodeCmap(firstChar, lastChar, sub.subset);
                var unimapStream = new PDFStream(makeOutput(), null, true);
                unimapStream.data(unimap);
                dict.ToUnicode = self._pdf.attach(unimapStream);
            },
            _makeCidToGidMap: function () {
                return new PDFStream(BinaryStream(this._sub.cidToGidMap()), null, true);
            }
        }, PDFDictionary);
        var PDFToUnicodeCmap = defclass(function PDFUnicodeCMap(firstChar, lastChar, map) {
            this.firstChar = firstChar;
            this.lastChar = lastChar;
            this.map = map;
        }, {
            render: function (out) {
                out.indent('/CIDInit /ProcSet findresource begin');
                out.indent('12 dict begin');
                out.indent('begincmap');
                out.indent('/CIDSystemInfo <<');
                out.indent('  /Registry (Adobe)');
                out.indent('  /Ordering (UCS)');
                out.indent('  /Supplement 0');
                out.indent('>> def');
                out.indent('/CMapName /Adobe-Identity-UCS def');
                out.indent('/CMapType 2 def');
                out.indent('1 begincodespacerange');
                out.indent('  <0000><ffff>');
                out.indent('endcodespacerange');
                var self = this;
                out.indent(self.lastChar - self.firstChar + 1, ' beginbfchar');
                out.withIndent(function () {
                    for (var code = self.firstChar; code <= self.lastChar; ++code) {
                        var unicode = self.map[code];
                        var str = ucs2encode([unicode]);
                        out.indent('<', zeropad(code.toString(16), 4), '>', '<');
                        for (var i = 0; i < str.length; ++i) {
                            out(zeropad(str.charCodeAt(i).toString(16), 4));
                        }
                        out('>');
                    }
                });
                out.indent('endbfchar');
                out.indent('endcmap');
                out.indent('CMapName currentdict /CMap defineresource pop');
                out.indent('end');
                out.indent('end');
            }
        });
        function makeHash(a) {
            return a.map(function (x) {
                return isArray(x) ? makeHash(x) : typeof x == 'number' ? (Math.round(x * 1000) / 1000).toFixed(3) : x;
            }).join(' ');
        }
        function cacheColorGradientFunction(pdf, r1, g1, b1, r2, g2, b2) {
            var hash = makeHash([
                r1,
                g1,
                b1,
                r2,
                g2,
                b2
            ]);
            var func = pdf.GRAD_COL_FUNCTIONS[hash];
            if (!func) {
                func = pdf.GRAD_COL_FUNCTIONS[hash] = pdf.attach(new PDFDictionary({
                    FunctionType: 2,
                    Domain: [
                        0,
                        1
                    ],
                    Range: [
                        0,
                        1,
                        0,
                        1,
                        0,
                        1
                    ],
                    N: 1,
                    C0: [
                        r1,
                        g1,
                        b1
                    ],
                    C1: [
                        r2,
                        g2,
                        b2
                    ]
                }));
            }
            return func;
        }
        function cacheOpacityGradientFunction(pdf, a1, a2) {
            var hash = makeHash([
                a1,
                a2
            ]);
            var func = pdf.GRAD_OPC_FUNCTIONS[hash];
            if (!func) {
                func = pdf.GRAD_OPC_FUNCTIONS[hash] = pdf.attach(new PDFDictionary({
                    FunctionType: 2,
                    Domain: [
                        0,
                        1
                    ],
                    Range: [
                        0,
                        1
                    ],
                    N: 1,
                    C0: [a1],
                    C1: [a2]
                }));
            }
            return func;
        }
        function makeGradientFunctions(pdf, stops) {
            var hasAlpha = false;
            var opacities = [];
            var colors = [];
            var offsets = [];
            var encode = [];
            var i, prev, cur, prevColor, curColor;
            for (i = 1; i < stops.length; ++i) {
                prev = stops[i - 1];
                cur = stops[i];
                prevColor = prev.color;
                curColor = cur.color;
                colors.push(cacheColorGradientFunction(pdf, prevColor.r, prevColor.g, prevColor.b, curColor.r, curColor.g, curColor.b));
                if (prevColor.a < 1 || curColor.a < 1) {
                    hasAlpha = true;
                }
                offsets.push(cur.offset);
                encode.push(0, 1);
            }
            if (hasAlpha) {
                for (i = 1; i < stops.length; ++i) {
                    prev = stops[i - 1];
                    cur = stops[i];
                    prevColor = prev.color;
                    curColor = cur.color;
                    opacities.push(cacheOpacityGradientFunction(pdf, prevColor.a, curColor.a));
                }
            }
            offsets.pop();
            return {
                hasAlpha: hasAlpha,
                colors: assemble(colors),
                opacities: hasAlpha ? assemble(opacities) : null
            };
            function assemble(funcs) {
                if (funcs.length == 1) {
                    return funcs[0];
                }
                return {
                    FunctionType: 3,
                    Functions: funcs,
                    Domain: [
                        0,
                        1
                    ],
                    Bounds: offsets,
                    Encode: encode
                };
            }
        }
        function cacheColorGradient(pdf, isRadial, stops, coords, funcs, box) {
            var shading, hash;
            if (!box) {
                var a = [isRadial].concat(coords);
                stops.forEach(function (x) {
                    a.push(x.offset, x.color.r, x.color.g, x.color.b);
                });
                hash = makeHash(a);
                shading = pdf.GRAD_COL[hash];
            }
            if (!shading) {
                shading = new PDFDictionary({
                    Type: _('Shading'),
                    ShadingType: isRadial ? 3 : 2,
                    ColorSpace: _('DeviceRGB'),
                    Coords: coords,
                    Domain: [
                        0,
                        1
                    ],
                    Function: funcs,
                    Extend: [
                        true,
                        true
                    ]
                });
                pdf.attach(shading);
                shading._resourceName = 'S' + ++RESOURCE_COUNTER;
                if (hash) {
                    pdf.GRAD_COL[hash] = shading;
                }
            }
            return shading;
        }
        function cacheOpacityGradient(pdf, isRadial, stops, coords, funcs, box) {
            var opacity, hash;
            if (!box) {
                var a = [isRadial].concat(coords);
                stops.forEach(function (x) {
                    a.push(x.offset, x.color.a);
                });
                hash = makeHash(a);
                opacity = pdf.GRAD_OPC[hash];
            }
            if (!opacity) {
                opacity = new PDFDictionary({
                    Type: _('ExtGState'),
                    AIS: false,
                    CA: 1,
                    ca: 1,
                    SMask: {
                        Type: _('Mask'),
                        S: _('Luminosity'),
                        G: pdf.attach(new PDFStream('/a0 gs /s0 sh', {
                            Type: _('XObject'),
                            Subtype: _('Form'),
                            FormType: 1,
                            BBox: box ? [
                                box.left,
                                box.top + box.height,
                                box.left + box.width,
                                box.top
                            ] : [
                                0,
                                1,
                                1,
                                0
                            ],
                            Group: {
                                Type: _('Group'),
                                S: _('Transparency'),
                                CS: _('DeviceGray'),
                                I: true
                            },
                            Resources: {
                                ExtGState: {
                                    a0: {
                                        CA: 1,
                                        ca: 1
                                    }
                                },
                                Shading: {
                                    s0: {
                                        ColorSpace: _('DeviceGray'),
                                        Coords: coords,
                                        Domain: [
                                            0,
                                            1
                                        ],
                                        ShadingType: isRadial ? 3 : 2,
                                        Function: funcs,
                                        Extend: [
                                            true,
                                            true
                                        ]
                                    }
                                }
                            }
                        }))
                    }
                });
                pdf.attach(opacity);
                opacity._resourceName = 'O' + ++RESOURCE_COUNTER;
                if (hash) {
                    pdf.GRAD_OPC[hash] = opacity;
                }
            }
            return opacity;
        }
        function cacheGradient(pdf, gradient, box) {
            var isRadial = gradient.type == 'radial';
            var funcs = makeGradientFunctions(pdf, gradient.stops);
            var coords = isRadial ? [
                gradient.start.x,
                gradient.start.y,
                gradient.start.r,
                gradient.end.x,
                gradient.end.y,
                gradient.end.r
            ] : [
                gradient.start.x,
                gradient.start.y,
                gradient.end.x,
                gradient.end.y
            ];
            var shading = cacheColorGradient(pdf, isRadial, gradient.stops, coords, funcs.colors, gradient.userSpace && box);
            var opacity = funcs.hasAlpha ? cacheOpacityGradient(pdf, isRadial, gradient.stops, coords, funcs.opacities, gradient.userSpace && box) : null;
            return {
                hasAlpha: funcs.hasAlpha,
                shading: shading,
                opacity: opacity
            };
        }
        var PDFPage = defclass(function PDFPage(pdf, props) {
            this._pdf = pdf;
            this._rcount = 0;
            this._textMode = false;
            this._fontResources = {};
            this._gsResources = {};
            this._xResources = {};
            this._patResources = {};
            this._shResources = {};
            this._opacity = 1;
            this._matrix = [
                1,
                0,
                0,
                1,
                0,
                0
            ];
            this._annotations = [];
            this._font = null;
            this._fontSize = null;
            this._contextStack = [];
            props = this.props = props || {};
            props.Type = _('Page');
            props.ProcSet = [
                _('PDF'),
                _('Text'),
                _('ImageB'),
                _('ImageC'),
                _('ImageI')
            ];
            props.Resources = new PDFDictionary({
                Font: new PDFDictionary(this._fontResources),
                ExtGState: new PDFDictionary(this._gsResources),
                XObject: new PDFDictionary(this._xResources),
                Pattern: new PDFDictionary(this._patResources),
                Shading: new PDFDictionary(this._shResources)
            });
            props.Annots = this._annotations;
        }, {
            _out: function () {
                this._content.data.apply(null, arguments);
            },
            transform: function (a, b, c, d, e, f) {
                if (!isIdentityMatrix(arguments)) {
                    this._matrix = mmul(arguments, this._matrix);
                    this._out(a, ' ', b, ' ', c, ' ', d, ' ', e, ' ', f, ' cm');
                    this._out(NL);
                }
            },
            translate: function (dx, dy) {
                this.transform(1, 0, 0, 1, dx, dy);
            },
            scale: function (sx, sy) {
                this.transform(sx, 0, 0, sy, 0, 0);
            },
            rotate: function (angle) {
                var cos = Math.cos(angle), sin = Math.sin(angle);
                this.transform(cos, sin, -sin, cos, 0, 0);
            },
            beginText: function () {
                this._textMode = true;
                this._out('BT', NL);
            },
            endText: function () {
                this._textMode = false;
                this._out('ET', NL);
            },
            _requireTextMode: function () {
                if (!this._textMode) {
                    throw new Error('Text mode required; call page.beginText() first');
                }
            },
            _requireFont: function () {
                if (!this._font) {
                    throw new Error('No font selected; call page.setFont() first');
                }
            },
            setFont: function (font, size) {
                this._requireTextMode();
                if (font == null) {
                    font = this._font;
                } else if (!(font instanceof PDFFont)) {
                    font = this._pdf.getFont(font);
                }
                if (size == null) {
                    size = this._fontSize;
                }
                this._fontResources[font._resourceName] = font;
                this._font = font;
                this._fontSize = size;
                this._out(font._resourceName, ' ', size, ' Tf', NL);
            },
            setTextLeading: function (size) {
                this._requireTextMode();
                this._out(size, ' TL', NL);
            },
            setTextRenderingMode: function (mode) {
                this._requireTextMode();
                this._out(mode, ' Tr', NL);
            },
            showText: function (text, requestedWidth) {
                this._requireFont();
                if (text.length > 1 && requestedWidth && this._font instanceof PDFFont) {
                    var outputWidth = this._font.getTextWidth(this._fontSize, text);
                    var scale = requestedWidth / outputWidth * 100;
                    this._out(scale, ' Tz ');
                }
                this._out(this._font.encodeText(text), ' Tj', NL);
            },
            showTextNL: function (text) {
                this._requireFont();
                this._out(this._font.encodeText(text), ' \'', NL);
            },
            addLink: function (uri, box) {
                var ll = this._toPage({
                    x: box.left,
                    y: box.bottom
                });
                var ur = this._toPage({
                    x: box.right,
                    y: box.top
                });
                this._annotations.push(new PDFDictionary({
                    Type: _('Annot'),
                    Subtype: _('Link'),
                    Rect: [
                        ll.x,
                        ll.y,
                        ur.x,
                        ur.y
                    ],
                    Border: [
                        0,
                        0,
                        0
                    ],
                    A: new PDFDictionary({
                        Type: _('Action'),
                        S: _('URI'),
                        URI: new PDFString(uri)
                    })
                }));
            },
            setStrokeColor: function (r, g, b) {
                this._out(r, ' ', g, ' ', b, ' RG', NL);
            },
            setOpacity: function (opacity) {
                this.setFillOpacity(opacity);
                this.setStrokeOpacity(opacity);
                this._opacity *= opacity;
            },
            setStrokeOpacity: function (opacity) {
                if (opacity < 1) {
                    var gs = this._pdf.getOpacityGS(this._opacity * opacity, true);
                    this._gsResources[gs._resourceName] = gs;
                    this._out(gs._resourceName, ' gs', NL);
                }
            },
            setFillColor: function (r, g, b) {
                this._out(r, ' ', g, ' ', b, ' rg', NL);
            },
            setFillOpacity: function (opacity) {
                if (opacity < 1) {
                    var gs = this._pdf.getOpacityGS(this._opacity * opacity, false);
                    this._gsResources[gs._resourceName] = gs;
                    this._out(gs._resourceName, ' gs', NL);
                }
            },
            gradient: function (gradient, box) {
                this.save();
                this.rect(box.left, box.top, box.width, box.height);
                this.clip();
                if (!gradient.userSpace) {
                    this.transform(box.width, 0, 0, box.height, box.left, box.top);
                }
                var g = cacheGradient(this._pdf, gradient, box);
                var sname = g.shading._resourceName, oname;
                this._shResources[sname] = g.shading;
                if (g.hasAlpha) {
                    oname = g.opacity._resourceName;
                    this._gsResources[oname] = g.opacity;
                    this._out('/' + oname + ' gs ');
                }
                this._out('/' + sname + ' sh', NL);
                this.restore();
            },
            setDashPattern: function (dashArray, dashPhase) {
                this._out(dashArray, ' ', dashPhase, ' d', NL);
            },
            setLineWidth: function (width) {
                this._out(width, ' w', NL);
            },
            setLineCap: function (lineCap) {
                this._out(lineCap, ' J', NL);
            },
            setLineJoin: function (lineJoin) {
                this._out(lineJoin, ' j', NL);
            },
            setMitterLimit: function (mitterLimit) {
                this._out(mitterLimit, ' M', NL);
            },
            save: function () {
                this._contextStack.push(this._context());
                this._out('q', NL);
            },
            restore: function () {
                this._out('Q', NL);
                this._context(this._contextStack.pop());
            },
            moveTo: function (x, y) {
                this._out(x, ' ', y, ' m', NL);
            },
            lineTo: function (x, y) {
                this._out(x, ' ', y, ' l', NL);
            },
            bezier: function (x1, y1, x2, y2, x3, y3) {
                this._out(x1, ' ', y1, ' ', x2, ' ', y2, ' ', x3, ' ', y3, ' c', NL);
            },
            bezier1: function (x1, y1, x3, y3) {
                this._out(x1, ' ', y1, ' ', x3, ' ', y3, ' y', NL);
            },
            bezier2: function (x2, y2, x3, y3) {
                this._out(x2, ' ', y2, ' ', x3, ' ', y3, ' v', NL);
            },
            close: function () {
                this._out('h', NL);
            },
            rect: function (x, y, w, h) {
                this._out(x, ' ', y, ' ', w, ' ', h, ' re', NL);
            },
            ellipse: function (x, y, rx, ry) {
                function _X(v) {
                    return x + v;
                }
                function _Y(v) {
                    return y + v;
                }
                var k = 0.5522847498307936;
                this.moveTo(_X(0), _Y(ry));
                this.bezier(_X(rx * k), _Y(ry), _X(rx), _Y(ry * k), _X(rx), _Y(0));
                this.bezier(_X(rx), _Y(-ry * k), _X(rx * k), _Y(-ry), _X(0), _Y(-ry));
                this.bezier(_X(-rx * k), _Y(-ry), _X(-rx), _Y(-ry * k), _X(-rx), _Y(0));
                this.bezier(_X(-rx), _Y(ry * k), _X(-rx * k), _Y(ry), _X(0), _Y(ry));
            },
            circle: function (x, y, r) {
                this.ellipse(x, y, r, r);
            },
            stroke: function () {
                this._out('S', NL);
            },
            nop: function () {
                this._out('n', NL);
            },
            clip: function () {
                this._out('W n', NL);
            },
            clipStroke: function () {
                this._out('W S', NL);
            },
            closeStroke: function () {
                this._out('s', NL);
            },
            fill: function () {
                this._out('f', NL);
            },
            fillStroke: function () {
                this._out('B', NL);
            },
            drawImage: function (url) {
                var img = this._pdf.getImage(url);
                if (img) {
                    this._xResources[img._resourceName] = img;
                    this._out(img._resourceName, ' Do', NL);
                }
            },
            comment: function (txt) {
                var self = this;
                txt.split(/\r?\n/g).forEach(function (line) {
                    self._out('% ', line, NL);
                });
            },
            _context: function (val) {
                if (val != null) {
                    this._opacity = val.opacity;
                    this._matrix = val.matrix;
                } else {
                    return {
                        opacity: this._opacity,
                        matrix: this._matrix
                    };
                }
            },
            _toPage: function (p) {
                var m = this._matrix;
                var a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];
                return {
                    x: a * p.x + c * p.y + e,
                    y: b * p.x + d * p.y + f
                };
            }
        }, PDFDictionary);
        function unquote(str) {
            return str.replace(/^\s*(['"])(.*)\1\s*$/, '$2');
        }
        function parseFontDef(fontdef) {
            var rx = /^\s*((normal|italic)\s+)?((normal|small-caps)\s+)?((normal|bold|\d+)\s+)?(([0-9.]+)(px|pt))(\/(([0-9.]+)(px|pt)|normal))?\s+(.*?)\s*$/i;
            var m = rx.exec(fontdef);
            if (!m) {
                return {
                    fontSize: 12,
                    fontFamily: 'sans-serif'
                };
            }
            var fontSize = m[8] ? parseInt(m[8], 10) : 12;
            return {
                italic: m[2] && m[2].toLowerCase() == 'italic',
                variant: m[4],
                bold: m[6] && /bold|700/i.test(m[6]),
                fontSize: fontSize,
                lineHeight: m[12] ? m[12] == 'normal' ? fontSize : parseInt(m[12], 10) : null,
                fontFamily: m[14].split(/\s*,\s*/g).map(unquote)
            };
        }
        function getFontURL(style) {
            function mkFamily(name) {
                if (style.bold) {
                    name += '|bold';
                }
                if (style.italic) {
                    name += '|italic';
                }
                return name.toLowerCase();
            }
            var fontFamily = style.fontFamily;
            var name, url;
            if (fontFamily instanceof Array) {
                for (var i = 0; i < fontFamily.length; ++i) {
                    name = mkFamily(fontFamily[i]);
                    url = FONT_MAPPINGS[name];
                    if (url) {
                        break;
                    }
                }
            } else {
                url = FONT_MAPPINGS[fontFamily.toLowerCase()];
            }
            while (typeof url == 'function') {
                url = url();
            }
            if (!url) {
                url = 'Times-Roman';
            }
            return url;
        }
        var FONT_MAPPINGS = {
            'serif': 'Times-Roman',
            'serif|bold': 'Times-Bold',
            'serif|italic': 'Times-Italic',
            'serif|bold|italic': 'Times-BoldItalic',
            'sans-serif': 'Helvetica',
            'sans-serif|bold': 'Helvetica-Bold',
            'sans-serif|italic': 'Helvetica-Oblique',
            'sans-serif|bold|italic': 'Helvetica-BoldOblique',
            'monospace': 'Courier',
            'monospace|bold': 'Courier-Bold',
            'monospace|italic': 'Courier-Oblique',
            'monospace|bold|italic': 'Courier-BoldOblique',
            'zapfdingbats': 'ZapfDingbats',
            'zapfdingbats|bold': 'ZapfDingbats',
            'zapfdingbats|italic': 'ZapfDingbats',
            'zapfdingbats|bold|italic': 'ZapfDingbats'
        };
        function fontAlias(alias, name) {
            alias = alias.toLowerCase();
            FONT_MAPPINGS[alias] = function () {
                return FONT_MAPPINGS[name];
            };
            FONT_MAPPINGS[alias + '|bold'] = function () {
                return FONT_MAPPINGS[name + '|bold'];
            };
            FONT_MAPPINGS[alias + '|italic'] = function () {
                return FONT_MAPPINGS[name + '|italic'];
            };
            FONT_MAPPINGS[alias + '|bold|italic'] = function () {
                return FONT_MAPPINGS[name + '|bold|italic'];
            };
        }
        fontAlias('Times New Roman', 'serif');
        fontAlias('Courier New', 'monospace');
        fontAlias('Arial', 'sans-serif');
        fontAlias('Helvetica', 'sans-serif');
        fontAlias('Verdana', 'sans-serif');
        fontAlias('Tahoma', 'sans-serif');
        fontAlias('Georgia', 'sans-serif');
        fontAlias('Monaco', 'monospace');
        fontAlias('Andale Mono', 'monospace');
        function defineFont(name, url) {
            if (arguments.length == 1) {
                for (var i in name) {
                    if (hasOwnProperty(name, i)) {
                        defineFont(i, name[i]);
                    }
                }
            } else {
                name = name.toLowerCase();
                FONT_MAPPINGS[name] = url;
                switch (name) {
                case 'dejavu sans':
                    FONT_MAPPINGS['sans-serif'] = url;
                    break;
                case 'dejavu sans|bold':
                    FONT_MAPPINGS['sans-serif|bold'] = url;
                    break;
                case 'dejavu sans|italic':
                    FONT_MAPPINGS['sans-serif|italic'] = url;
                    break;
                case 'dejavu sans|bold|italic':
                    FONT_MAPPINGS['sans-serif|bold|italic'] = url;
                    break;
                case 'dejavu serif':
                    FONT_MAPPINGS['serif'] = url;
                    break;
                case 'dejavu serif|bold':
                    FONT_MAPPINGS['serif|bold'] = url;
                    break;
                case 'dejavu serif|italic':
                    FONT_MAPPINGS['serif|italic'] = url;
                    break;
                case 'dejavu serif|bold|italic':
                    FONT_MAPPINGS['serif|bold|italic'] = url;
                    break;
                case 'dejavu mono':
                    FONT_MAPPINGS['monospace'] = url;
                    break;
                case 'dejavu mono|bold':
                    FONT_MAPPINGS['monospace|bold'] = url;
                    break;
                case 'dejavu mono|italic':
                    FONT_MAPPINGS['monospace|italic'] = url;
                    break;
                case 'dejavu mono|bold|italic':
                    FONT_MAPPINGS['monospace|bold|italic'] = url;
                    break;
                }
            }
        }
        function mmul(a, b) {
            var a1 = a[0], b1 = a[1], c1 = a[2], d1 = a[3], e1 = a[4], f1 = a[5];
            var a2 = b[0], b2 = b[1], c2 = b[2], d2 = b[3], e2 = b[4], f2 = b[5];
            return [
                a1 * a2 + b1 * c2,
                a1 * b2 + b1 * d2,
                c1 * a2 + d1 * c2,
                c1 * b2 + d1 * d2,
                e1 * a2 + f1 * c2 + e2,
                e1 * b2 + f1 * d2 + f2
            ];
        }
        function isIdentityMatrix(m) {
            return m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0;
        }
        var TEXT_RENDERING_MODE = {
            fill: 0,
            stroke: 1,
            fillAndStroke: 2,
            invisible: 3,
            fillAndClip: 4,
            strokeAndClip: 5,
            fillStrokeClip: 6,
            clip: 7
        };
        var TEXT_RENDERING_MODE$1 = TEXT_RENDERING_MODE;
        var DASH_PATTERNS = {
            dash: [4],
            dashDot: [
                4,
                2,
                1,
                2
            ],
            dot: [
                1,
                2
            ],
            longDash: [
                8,
                2
            ],
            longDashDot: [
                8,
                2,
                1,
                2
            ],
            longDashDotDot: [
                8,
                2,
                1,
                2,
                1,
                2
            ],
            solid: []
        };
        var LINE_CAP = {
            butt: 0,
            round: 1,
            square: 2
        };
        var LINE_JOIN = {
            miter: 0,
            round: 1,
            bevel: 2
        };
        function render(group, callback) {
            var fonts = [], images = {}, options = group.options;
            function getOption(name, defval, hash) {
                if (!hash) {
                    hash = options;
                }
                if (hash.pdf && hash.pdf[name] != null) {
                    return hash.pdf[name];
                }
                return defval;
            }
            var multiPage = getOption('multiPage');
            var imgDPI = getOption('imgDPI');
            if (imgDPI) {
                clearImageCache();
            }
            group.traverse(function (element) {
                dispatch({
                    Image: function (element) {
                        var url = element.src();
                        if (imgDPI) {
                            var box = element.bbox().size;
                            var prev = images[url];
                            box = {
                                width: Math.ceil(box.width * imgDPI / 72),
                                height: Math.ceil(box.height * imgDPI / 72)
                            };
                            if (prev) {
                                box.width = Math.max(prev.width, box.width);
                                box.height = Math.max(prev.height, box.height);
                            }
                            images[url] = box;
                        } else {
                            images[url] = null;
                        }
                    },
                    Text: function (element) {
                        var style = parseFontDef(element.options.font);
                        var url = getFontURL(style);
                        if (fonts.indexOf(url) < 0) {
                            fonts.push(url);
                        }
                    }
                }, element);
            });
            function doIt() {
                if (--count > 0) {
                    return;
                }
                var pdf = new PDFDocument({
                    producer: getOption('producer'),
                    title: getOption('title'),
                    author: getOption('author'),
                    subject: getOption('subject'),
                    keywords: getOption('keywords'),
                    creator: getOption('creator'),
                    date: getOption('date'),
                    autoPrint: getOption('autoPrint')
                });
                function drawPage(group) {
                    var options = group.options;
                    var tmp = optimize(group);
                    var bbox = tmp.bbox;
                    group = tmp.root;
                    var paperSize = getOption('paperSize', getOption('paperSize', 'auto'), options), addMargin = false;
                    if (paperSize == 'auto') {
                        if (bbox) {
                            var size = bbox.getSize();
                            paperSize = [
                                size.width,
                                size.height
                            ];
                            addMargin = true;
                            var origin = bbox.getOrigin();
                            tmp = new drawing.Group();
                            tmp.transform(new kendoGeometry.Matrix(1, 0, 0, 1, -origin.x, -origin.y));
                            tmp.append(group);
                            group = tmp;
                        } else {
                            paperSize = 'A4';
                        }
                    }
                    var page;
                    page = pdf.addPage({
                        paperSize: paperSize,
                        margin: getOption('margin', getOption('margin'), options),
                        addMargin: addMargin,
                        landscape: getOption('landscape', getOption('landscape', false), options)
                    });
                    drawElement(group, page, pdf);
                }
                if (multiPage) {
                    group.children.forEach(drawPage);
                } else {
                    drawPage(group);
                }
                callback(pdf.render(), pdf);
            }
            var count = 2;
            loadFonts(fonts, doIt);
            loadImages(images, doIt);
        }
        function toDataURL(group, callback) {
            render(group, function (data) {
                callback('data:application/pdf;base64,' + data.base64());
            });
        }
        function toBlob(group, callback) {
            render(group, function (data) {
                callback(new window.Blob([data.get()], { type: 'application/pdf' }));
            });
        }
        function saveAs$1(group, filename, proxy, callback) {
            if (window.Blob && !supportBrowser.safari) {
                toBlob(group, function (blob) {
                    kendo.saveAs({
                        dataURI: blob,
                        fileName: filename
                    });
                    if (callback) {
                        callback(blob);
                    }
                });
            } else {
                toDataURL(group, function (dataURL) {
                    kendo.saveAs({
                        dataURI: dataURL,
                        fileName: filename,
                        proxyURL: proxy
                    });
                    if (callback) {
                        callback(dataURL);
                    }
                });
            }
        }
        function dispatch(handlers, element) {
            var handler = handlers[element.nodeType];
            if (handler) {
                return handler.call.apply(handler, arguments);
            }
            return element;
        }
        function drawElement(element, page, pdf) {
            if (element.options._pdfDebug) {
                page.comment('BEGIN: ' + element.options._pdfDebug);
            }
            var transform = element.transform();
            var opacity = element.opacity();
            page.save();
            if (opacity != null && opacity < 1) {
                page.setOpacity(opacity);
            }
            setStrokeOptions(element, page, pdf);
            setFillOptions(element, page, pdf);
            if (transform) {
                var m = transform.matrix();
                page.transform(m.a, m.b, m.c, m.d, m.e, m.f);
            }
            setClipping(element, page, pdf);
            dispatch({
                Path: drawPath,
                MultiPath: drawMultiPath,
                Circle: drawCircle,
                Arc: drawArc,
                Text: drawText,
                Image: drawImage,
                Group: drawGroup,
                Rect: drawRect
            }, element, page, pdf);
            page.restore();
            if (element.options._pdfDebug) {
                page.comment('END: ' + element.options._pdfDebug);
            }
        }
        function setStrokeOptions(element, page) {
            var stroke = element.stroke && element.stroke();
            if (!stroke) {
                return;
            }
            var color = stroke.color;
            if (color) {
                color = parseColor$1(color);
                if (color == null) {
                    return;
                }
                page.setStrokeColor(color.r, color.g, color.b);
                if (color.a != 1) {
                    page.setStrokeOpacity(color.a);
                }
            }
            var width = stroke.width;
            if (width != null) {
                if (width === 0) {
                    return;
                }
                page.setLineWidth(width);
            }
            var dashType = stroke.dashType;
            if (dashType) {
                page.setDashPattern(DASH_PATTERNS[dashType], 0);
            }
            var lineCap = stroke.lineCap;
            if (lineCap) {
                page.setLineCap(LINE_CAP[lineCap]);
            }
            var lineJoin = stroke.lineJoin;
            if (lineJoin) {
                page.setLineJoin(LINE_JOIN[lineJoin]);
            }
            var opacity = stroke.opacity;
            if (opacity != null) {
                page.setStrokeOpacity(opacity);
            }
        }
        function setFillOptions(element, page) {
            var fill = element.fill && element.fill();
            if (!fill) {
                return;
            }
            if (fill instanceof drawing.Gradient) {
                return;
            }
            var color = fill.color;
            if (color) {
                color = parseColor$1(color);
                if (color == null) {
                    return;
                }
                page.setFillColor(color.r, color.g, color.b);
                if (color.a != 1) {
                    page.setFillOpacity(color.a);
                }
            }
            var opacity = fill.opacity;
            if (opacity != null) {
                page.setFillOpacity(opacity);
            }
        }
        function setClipping(element, page, pdf) {
            var clip = element.clip();
            if (clip) {
                _drawPath(clip, page, pdf);
                page.clip();
            }
        }
        function shouldDraw(thing) {
            return thing && (thing instanceof drawing.Gradient || thing.color && !/^(none|transparent)$/i.test(thing.color) && (thing.width == null || thing.width > 0) && (thing.opacity == null || thing.opacity > 0));
        }
        function maybeGradient(element, page, pdf, stroke) {
            var fill = element.fill();
            if (fill instanceof drawing.Gradient) {
                if (stroke) {
                    page.clipStroke();
                } else {
                    page.clip();
                }
                var isRadial = fill instanceof drawing.RadialGradient;
                var start, end;
                if (isRadial) {
                    start = {
                        x: fill.center().x,
                        y: fill.center().y,
                        r: 0
                    };
                    end = {
                        x: fill.center().x,
                        y: fill.center().y,
                        r: fill.radius()
                    };
                } else {
                    start = {
                        x: fill.start().x,
                        y: fill.start().y
                    };
                    end = {
                        x: fill.end().x,
                        y: fill.end().y
                    };
                }
                var stops = fill.stops.elements().map(function (stop) {
                    var offset = stop.offset();
                    if (/%$/.test(offset)) {
                        offset = parseFloat(offset) / 100;
                    } else {
                        offset = parseFloat(offset);
                    }
                    var color = parseColor$1(stop.color());
                    color.a *= stop.opacity();
                    return {
                        offset: offset,
                        color: color
                    };
                });
                stops.unshift(stops[0]);
                stops.push(stops[stops.length - 1]);
                var gradient = {
                    userSpace: fill.userSpace(),
                    type: isRadial ? 'radial' : 'linear',
                    start: start,
                    end: end,
                    stops: stops
                };
                var box = element.rawBBox();
                var tl = box.topLeft(), size = box.getSize();
                box = {
                    left: tl.x,
                    top: tl.y,
                    width: size.width,
                    height: size.height
                };
                page.gradient(gradient, box);
                return true;
            }
        }
        function maybeFillStroke(element, page, pdf) {
            if (shouldDraw(element.fill()) && shouldDraw(element.stroke())) {
                if (!maybeGradient(element, page, pdf, true)) {
                    page.fillStroke();
                }
            } else if (shouldDraw(element.fill())) {
                if (!maybeGradient(element, page, pdf, false)) {
                    page.fill();
                }
            } else if (shouldDraw(element.stroke())) {
                page.stroke();
            } else {
                page.nop();
            }
        }
        function maybeDrawRect(path, page) {
            var segments = path.segments;
            if (segments.length == 4 && path.options.closed) {
                var a = [];
                for (var i = 0; i < segments.length; ++i) {
                    if (segments[i].controlIn()) {
                        return false;
                    }
                    a[i] = segments[i].anchor();
                }
                var isRect = a[0].y == a[1].y && a[1].x == a[2].x && a[2].y == a[3].y && a[3].x == a[0].x || a[0].x == a[1].x && a[1].y == a[2].y && a[2].x == a[3].x && a[3].y == a[0].y;
                if (isRect) {
                    page.rect(a[0].x, a[0].y, a[2].x - a[0].x, a[2].y - a[0].y);
                    return true;
                }
            }
        }
        function _drawPath(element, page, pdf) {
            var segments = element.segments;
            if (segments.length === 0) {
                return;
            }
            if (!maybeDrawRect(element, page, pdf)) {
                for (var prev, i = 0; i < segments.length; ++i) {
                    var seg = segments[i];
                    var anchor = seg.anchor();
                    if (!prev) {
                        page.moveTo(anchor.x, anchor.y);
                    } else {
                        var prevOut = prev.controlOut();
                        var controlIn = seg.controlIn();
                        if (prevOut && controlIn) {
                            page.bezier(prevOut.x, prevOut.y, controlIn.x, controlIn.y, anchor.x, anchor.y);
                        } else {
                            page.lineTo(anchor.x, anchor.y);
                        }
                    }
                    prev = seg;
                }
                if (element.options.closed) {
                    page.close();
                }
            }
        }
        function drawPath(element, page, pdf) {
            _drawPath(element, page, pdf);
            maybeFillStroke(element, page, pdf);
        }
        function drawMultiPath(element, page, pdf) {
            var paths = element.paths;
            for (var i = 0; i < paths.length; ++i) {
                _drawPath(paths[i], page, pdf);
            }
            maybeFillStroke(element, page, pdf);
        }
        function drawCircle(element, page, pdf) {
            var g = element.geometry();
            page.circle(g.center.x, g.center.y, g.radius);
            maybeFillStroke(element, page, pdf);
        }
        function drawArc(element, page, pdf) {
            var points = element.geometry().curvePoints();
            page.moveTo(points[0].x, points[0].y);
            for (var i = 1; i < points.length;) {
                page.bezier(points[i].x, points[i++].y, points[i].x, points[i++].y, points[i].x, points[i++].y);
            }
            maybeFillStroke(element, page, pdf);
        }
        function drawText(element, page) {
            var style = parseFontDef(element.options.font);
            var pos = element._position;
            var mode;
            if (element.fill() && element.stroke()) {
                mode = TEXT_RENDERING_MODE$1.fillAndStroke;
            } else if (element.fill()) {
                mode = TEXT_RENDERING_MODE$1.fill;
            } else if (element.stroke()) {
                mode = TEXT_RENDERING_MODE$1.stroke;
            }
            page.transform(1, 0, 0, -1, pos.x, pos.y + style.fontSize);
            page.beginText();
            page.setFont(getFontURL(style), style.fontSize);
            page.setTextRenderingMode(mode);
            page.showText(element.content(), element._pdfRect ? element._pdfRect.width() : null);
            page.endText();
        }
        function drawGroup(element, page, pdf) {
            if (element._pdfLink) {
                page.addLink(element._pdfLink.url, element._pdfLink);
            }
            var children = element.children;
            for (var i = 0; i < children.length; ++i) {
                drawElement(children[i], page, pdf);
            }
        }
        function drawImage(element, page) {
            var url = element.src();
            if (!url) {
                return;
            }
            var rect = element.rect();
            var tl = rect.getOrigin();
            var sz = rect.getSize();
            page.transform(sz.width, 0, 0, -sz.height, tl.x, tl.y + sz.height);
            page.drawImage(url);
        }
        function drawRect(element, page, pdf) {
            var geometry = element.geometry();
            page.rect(geometry.origin.x, geometry.origin.y, geometry.size.width, geometry.size.height);
            maybeFillStroke(element, page, pdf);
        }
        function parseColor$1(value) {
            var color = kendo.parseColor(value, true);
            return color ? color.toRGB() : null;
        }
        function optimize(root) {
            var clipbox = false;
            var matrix = kendoGeometry.Matrix.unit();
            var currentBox = null;
            var changed;
            do {
                changed = false;
                root = opt(root);
            } while (root && changed);
            return {
                root: root,
                bbox: currentBox
            };
            function change(newShape) {
                changed = true;
                return newShape;
            }
            function visible(shape) {
                return shape.visible() && shape.opacity() > 0 && (shouldDraw(shape.fill()) || shouldDraw(shape.stroke()));
            }
            function optArray(a) {
                var b = [];
                for (var i = 0; i < a.length; ++i) {
                    var el = opt(a[i]);
                    if (el != null) {
                        b.push(el);
                    }
                }
                return b;
            }
            function withClipping(shape, f) {
                var saveclipbox = clipbox;
                var savematrix = matrix;
                if (shape.transform()) {
                    matrix = matrix.multiplyCopy(shape.transform().matrix());
                }
                var clip = shape.clip();
                if (clip) {
                    clip = clip.bbox();
                    if (clip) {
                        clip = clip.bbox(matrix);
                        clipbox = clipbox ? kendoGeometry.Rect.intersect(clipbox, clip) : clip;
                    }
                }
                try {
                    return f();
                } finally {
                    clipbox = saveclipbox;
                    matrix = savematrix;
                }
            }
            function inClipbox(shape) {
                if (clipbox == null) {
                    return false;
                }
                var box = shape.rawBBox().bbox(matrix);
                if (clipbox && box) {
                    box = kendoGeometry.Rect.intersect(box, clipbox);
                }
                return box;
            }
            function opt(shape) {
                return withClipping(shape, function () {
                    if (!(shape instanceof drawing.Group || shape instanceof drawing.MultiPath)) {
                        var box = inClipbox(shape);
                        if (!box) {
                            return change(null);
                        }
                        currentBox = currentBox ? kendoGeometry.Rect.union(currentBox, box) : box;
                    }
                    return dispatch({
                        Path: function (shape) {
                            if (shape.segments.length === 0 || !visible(shape)) {
                                return change(null);
                            }
                            return shape;
                        },
                        MultiPath: function (shape) {
                            if (!visible(shape)) {
                                return change(null);
                            }
                            var el = new drawing.MultiPath(shape.options);
                            el.paths = optArray(shape.paths);
                            if (el.paths.length === 0) {
                                return change(null);
                            }
                            return el;
                        },
                        Circle: function (shape) {
                            if (!visible(shape)) {
                                return change(null);
                            }
                            return shape;
                        },
                        Arc: function (shape) {
                            if (!visible(shape)) {
                                return change(null);
                            }
                            return shape;
                        },
                        Text: function (shape) {
                            if (!/\S/.test(shape.content()) || !visible(shape)) {
                                return change(null);
                            }
                            return shape;
                        },
                        Image: function (shape) {
                            if (!(shape.visible() && shape.opacity() > 0)) {
                                return change(null);
                            }
                            return shape;
                        },
                        Group: function (shape) {
                            var el = new drawing.Group(shape.options);
                            el.children = optArray(shape.children);
                            el._pdfLink = shape._pdfLink;
                            if (shape !== root && el.children.length === 0 && !shape._pdfLink) {
                                return change(null);
                            }
                            return el;
                        },
                        Rect: function (shape) {
                            if (!visible(shape)) {
                                return change(null);
                            }
                            return shape;
                        }
                    }, shape);
                });
            }
        }
        function exportPDF(group, options) {
            var promise = util.createPromise();
            for (var i in options) {
                if (i == 'margin' && group.options.pdf && group.options.pdf._ignoreMargin) {
                    continue;
                }
                group.options.set('pdf.' + i, options[i]);
            }
            toDataURL(group, promise.resolve);
            return promise;
        }
        function exportPDFToBlob(group, options) {
            var promise = util.createPromise();
            for (var i in options) {
                if (i == 'margin' && group.options.pdf && group.options.pdf._ignoreMargin) {
                    continue;
                }
                group.options.set('pdf.' + i, options[i]);
            }
            if (window.Blob && !supportBrowser.safari) {
                toBlob(group, promise.resolve);
            } else {
                toDataURL(group, promise.resolve);
            }
            return promise;
        }
        kendo.deepExtend(kendo.pdf, {
            Document: PDFDocument,
            BinaryStream: BinaryStream,
            defineFont: defineFont,
            parseFontDef: parseFontDef,
            getFontURL: getFontURL,
            loadFonts: loadFonts,
            loadImages: loadImages,
            getPaperOptions: getPaperOptions,
            clearImageCache: clearImageCache,
            TEXT_RENDERING_MODE: TEXT_RENDERING_MODE,
            exportPDF: exportPDF,
            exportPDFToBlob: exportPDFToBlob,
            saveAs: saveAs$1,
            toDataURL: toDataURL,
            toBlob: toBlob,
            render: render
        });
        kendo.drawing.exportPDF = kendo.pdf.exportPDF;
        kendo.drawing.pdf = kendo.pdf;
    }(kendo));
    return kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf/mixins', ['pdf/core'], f);
}(function () {
    (function ($, undefined) {
        kendo.PDFMixin = {
            extend: function (proto) {
                proto.events.push('pdfExport');
                proto.options.pdf = this.options;
                proto.saveAsPDF = this.saveAsPDF;
                proto._drawPDF = this._drawPDF;
                proto._drawPDFShadow = this._drawPDFShadow;
            },
            options: {
                fileName: 'Export.pdf',
                proxyURL: '',
                paperSize: 'auto',
                allPages: false,
                landscape: false,
                margin: null,
                title: null,
                author: null,
                subject: null,
                keywords: null,
                creator: 'Kendo UI PDF Generator v.' + kendo.version,
                date: null
            },
            saveAsPDF: function () {
                var progress = new $.Deferred();
                var promise = progress.promise();
                var args = { promise: promise };
                if (this.trigger('pdfExport', args)) {
                    return;
                }
                var options = this.options.pdf;
                options.multiPage = options.multiPage || options.allPages;
                this._drawPDF(progress).then(function (root) {
                    return kendo.drawing.exportPDF(root, options);
                }).done(function (dataURI) {
                    kendo.saveAs({
                        dataURI: dataURI,
                        fileName: options.fileName,
                        proxyURL: options.proxyURL,
                        forceProxy: options.forceProxy,
                        proxyTarget: options.proxyTarget
                    });
                    progress.resolve();
                }).fail(function (err) {
                    progress.reject(err);
                });
                return promise;
            },
            _drawPDF: function (progress) {
                var promise = new $.Deferred();
                kendo.drawing.drawDOM(this.wrapper).done(function (group) {
                    var args = {
                        page: group,
                        pageNumber: 1,
                        progress: 1,
                        totalPages: 1
                    };
                    progress.notify(args);
                    promise.resolve(args.page);
                }).fail(function (err) {
                    promise.reject(err);
                });
                return promise;
            },
            _drawPDFShadow: function (settings, drawOptions) {
                settings = settings || {};
                var wrapper = this.wrapper;
                var shadow = $('<div class=\'k-pdf-export-shadow\'>');
                if (settings.width) {
                    shadow.css({
                        width: settings.width,
                        overflow: 'visible'
                    });
                }
                wrapper.before(shadow);
                shadow.append(settings.content || wrapper.clone(true, true));
                var defer = $.Deferred();
                setTimeout(function () {
                    var promise = kendo.drawing.drawDOM(shadow, drawOptions);
                    promise.always(function () {
                        shadow.remove();
                    }).then(function () {
                        defer.resolve.apply(defer, arguments);
                    }).fail(function () {
                        defer.reject.apply(defer, arguments);
                    }).progress(function () {
                        defer.progress.apply(defer, arguments);
                    });
                }, 15);
                return defer.promise();
            }
        };
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pdf', [
        'kendo.core',
        'kendo.drawing',
        'pdf/core',
        'pdf/mixins'
    ], f);
}(function () {
    var __meta__ = {
        id: 'pdf',
        name: 'PDF export',
        description: 'PDF Generation framework',
        mixin: true,
        category: 'framework',
        depends: [
            'core',
            'drawing'
        ]
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.grid', [
        'kendo.data',
        'kendo.columnsorter',
        'kendo.editable',
        'kendo.window',
        'kendo.filtermenu',
        'kendo.columnmenu',
        'kendo.groupable',
        'kendo.pager',
        'kendo.selectable',
        'kendo.sortable',
        'kendo.reorderable',
        'kendo.resizable',
        'kendo.ooxml',
        'kendo.excel',
        'kendo.pane',
        'kendo.progressbar',
        'kendo.pdf'
    ], f);
}(function () {
    var __meta__ = {
        id: 'grid',
        name: 'Grid',
        category: 'web',
        description: 'The Grid widget displays tabular data and offers rich support for interacting with data,including paging, sorting, grouping, and selection.',
        depends: [
            'data',
            'columnsorter',
            'sortable'
        ],
        features: [
            {
                id: 'grid-editing',
                name: 'Editing',
                description: 'Support for record editing',
                depends: [
                    'editable',
                    'window'
                ]
            },
            {
                id: 'grid-filtering',
                name: 'Filtering',
                description: 'Support for record filtering',
                depends: ['filtermenu']
            },
            {
                id: 'grid-columnmenu',
                name: 'Column menu',
                description: 'Support for header column menu',
                depends: ['columnmenu']
            },
            {
                id: 'grid-grouping',
                name: 'Grouping',
                description: 'Support for grid grouping',
                depends: ['groupable']
            },
            {
                id: 'grid-filtercell',
                name: 'Row filter',
                description: 'Support for grid header filtering',
                depends: ['filtercell']
            },
            {
                id: 'grid-paging',
                name: 'Paging',
                description: 'Support for grid paging',
                depends: ['pager']
            },
            {
                id: 'grid-selection',
                name: 'Selection',
                description: 'Support for row selection',
                depends: ['selectable']
            },
            {
                id: 'grid-column-reorder',
                name: 'Column reordering',
                description: 'Support for column reordering',
                depends: ['reorderable']
            },
            {
                id: 'grid-column-resize',
                name: 'Column resizing',
                description: 'Support for column resizing',
                depends: ['resizable']
            },
            {
                id: 'grid-mobile',
                name: 'Grid adaptive rendering',
                description: 'Support for adaptive rendering',
                depends: [
                    'mobile.actionsheet',
                    'mobile.pane'
                ]
            },
            {
                id: 'grid-excel-export',
                name: 'Excel export',
                description: 'Export grid data as Excel spreadsheet',
                depends: ['excel']
            },
            {
                id: 'grid-pdf-export',
                name: 'PDF export',
                description: 'Export grid data as PDF',
                depends: [
                    'pdf',
                    'drawing',
                    'progressbar'
                ]
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, DataSource = kendo.data.DataSource, ObservableObject = kendo.data.ObservableObject, tbodySupportsInnerHtml = kendo.support.tbodyInnerHtml, activeElement = kendo._activeElement, Widget = ui.Widget, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, keys = kendo.keys, isPlainObject = $.isPlainObject, extend = $.extend, map = $.map, grep = $.grep, isArray = $.isArray, inArray = $.inArray, push = Array.prototype.push, proxy = $.proxy, isFunction = kendo.isFunction, isEmptyObject = $.isEmptyObject, contains = $.contains, math = Math, DOT = '.', PROGRESS = 'progress', ERROR = 'error', HIERARCHY_CELL_CLASS = 'k-hierarchy-cell', DATA_CELL = ':not(.k-group-cell):not(.k-hierarchy-cell:not(:has(.k-icon.k-i-collapse,.k-icon.k-i-expand))):visible', SELECTION_CELL_SELECTOR = 'tbody>tr:not(.k-grouping-row):not(.k-detail-row):not(.k-group-footer) > td:not(.k-group-cell):not(.k-hierarchy-cell)', NAVROW = 'tr:not(.k-footer-template):visible', NAVCELL = ':not(.k-group-cell):not(.k-detail-cell):not(.k-hierarchy-cell):visible', ITEMROW = 'tr:not(.k-grouping-row):not(.k-detail-row):not(.k-footer-template):not(.k-group-footer):visible', FIRSTITEMROW = ITEMROW + ':first', LASTITEMROW = ITEMROW + ':last', FIRSTNAVITEM = NAVROW + ':first>' + NAVCELL + ':first', HEADERCELLS = 'th.k-header:not(.k-group-cell):not(.k-hierarchy-cell)', NS = '.kendoGrid', CONTENTRLOCKEDCONTAINER = 'k-grid-content-locked', GROUPCELLCLASS = 'k-group-cell', EDIT = 'edit', BEFOREEDIT = 'beforeEdit', SAVE = 'save', REMOVE = 'remove', DETAILINIT = 'detailInit', FILTERMENUINIT = 'filterMenuInit', COLUMNMENUINIT = 'columnMenuInit', FILTERMENUOPEN = 'filterMenuOpen', COLUMNMENUOPEN = 'columnMenuOpen', CELLCLOSE = 'cellClose', CHANGE = 'change', COLUMNHIDE = 'columnHide', COLUMNSHOW = 'columnShow', SAVECHANGES = 'saveChanges', DATABOUND = 'dataBound', DETAILEXPAND = 'detailExpand', DETAILCOLLAPSE = 'detailCollapse', ITEM_CHANGE = 'itemchange', PAGE = 'page', PAGING = 'paging', SCROLL = 'scroll', SYNC = 'sync', FOCUSED = 'k-state-focused', FOCUSABLE = ':kendoFocusable', SELECTED = 'k-state-selected', CHECKBOX = 'k-checkbox', CHECKBOXINPUT = 'input[data-role=\'checkbox\'].' + CHECKBOX, NORECORDSCLASS = 'k-grid-norecords', LINK_CLASS = 'k-link', ICON_CLASS = 'k-icon', ORDER_CLASS = 'k-sort-order', HEADER_COLUMN_MENU_CLASS = 'k-header-column-menu', FILTER_MENU_CLASS = 'k-grid-filter', RESIZE = 'resize', COLUMNRESIZE = 'columnResize', COLUMNREORDER = 'columnReorder', COLUMNLOCK = 'columnLock', COLUMNUNLOCK = 'columnUnlock', NAVIGATE = 'navigate', CLICK = 'click', MOUSEDOWN = 'mousedown', HEIGHT = 'height', TABINDEX = 'tabIndex', FUNCTION = 'function', STRING = 'string', BOTTOM = 'bottom', CONTAINER_FOR = 'container-for', FIELD = 'field', INPUT = 'input', INCELL = 'incell', INLINE = 'inline', UNIQUE_ID = 'uid', MINCOLSPANVALUE = 1, COLSPAN = 'colSpan', OVERFLOW = 'overflow', HIDDEN = 'hidden', GROUP_SORT = 'group-sort', DELETECONFIRM = 'Are you sure you want to delete this record?', NORECORDS = 'No records available.', CONFIRMDELETE = 'Delete', CANCELDELETE = 'Cancel', COLLAPSE = 'Collapse', EXPAND = 'Expand', ARIALABEL = 'aria-label', formatRegExp = /(\}|\#)/gi, templateHashRegExp = /#/gi, whitespaceRegExp = '[\\x20\\t\\r\\n\\f]', nonDataCellsRegExp = new RegExp('(^|' + whitespaceRegExp + ')' + '(k-group-cell|k-hierarchy-cell)' + '(' + whitespaceRegExp + '|$)'), filterRowRegExp = new RegExp('(^|' + whitespaceRegExp + ')' + '(k-filter-row)' + '(' + whitespaceRegExp + '|$)'), COMMANDBUTTONTMPL = '# if (iconClass) {#' + '<a role="button" class="k-button k-button-icontext #=className#" #=attr# href="\\#"><span class="#=iconClass#"></span>#=text#</a>' + '# } else { #' + '<a role="button" class="k-button k-button-icontext #=className#" #=attr# href="\\#">#=text#</a>' + '# } #', SELECTCOLUMNTMPL = '# var checkboxGuid = kendo.guid(); #' + '<input class="' + CHECKBOX + '" data-role="checkbox" id="#= checkboxGuid #" aria-label="Select row" aria-checked="false" type="checkbox">' + '<label for="#= checkboxGuid #" class="k-checkbox-label k-no-text">&\\#8203;</label>', SELECTCOLUMNHEADERTMPL = '# var checkboxGuid = kendo.guid(); #' + '<input class="' + CHECKBOX + '" data-role="checkbox" aria-label="Select all rows" aria-checked="false" type="checkbox" id="#= checkboxGuid #">' + '<label for="#= checkboxGuid #" class="k-checkbox-label k-no-text">##&\\#8203;##</label>', isRtl = false, browser = kendo.support.browser, isIE7 = browser.msie && browser.version == 7, isIE8 = browser.msie && browser.version == 8;
        var isIE11 = browser.msie && browser.version === 11;
        var isMac = /Mac OS/.test(navigator.userAgent);
        var classNames = {
            content: 'k-content',
            widget: 'k-widget',
            scrollContainer: 'k-scroll-container'
        };
        var VirtualScrollable = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that._refreshHandler = proxy(that.refresh, that);
                that.setDataSource(options.dataSource);
                that.wrap();
            },
            setDataSource: function (dataSource) {
                var that = this;
                if (that.dataSource) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                }
                that.dataSource = dataSource;
                that.dataSource.bind(CHANGE, that._refreshHandler);
                that.dataSource.options.useRanges = true;
            },
            options: {
                name: 'VirtualScrollable',
                itemHeight: $.noop,
                prefetch: true,
                maxScrollHeight: 250000
            },
            events: [
                PAGING,
                PAGE,
                SCROLL
            ],
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.dataSource.unbind(CHANGE, that._refreshHandler);
                that.wrapper.add(that.verticalScrollbar).off(NS);
                clearTimeout(that._timeout);
                if (that._scrollingTimeout) {
                    clearTimeout(that._scrollingTimeout);
                }
                if (that.drag) {
                    that.drag.destroy();
                    that.drag = null;
                }
                that.wrapper = that.element = that.verticalScrollbar = null;
                that._refreshHandler = null;
            },
            wrap: function () {
                var that = this, scrollbar = kendo.support.scrollbar() + 1, element = that.element, wrapper;
                element.css({
                    width: 'auto',
                    overflow: 'hidden'
                }).css(isRtl ? 'padding-left' : 'padding-right', scrollbar);
                that.content = element.children().first();
                wrapper = that.wrapper = that.content.wrap('<div class="k-virtual-scrollable-wrap"/>').parent().bind('DOMMouseScroll' + NS + ' mousewheel' + NS, proxy(that._wheelScroll, that));
                that._wrapper();
                if (kendo.support.kineticScrollNeeded) {
                    that.drag = new kendo.UserEvents(that.wrapper, {
                        global: true,
                        allowSelection: true,
                        start: function (e) {
                            e.sender.capture();
                        },
                        move: function (e) {
                            that.verticalScrollbar.scrollTop(that.verticalScrollbar.scrollTop() - e.y.delta);
                            wrapper.scrollLeft(wrapper.scrollLeft() - e.x.delta);
                            e.preventDefault();
                        }
                    });
                }
                that.verticalScrollbar = $('<div class="k-scrollbar k-scrollbar-vertical" />').css({ width: scrollbar }).appendTo(element).bind('scroll' + NS, proxy(that._scroll, that));
            },
            _wrapper: function () {
                var that = this;
                if (isIE11) {
                    that.wrapper.css({ 'overflow-y': SCROLL });
                    that.element.css(isRtl ? 'padding-left' : 'padding-right', 0);
                }
            },
            _wheelScroll: function (e) {
                if (e.ctrlKey) {
                    return;
                }
                var scrollbar = this.verticalScrollbar, scrollTop = scrollbar.scrollTop(), delta = kendo.wheelDeltaY(e);
                if (delta && !(delta > 0 && scrollTop === 0) && !(delta < 0 && scrollTop + scrollbar[0].clientHeight == scrollbar[0].scrollHeight)) {
                    e.preventDefault();
                    this.verticalScrollbar.scrollTop(scrollTop + -delta);
                }
            },
            _scroll: function (e) {
                var that = this, delayLoading = !that.options.prefetch, scrollTop = e.currentTarget.scrollTop, dataSource = that.dataSource, rowHeight = that.itemHeight, skip = dataSource.skip() || 0, start = that._rangeStart || skip, height = that.element.innerHeight(), isScrollingUp = !!(that._scrollbarTop && that._scrollbarTop > scrollTop), firstItemIndex = math.max(math.floor(scrollTop / rowHeight), 0), lastItemOffset = isScrollingUp ? math.ceil(height / rowHeight) : math.floor(height / rowHeight), lastItemIndex = math.max(firstItemIndex + lastItemOffset, 0);
                if (that._preventScroll) {
                    that._preventScroll = false;
                    return;
                }
                that._scrollTop = scrollTop - start * rowHeight;
                that._scrollbarTop = scrollTop;
                that._scrolling = delayLoading;
                if (!that._fetch(firstItemIndex, lastItemIndex, isScrollingUp)) {
                    that.wrapper[0].scrollTop = that._scrollTop;
                }
                that.trigger(SCROLL);
                if (delayLoading) {
                    if (that._scrollingTimeout) {
                        clearTimeout(that._scrollingTimeout);
                    }
                    that._scrollingTimeout = setTimeout(function () {
                        that._scrolling = false;
                        that._page(that._rangeStart, that.dataSource.take());
                    }, 100);
                }
            },
            scrollToTop: function () {
                this._scrollTo(0);
            },
            scrollToBottom: function () {
                var scrollbar = this.verticalScrollbar;
                this._scrollTo(scrollbar[0].scrollHeight - scrollbar.height());
            },
            _scrollWrapperToTop: function () {
                this.wrapper.scrollTop(0);
            },
            _scrollWrapperToBottom: function () {
                this.wrapper.scrollTop(this.wrapper[0].scrollHeight);
            },
            _scrollWrapperOnColumnResize: function () {
                var that = this;
                var wrapper = this.wrapper;
                var initialScrollTop = wrapper.scrollTop();
                if (wrapper[0].scrollWidth > wrapper[0].clientWidth) {
                    if (!that._wrapperScrolled && initialScrollTop || that._isScrolledToBottom()) {
                        wrapper.scrollTop(initialScrollTop + kendo.support.scrollbar());
                        that._scrollTop = wrapper.scrollTop();
                        that._wrapperScrolled = true;
                    }
                } else if (that._wrapperScrolled) {
                    if (!that._isWrapperScrolledToBottom()) {
                        wrapper.scrollTop(initialScrollTop - kendo.support.scrollbar());
                        that._scrollTop = wrapper.scrollTop();
                    }
                    that._wrapperScrolled = false;
                }
            },
            _scrollTo: function (scrollTop) {
                var that = this;
                var scrollbar = that.verticalScrollbar;
                if (scrollbar.scrollTop() !== scrollTop) {
                    that._preventScroll = true;
                }
                that.wrapper.scrollTop(scrollTop);
                that._scrollTop = that.wrapper.scrollTop();
                scrollbar.scrollTop(scrollTop);
                that._scrollbarTop = scrollbar.scrollTop();
            },
            _isScrolledToTop: function () {
                return this.verticalScrollbar.scrollTop() === 0;
            },
            _isScrolledToBottom: function () {
                var scrollbar = this.verticalScrollbar;
                var scrollTop = scrollbar.scrollTop();
                return scrollTop > 0 && scrollTop >= parseInt(scrollbar[0].scrollHeight - scrollbar.height(), 10);
            },
            _isWrapperScrolledToBottom: function () {
                var wrapper = this.wrapper;
                return wrapper.scrollTop() >= parseInt(wrapper[0].scrollHeight - wrapper.height(), 10);
            },
            itemIndex: function (rowIndex) {
                var rangeStart = this._rangeStart || this.dataSource.skip() || 0;
                return rangeStart + rowIndex;
            },
            _isElementVisible: function (element) {
                return this._isElementVisibleInWrapper(element);
            },
            _isElementVisibleInWrapper: function (element) {
                var that = this;
                var wrapper = that.wrapper;
                var offsetTop;
                var halfHeight;
                element = $(element);
                if (element[0] && contains(wrapper[0], element[0])) {
                    offsetTop = element.offset().top - wrapper.offset().top;
                    halfHeight = element.outerHeight() / 2;
                    if ((offsetTop >= 0 || math.abs(offsetTop) <= halfHeight) && math.floor(offsetTop + halfHeight) <= wrapper.height()) {
                        return true;
                    }
                }
                return false;
            },
            position: function (index) {
                var rangeStart = this._rangeStart || this.dataSource.skip() || 0;
                var pageSize = this.dataSource.pageSize();
                var result;
                if (index > rangeStart) {
                    result = index - rangeStart + 1;
                } else {
                    result = rangeStart - index - 1;
                }
                return result > pageSize ? pageSize : result;
            },
            scrollIntoView: function (row) {
                var container = this.wrapper[0];
                var containerHeight = container.clientHeight;
                var containerScroll = !this._isScrolledToBottom() ? this._scrollTop || container.scrollTop : container.scrollTop;
                var elementOffset = row[0].offsetTop;
                var elementHeight = row[0].offsetHeight;
                if (containerScroll > elementOffset) {
                    this.verticalScrollbar[0].scrollTop -= containerHeight / 2;
                } else if (elementOffset + elementHeight >= containerScroll + containerHeight) {
                    this.verticalScrollbar[0].scrollTop += containerHeight / 2;
                }
            },
            _fetch: function (firstItemIndex, lastItemIndex, scrollingUp) {
                var that = this, dataSource = that.dataSource, itemHeight = that.itemHeight, take = dataSource.take(), rangeStart = that._rangeStart || dataSource.skip() || 0, currentSkip = math.floor(firstItemIndex / take) * take, fetching = false, prefetchAt = 0.33;
                var scrollbar = that.verticalScrollbar;
                var webkitCorrection = browser.webkit ? 1 : 0;
                if (firstItemIndex < rangeStart) {
                    fetching = true;
                    rangeStart = math.max(0, lastItemIndex - take);
                    that._scrollTop = scrollbar.scrollTop() - rangeStart * itemHeight;
                    that._page(rangeStart, take);
                } else if (lastItemIndex >= rangeStart + take && !scrollingUp) {
                    fetching = true;
                    rangeStart = math.min(firstItemIndex, dataSource.total() - take);
                    if (scrollbar.scrollTop() >= scrollbar[0].scrollHeight - scrollbar[0].offsetHeight - webkitCorrection) {
                        that._scrollTop = that.wrapper[0].scrollHeight - that.wrapper[0].offsetHeight;
                    } else {
                        that._scrollTop = itemHeight;
                    }
                    that._page(rangeStart, take);
                } else if (!that._fetching && that.options.prefetch) {
                    if (firstItemIndex < currentSkip + take - take * prefetchAt && firstItemIndex > take) {
                        dataSource.prefetch(currentSkip - take, take, $.noop);
                    }
                    if (lastItemIndex > currentSkip + take * prefetchAt) {
                        dataSource.prefetch(currentSkip + take, take, $.noop);
                    }
                }
                return fetching;
            },
            fetching: function () {
                return this._fetching;
            },
            _page: function (skip, take, callback) {
                var that = this, delayLoading = !that.options.prefetch, dataSource = that.dataSource;
                callback = isFunction(callback) ? callback : $.noop;
                if (that.trigger(PAGING, {
                        skip: skip,
                        take: take
                    })) {
                    return;
                }
                clearTimeout(that._timeout);
                that._fetching = true;
                that._rangeStart = skip;
                if (dataSource.inRange(skip, take)) {
                    kendo.ui.progress($(that.wrapper).parent(), true);
                    dataSource.range(skip, take, function () {
                        kendo.ui.progress($(that.wrapper).parent(), false);
                        callback();
                        that.trigger(PAGE);
                    });
                } else {
                    if (!delayLoading) {
                        kendo.ui.progress(that.wrapper.parent(), true);
                    }
                    that._timeout = setTimeout(function () {
                        if (!that._scrolling) {
                            if (delayLoading) {
                                kendo.ui.progress(that.wrapper.parent(), true);
                            }
                            dataSource.range(skip, take, function () {
                                kendo.ui.progress(that.wrapper.parent(), false);
                                callback();
                                that.trigger(PAGE);
                            });
                        }
                    }, 100);
                }
            },
            repaintScrollbar: function (shouldScrollWrapper) {
                var that = this, html = '', maxHeight = that.options.maxScrollHeight, dataSource = that.dataSource, scrollbar = !kendo.support.kineticScrollNeeded ? kendo.support.scrollbar() : 0, wrapperElement = that.wrapper[0], totalHeight, idx, itemHeight;
                var wasScrolledToBottom = that._isScrolledToBottom();
                itemHeight = that.itemHeight = that.options.itemHeight() || 0;
                var addScrollBarHeight = wrapperElement.scrollWidth > wrapperElement.offsetWidth ? scrollbar : 0;
                totalHeight = dataSource.total() * itemHeight + addScrollBarHeight;
                for (idx = 0; idx < math.floor(totalHeight / maxHeight); idx++) {
                    html += '<div style="width:1px;height:' + maxHeight + 'px"></div>';
                }
                if (totalHeight % maxHeight) {
                    html += '<div style="width:1px;height:' + totalHeight % maxHeight + 'px"></div>';
                }
                that.verticalScrollbar.html(html);
                if (wasScrolledToBottom && !that._isScrolledToBottom()) {
                    that.scrollToBottom();
                }
                if (typeof that._scrollTop !== 'undefined' && !!shouldScrollWrapper) {
                    wrapperElement.scrollTop = that._scrollTop;
                    that._scrollWrapperOnColumnResize();
                }
            },
            refresh: function (e) {
                var that = this, dataSource = that.dataSource, rangeStart = that._rangeStart;
                var action = (e || {}).action;
                var shouldScrollWrapper = that._isScrolledToBottom() || !action || action !== ITEM_CHANGE && action !== REMOVE && action !== SYNC;
                kendo.ui.progress(that.wrapper.parent(), false);
                clearTimeout(that._timeout);
                that.repaintScrollbar(shouldScrollWrapper);
                if (that.drag) {
                    that.drag.cancel();
                }
                if (typeof rangeStart !== 'undefined' && !that._fetching) {
                    if (!action || action !== SYNC && action !== ITEM_CHANGE) {
                        that._rangeStart = dataSource.skip();
                    }
                    if (dataSource.page() === 1 && (!action || action !== SYNC && action !== ITEM_CHANGE)) {
                        that.verticalScrollbar[0].scrollTop = 0;
                    }
                }
                that._fetching = false;
            }
        });
        function attrEquals(attrName, attrValue) {
            return '[' + kendo.attr(attrName) + '=' + attrValue + ']';
        }
        function groupCells(count) {
            return new Array(count + 1).join('<td class="k-group-cell">&nbsp;</td>');
        }
        function stringifyAttributes(attributes) {
            var attr, result = ' ';
            if (attributes) {
                if (typeof attributes === STRING) {
                    return attributes;
                }
                for (attr in attributes) {
                    if (attributes[attr] !== '') {
                        result += attr + '="' + attributes[attr] + '"';
                    }
                }
            }
            return result;
        }
        var defaultCommands = {
            create: {
                text: 'Add new record',
                className: 'k-grid-add',
                iconClass: 'k-icon k-i-plus'
            },
            cancel: {
                text: 'Cancel changes',
                className: 'k-grid-cancel-changes',
                iconClass: 'k-icon k-i-cancel'
            },
            save: {
                text: 'Save changes',
                className: 'k-grid-save-changes',
                iconClass: 'k-icon k-i-check'
            },
            destroy: {
                text: 'Delete',
                className: 'k-grid-delete',
                iconClass: 'k-icon k-i-close'
            },
            edit: {
                text: 'Edit',
                className: 'k-grid-edit',
                iconClass: 'k-icon k-i-edit'
            },
            update: {
                text: 'Update',
                className: 'k-primary k-grid-update',
                iconClass: 'k-icon k-i-check'
            },
            canceledit: {
                text: 'Cancel',
                className: 'k-grid-cancel',
                iconClass: 'k-icon k-i-cancel'
            },
            excel: {
                text: 'Export to Excel',
                className: 'k-grid-excel',
                iconClass: 'k-icon k-i-file-excel'
            },
            pdf: {
                text: 'Export to PDF',
                className: 'k-grid-pdf',
                iconClass: 'k-icon k-i-file-pdf'
            }
        };
        function cursor(context, value) {
            $('th, th .k-grid-filter, th .k-link', context).add(document.body).css('cursor', value);
        }
        function reorder(selector, source, dest, before, count) {
            var sourceIndex = source;
            source = $();
            count = count || 1;
            for (var idx = 0; idx < count; idx++) {
                source = source.add(selector.eq(sourceIndex + idx));
            }
            if (typeof dest == 'number') {
                source[before ? 'insertBefore' : 'insertAfter'](selector.eq(dest));
            } else {
                source.appendTo(dest);
            }
        }
        function elements(lockedContent, content, filter) {
            return $(lockedContent).add(content).find(filter);
        }
        function attachCustomCommandEvent(context, container, commands) {
            var idx, length, command, commandName;
            commands = !isArray(commands) ? [commands] : commands;
            for (idx = 0, length = commands.length; idx < length; idx++) {
                command = commands[idx];
                if (isPlainObject(command) && command.click) {
                    commandName = command.name || command.text;
                    container.on(CLICK + NS, 'a.k-grid-' + (commandName || '').replace(/\s/g, ''), { commandName: commandName }, proxy(command.click, context));
                }
            }
        }
        function normalizeColumns(columns, encoded, hide) {
            return map(columns, function (column) {
                column = typeof column === STRING ? { field: column } : column;
                var hidden;
                if (!isVisible(column) || hide) {
                    column.attributes = addHiddenStyle(column.attributes);
                    column.footerAttributes = addHiddenStyle(column.footerAttributes);
                    column.headerAttributes = addHiddenStyle(column.headerAttributes);
                    hidden = true;
                }
                if (column.columns) {
                    column.columns = normalizeColumns(column.columns, encoded, hidden);
                }
                var uid = kendo.guid();
                column.headerAttributes = extend({ id: uid }, column.headerAttributes);
                return extend({
                    encoded: encoded,
                    hidden: hidden
                }, column);
            });
        }
        function columnParent(column, columns) {
            var parents = [];
            columnParents(column, columns, parents);
            return parents[parents.length - 1];
        }
        function columnParents(column, columns, parents) {
            parents = parents || [];
            for (var idx = 0; idx < columns.length; idx++) {
                if (column === columns[idx]) {
                    return true;
                } else if (columns[idx].columns) {
                    var inserted = parents.length;
                    parents.push(columns[idx]);
                    if (!columnParents(column, columns[idx].columns, parents)) {
                        parents.splice(inserted, parents.length - inserted);
                    } else {
                        return true;
                    }
                }
            }
            return false;
        }
        function setColumnVisibility(column, visible) {
            setVisibility(column, visible, visible);
        }
        function setVisibility(column, visible, show) {
            var method = show ? removeHiddenStyle : addHiddenStyle;
            column.hidden = !visible;
            column.attributes = method(column.attributes);
            column.footerAttributes = method(column.footerAttributes);
            column.headerAttributes = method(column.headerAttributes);
        }
        function setColumnMediaVisibility(column, visible) {
            setColumnMatchesMedia(column);
            var hideByMedia = column._hideByMedia;
            setVisibility(column, visible, hideByMedia ? column.matchesMedia : visible);
        }
        function setColumnMatchesMedia(column) {
            column.matchesMedia = columnMatchesMedia(column);
        }
        function columnMatchesMedia(column) {
            return column && (isUndefined(column.media) || !isUndefined(column.media) && kendo.matchesMedia(column.media));
        }
        function isCellVisible() {
            return this.style.display !== 'none';
        }
        function isElementVisible(element) {
            return $(element)[0].style.display !== 'none';
        }
        function isVisible(column) {
            return visibleColumns([column]).length > 0;
        }
        function visibleColumns(columns) {
            return grep(columns, function (column) {
                var result = !column.hidden && column.matchesMedia !== false;
                if (result && column.columns) {
                    result = visibleColumns(column.columns).length > 0;
                }
                return result;
            });
        }
        function columnsWithMedia(columns) {
            var result = [];
            var column;
            for (var i = 0; i < columns.length; i++) {
                column = columns[i];
                if (!isUndefined(column.media)) {
                    if (!isUndefined(column.minScreenWidth)) {
                        throw new Error('Using \'media\' and \'minScreenWidth\' options at the same time is not supported.');
                    }
                    result.push(column);
                }
                if (column.columns) {
                    result = result.concat(columnsWithMedia(column.columns));
                }
            }
            return result;
        }
        function isUndefined(value) {
            return typeof value === 'undefined';
        }
        function toJQuery(elements) {
            return $(elements).map(function () {
                return this.toArray();
            });
        }
        function updateCellRowSpan(cell, columns, sourceLockedColumnsCount) {
            var lockedColumnDepth = depth(lockedColumns(columns));
            var nonLockedColumnDepth = depth(nonLockedColumns(columns));
            var rowSpan = cell.rowSpan;
            if (sourceLockedColumnsCount) {
                if (lockedColumnDepth > nonLockedColumnDepth) {
                    cell.rowSpan = rowSpan - (lockedColumnDepth - nonLockedColumnDepth) || 1;
                } else {
                    cell.rowSpan = rowSpan + (nonLockedColumnDepth - lockedColumnDepth);
                }
            } else {
                if (lockedColumnDepth > nonLockedColumnDepth) {
                    cell.rowSpan = rowSpan + (lockedColumnDepth - nonLockedColumnDepth);
                } else {
                    cell.rowSpan = rowSpan - (nonLockedColumnDepth - lockedColumnDepth) || 1;
                }
            }
        }
        function moveCellsBetweenContainers(sources, target, leafs, columns, container, destination, groups, action) {
            var sourcesDepth = depth(sources);
            var targetDepth = depth([target]);
            if (sourcesDepth > targetDepth) {
                var groupCells = new Array(groups + 1).join('<th class="k-group-cell k-header" scope="col">&nbsp;</th>');
                var rows = destination.children(':not(.k-filter-row)');
                $(new Array(sourcesDepth - targetDepth + 1).join('<tr>' + groupCells + '</tr>')).insertAfter(rows.last());
            }
            addRowSpanValue(destination, sourcesDepth - targetDepth);
            moveCells(leafs, columns, container, destination, action);
        }
        function updateCellIndex(thead, columns, offset) {
            offset = offset || 0;
            var position;
            var cell;
            var allColumns = columns;
            columns = leafColumns(columns);
            var cells = {};
            var rows = thead.find('>tr:not(.k-filter-row)');
            var filter = function () {
                var el = $(this);
                return !el.hasClass('k-group-cell') && !el.hasClass('k-hierarchy-cell');
            };
            for (var idx = 0, length = columns.length; idx < length; idx++) {
                position = columnPosition(columns[idx], allColumns);
                if (!cells[position.row]) {
                    cells[position.row] = rows.eq(position.row).find('.k-header').filter(filter);
                }
                cell = cells[position.row].eq(position.cell);
                cell.attr(kendo.attr('index'), offset + idx);
            }
            return columns.length;
        }
        function depth(columns) {
            var result = 1;
            var max = 0;
            for (var idx = 0; idx < columns.length; idx++) {
                if (columns[idx].columns) {
                    var temp = depth(columns[idx].columns);
                    if (temp > max) {
                        max = temp;
                    }
                }
            }
            return result + max;
        }
        function moveCells(leafs, columns, container, destination, action) {
            var sourcePosition = columnVisiblePosition(leafs[0], columns);
            var ths = container.find('>tr:not(.k-filter-row):eq(' + sourcePosition.row + ')>th.k-header');
            var t = $();
            var sourceIndex = sourcePosition.cell;
            var idx;
            for (idx = 0; idx < leafs.length; idx++) {
                t = t.add(ths.eq(sourceIndex + idx));
            }
            destination.find('>tr:not(.k-filter-row)').eq(sourcePosition.row)[action](t);
            var children = [];
            for (idx = 0; idx < leafs.length; idx++) {
                if (leafs[idx].columns) {
                    children = children.concat(leafs[idx].columns);
                }
            }
            if (children.length) {
                moveCells(children, columns, container, destination, action);
            }
        }
        function columnPosition(column, columns, row, cellCounts) {
            var result;
            var idx;
            row = row || 0;
            cellCounts = cellCounts || {};
            cellCounts[row] = cellCounts[row] || 0;
            for (idx = 0; idx < columns.length; idx++) {
                if (columns[idx] == column) {
                    result = {
                        cell: cellCounts[row],
                        row: row
                    };
                    break;
                } else if (columns[idx].columns) {
                    result = columnPosition(column, columns[idx].columns, row + 1, cellCounts);
                    if (result) {
                        break;
                    }
                }
                cellCounts[row]++;
            }
            return result;
        }
        function findParentColumnWithChildren(columns, index, source, rtl) {
            var target;
            var locked = !!source.locked;
            var targetLocked;
            do {
                target = columns[index];
                index += rtl ? 1 : -1;
                targetLocked = !!target.locked;
            } while (target && index > -1 && index < columns.length && target != source && !target.columns && targetLocked === locked);
            return target;
        }
        function findReorderTarget(columns, target, source, before, masterColumns) {
            if (target.columns) {
                target = target.columns;
                return target[before ? 0 : target.length - 1];
            } else {
                var parent = columnParent(target, columns);
                var parentColumns;
                if (parent) {
                    parentColumns = parent.columns;
                } else {
                    parentColumns = columns;
                }
                var index = inArray(target, parentColumns);
                if (index === 0 && before) {
                    index++;
                } else if (index == parentColumns.length - 1 && !before || !source.locked && !target.columns && !before) {
                    index--;
                } else if (index > 0 || index === 0 && !before) {
                    index++;
                }
                var sourceIndex = inArray(source, parentColumns);
                target = findParentColumnWithChildren(parentColumns, index, source, sourceIndex > index);
                var targetIndex = inArray(target, masterColumns);
                if (target.columns && (!targetIndex || targetIndex === parentColumns.length - 1)) {
                    return null;
                }
                if (target && target != source && target.columns) {
                    return findReorderTarget(columns, target, source, before, masterColumns);
                }
            }
            return null;
        }
        function columnVisiblePosition(column, columns, row, cellCounts) {
            var result;
            var idx;
            row = row || 0;
            cellCounts = cellCounts || {};
            cellCounts[row] = cellCounts[row] || 0;
            for (idx = 0; idx < columns.length; idx++) {
                if (columns[idx] == column) {
                    result = {
                        cell: cellCounts[row],
                        row: row
                    };
                    break;
                } else if (columns[idx].columns) {
                    result = columnVisiblePosition(column, columns[idx].columns, row + 1, cellCounts);
                    if (result) {
                        break;
                    }
                }
                if (!columns[idx].hidden) {
                    cellCounts[row]++;
                }
            }
            return result;
        }
        function flatColumnsInDomOrder(columns) {
            var result = flatColumns(lockedColumns(columns));
            return result.concat(flatColumns(nonLockedColumns(columns)));
        }
        function targetParentContainerIndex(flatColumns, columns, sourceIndex, targetIndex) {
            var column = flatColumns[sourceIndex];
            var target = flatColumns[targetIndex];
            var parent = columnParent(column, columns);
            columns = parent ? parent.columns : columns;
            return inArray(target, columns);
        }
        function flatColumns(columns) {
            var result = [];
            var children = [];
            for (var idx = 0; idx < columns.length; idx++) {
                result.push(columns[idx]);
                if (columns[idx].columns) {
                    children = children.concat(columns[idx].columns);
                }
            }
            if (children.length) {
                result = result.concat(flatColumns(children));
            }
            return result;
        }
        function hiddenLeafColumnsCount(columns) {
            var counter = 0;
            var column;
            for (var idx = 0; idx < columns.length; idx++) {
                column = columns[idx];
                if (column.columns) {
                    counter += hiddenLeafColumnsCount(column.columns);
                } else if (column.hidden) {
                    counter++;
                }
            }
            return counter;
        }
        function columnsWidth(cols) {
            var colWidth, width = 0;
            for (var idx = 0, length = cols.length; idx < length; idx++) {
                colWidth = cols[idx].style.width;
                if (colWidth && colWidth.indexOf('%') == -1) {
                    width += parseInt(colWidth, 10);
                }
            }
            return width;
        }
        function removeRowSpanValue(container, count) {
            var cells = container.find('tr:not(.k-filter-row) th:not(.k-group-cell,.k-hierarchy-cell)');
            var rowSpan;
            for (var idx = 0; idx < cells.length; idx++) {
                rowSpan = cells[idx].rowSpan;
                if (rowSpan > 1) {
                    cells[idx].rowSpan = rowSpan - count || 1;
                }
            }
        }
        function addRowSpanValue(container, count) {
            var cells = container.find('tr:not(.k-filter-row) th:not(.k-group-cell,.k-hierarchy-cell)');
            for (var idx = 0; idx < cells.length; idx++) {
                cells[idx].rowSpan += count;
            }
        }
        function removeEmptyRows(container) {
            var rows = container.find('tr:not(.k-filter-row)');
            var emptyRowsCount = rows.filter(function () {
                return !$(this).children().length;
            }).remove().length;
            var cells = rows.find('th:not(.k-group-cell,.k-hierarchy-cell)');
            for (var idx = 0; idx < cells.length; idx++) {
                if (cells[idx].rowSpan > 1) {
                    cells[idx].rowSpan -= emptyRowsCount;
                }
            }
            return rows.length - emptyRowsCount;
        }
        function mapColumnToCellRows(columns, cells, rows, rowIndex, offset) {
            var idx, row, length, children = [];
            for (idx = 0, length = columns.length; idx < length; idx++) {
                row = rows[rowIndex] || [];
                row.push(cells.eq(offset + idx));
                rows[rowIndex] = row;
                if (columns[idx].columns) {
                    children = children.concat(columns[idx].columns);
                }
            }
            if (children.length) {
                mapColumnToCellRows(children, cells, rows, rowIndex + 1, offset + columns.length);
            }
        }
        function lockedColumns(columns) {
            return grep(columns, function (column) {
                return column.locked;
            });
        }
        function nonLockedColumns(columns) {
            return grep(columns, function (column) {
                return !column.locked;
            });
        }
        function visibleNonLockedColumns(columns) {
            return grep(columns, function (column) {
                return !column.locked && isVisible(column);
            });
        }
        function visibleLockedColumns(columns) {
            return grep(columns, function (column) {
                return column.locked && isVisible(column);
            });
        }
        function visibleLeafColumns(columns) {
            var result = [];
            for (var idx = 0; idx < columns.length; idx++) {
                if (columns[idx].hidden) {
                    continue;
                }
                if (columns[idx].columns) {
                    result = result.concat(visibleLeafColumns(columns[idx].columns));
                } else {
                    result.push(columns[idx]);
                }
            }
            return result;
        }
        function leafColumns(columns) {
            var result = [];
            for (var idx = 0; idx < columns.length; idx++) {
                if (!columns[idx].columns) {
                    result.push(columns[idx]);
                    continue;
                }
                result = result.concat(leafColumns(columns[idx].columns));
            }
            return result;
        }
        function leafDataCells(container) {
            var rows = container.find('>tr:not(.k-filter-row)');
            var filter = function () {
                var el = $(this);
                return !el.hasClass('k-group-cell') && !el.hasClass('k-hierarchy-cell');
            };
            var cells = $();
            if (rows.length > 1) {
                cells = rows.find('th').filter(filter).filter(function () {
                    return this.rowSpan > 1;
                });
            }
            cells = cells.add(rows.last().find('th').filter(filter));
            var indexAttr = kendo.attr('index');
            cells.sort(function (a, b) {
                a = $(a);
                b = $(b);
                var indexA = a.attr(indexAttr);
                var indexB = b.attr(indexAttr);
                if (indexA === undefined) {
                    indexA = $(a).index();
                }
                if (indexB === undefined) {
                    indexB = $(b).index();
                }
                indexA = parseInt(indexA, 10);
                indexB = parseInt(indexB, 10);
                return indexA > indexB ? 1 : indexA < indexB ? -1 : 0;
            });
            return cells;
        }
        function parentColumnsCells(cell) {
            var container = cell.closest('table');
            var result = $().add(cell);
            var row = cell.closest('tr');
            var headerRows = container.find('tr:not(.k-filter-row)');
            var level = headerRows.index(row);
            if (level > 0) {
                var parent = headerRows.eq(level - 1);
                var parentCellsWithChildren = parent.find('th:not(.k-group-cell,.k-hierarchy-cell)').filter(function () {
                    return !$(this).attr('rowspan');
                });
                var offset = 0;
                var index = row.find('th:not(.k-group-cell,.k-hierarchy-cell)').index(cell);
                var prevCells = cell.prevAll(':not(.k-group-cell,.k-hierarchy-cell)').filter(function () {
                    return this.colSpan > 1;
                });
                for (var idx = 0; idx < prevCells.length; idx++) {
                    offset += prevCells[idx].colSpan || 1;
                }
                index += Math.max(offset - 1, 0);
                offset = 0;
                for (idx = 0; idx < parentCellsWithChildren.length; idx++) {
                    var parentCell = parentCellsWithChildren.eq(idx);
                    if (parentCell.attr('data-colspan')) {
                        offset += parentCell[0].getAttribute('data-colspan');
                    } else {
                        offset += 1;
                    }
                    if (index >= idx && index < offset) {
                        result = parentColumnsCells(parentCell).add(result);
                        break;
                    }
                }
            }
            return result;
        }
        function childColumnsCells(cell) {
            var container = cell.closest('thead');
            var result = $().add(cell);
            var row = cell.closest('tr');
            var headerRows = container.find('tr:not(.k-filter-row)');
            var level = headerRows.index(row) + cell[0].rowSpan;
            var colSpanAttr = kendo.attr('colspan');
            if (level <= headerRows.length - 1) {
                var child = row.next();
                var prevCells = cell.prevAll(':not(.k-group-cell,.k-hierarchy-cell)');
                var idx;
                prevCells = prevCells.filter(function () {
                    return !this.rowSpan || this.rowSpan === 1;
                });
                var offset = 0;
                for (idx = 0; idx < prevCells.length; idx++) {
                    offset += parseInt(prevCells.eq(idx).attr(colSpanAttr), 10) || 1;
                }
                var cells = child.find('th:not(.k-group-cell,.k-hierarchy-cell)');
                var colSpan = parseInt(cell.attr(colSpanAttr), 10) || 1;
                idx = 0;
                while (idx < colSpan) {
                    child = cells.eq(idx + offset);
                    result = result.add(childColumnsCells(child));
                    var value = parseInt(child.attr(colSpanAttr), 10);
                    if (value > 1) {
                        colSpan -= value - 1;
                    }
                    idx++;
                }
            }
            return result;
        }
        function appendContent(tbody, table, html, empty) {
            var placeholder, tmp = tbody;
            if (empty) {
                tbody.empty();
            }
            if (tbodySupportsInnerHtml) {
                tbody[0].innerHTML = html;
            } else {
                placeholder = document.createElement('div');
                placeholder.innerHTML = '<table><tbody>' + html + '</tbody></table>';
                tbody = placeholder.firstChild.firstChild;
                table[0].replaceChild(tbody, tmp[0]);
                tbody = $(tbody);
            }
            return tbody;
        }
        function addHiddenStyle(attr) {
            attr = attr || {};
            var style = attr.style;
            if (!style) {
                style = 'display:none';
            } else {
                style = style.replace(/display:[^;]*/i, 'display:none');
                if (!style.match(/display:/i)) {
                    style = style.replace(/(.*)?/i, 'display:none;$1');
                }
            }
            return extend({}, attr, { style: style });
        }
        function removeHiddenStyle(attr) {
            attr = attr || {};
            var style = attr.style;
            if (style) {
                attr.style = style.replace(/(display\s*:\s*none\s*;?)*/gi, '');
            }
            return attr;
        }
        function normalizeCols(table, visibleColumns, hasDetails, groups) {
            var colgroup = table.find('>colgroup'), width, cols = map(visibleColumns, function (column) {
                    width = column.width;
                    if (width && parseInt(width, 10) !== 0) {
                        return kendo.format('<col style="width:{0}"/>', typeof width === STRING ? width : width + 'px');
                    }
                    return '<col />';
                });
            if (hasDetails || colgroup.find('.k-hierarchy-col').length) {
                cols.splice(0, 0, '<col class="k-hierarchy-col" />');
            }
            if (colgroup.length) {
                colgroup.remove();
            }
            colgroup = $(new Array(groups + 1).join('<col class="k-group-col">') + cols.join(''));
            if (!colgroup.is('colgroup')) {
                colgroup = $('<colgroup/>').append(colgroup);
            }
            table.prepend(colgroup);
            if (browser.msie && browser.version == 8) {
                table.css('display', 'inline-table');
                window.setTimeout(function () {
                    table.css('display', '');
                }, 1);
            }
        }
        function normalizeHeaderCells(container, columns) {
            var lastIndex = 0;
            var idx, len;
            var th = container.find('th:not(.k-group-cell)');
            for (idx = 0, len = columns.length; idx < len; idx++) {
                if (columns[idx].locked) {
                    th.eq(idx).insertBefore(th.eq(lastIndex));
                    th = container.find('th:not(.k-group-cell)');
                    lastIndex++;
                }
            }
        }
        function convertToObject(array) {
            var result = {}, item, idx, length;
            for (idx = 0, length = array.length; idx < length; idx++) {
                item = array[idx];
                result[item.value] = item.text;
            }
            return result;
        }
        function formatGroupValue(value, format, columnValues, encoded) {
            var isForeignKey = columnValues && columnValues.length && isPlainObject(columnValues[0]) && 'value' in columnValues[0], groupValue = isForeignKey ? convertToObject(columnValues)[value] : value;
            groupValue = groupValue != null ? groupValue : '';
            return format ? kendo.format(format, groupValue) : encoded === false ? groupValue : kendo.htmlEncode(groupValue);
        }
        function setCellVisibility(cells, index, visible) {
            var pad = 0, state, cell = cells[pad];
            while (cell) {
                state = visible ? true : cell.style.display !== 'none';
                if (state && !nonDataCellsRegExp.test(cell.className) && --index < 0) {
                    cell.style.display = visible ? '' : 'none';
                    break;
                }
                cell = cells[++pad];
            }
        }
        function hideColumnCells(rows, columnIndex) {
            var idx = 0, length = rows.length, cell, row;
            for (; idx < length; idx += 1) {
                row = rows.eq(idx);
                if (row.is('.k-grouping-row,.k-detail-row')) {
                    cell = row.children(':not(.k-group-cell):first,.k-detail-cell').last();
                    cell.attr('colspan', parseInt(cell.attr('colspan'), 10) - 1);
                } else {
                    if (row.hasClass('k-grid-edit-row') && (cell = row.children('.k-edit-container')[0])) {
                        cell = $(cell);
                        cell.attr('colspan', parseInt(cell.attr('colspan'), 10) - 1);
                        cell.find('col').eq(columnIndex).remove();
                        row = cell.find('tr:first');
                    }
                    setCellVisibility(row[0].cells, columnIndex, false);
                }
            }
        }
        function groupRows(data) {
            var result = [];
            var item;
            for (var idx = 0; idx < data.length; idx++) {
                item = data[idx];
                if (!('field' in item && 'value' in item && 'items' in item)) {
                    break;
                }
                result.push(item);
                if (item.hasSubgroups) {
                    result = result.concat(groupRows(item.items));
                }
            }
            return result;
        }
        function groupFooters(data) {
            var result = [];
            var item;
            for (var idx = 0; idx < data.length; idx++) {
                item = data[idx];
                if (!('field' in item && 'value' in item && 'items' in item)) {
                    break;
                }
                if (item.hasSubgroups) {
                    result = result.concat(groupFooters(item.items));
                }
                result.push(item.aggregates);
            }
            return result;
        }
        function showColumnCells(rows, columnIndex) {
            var idx = 0, length = rows.length, cell, row, columns;
            for (; idx < length; idx += 1) {
                row = rows.eq(idx);
                if (row.is('.k-grouping-row,.k-detail-row')) {
                    cell = row.children(':not(.k-group-cell):first,.k-detail-cell').last();
                    cell.attr('colspan', parseInt(cell.attr('colspan'), 10) + 1);
                } else {
                    if (row.hasClass('k-grid-edit-row') && (cell = row.children('.k-edit-container')[0])) {
                        cell = $(cell);
                        cell.attr('colspan', parseInt(cell.attr('colspan'), 10) + 1);
                        normalizeCols(cell.find('>form>table'), visibleColumns(columns), false, 0);
                        row = cell.find('tr:first');
                    }
                    setCellVisibility(row[0].cells, columnIndex, true);
                }
            }
        }
        function updateColspan(toAdd, toRemove, num) {
            num = num || 1;
            var item, idx, length;
            for (idx = 0, length = toAdd.length; idx < length; idx++) {
                item = toAdd.eq(idx).children().last();
                item.attr('colspan', parseInt(item.attr('colspan'), 10) + num);
                item = toRemove.eq(idx).children().last();
                item.attr('colspan', parseInt(item.attr('colspan'), 10) - num);
            }
        }
        function tableWidth(table) {
            var idx, length, width = 0;
            var cols = table.find('>colgroup>col');
            for (idx = 0, length = cols.length; idx < length; idx += 1) {
                width += parseInt(cols[idx].style.width, 10);
            }
            return width;
        }
        var Grid = kendo.ui.DataBoundWidget.extend({
            init: function (element, options, events) {
                var that = this;
                options = isArray(options) ? { dataSource: options } : options;
                Widget.fn.init.call(that, element, options);
                if (events) {
                    that._events = events;
                }
                isRtl = kendo.support.isRtl(element);
                that._element();
                that._aria();
                that._columns($.extend(true, [], that.options.columns));
                that._dataSource();
                that._tbody();
                that._pageable();
                that._thead();
                that._groupable();
                that._toolbar();
                that._setContentHeight();
                that._templates();
                that._navigatable();
                that._selectable();
                that._clipboard();
                that._details();
                that._editable();
                that._attachCustomCommandsEvent();
                that._adaptiveColumns();
                that._minScreenSupport();
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                } else {
                    that._group = that._groups() > 0;
                    that._footer();
                }
                if (that.lockedContent) {
                    that.wrapper.addClass('k-grid-lockedcolumns');
                    that._resizeHandler = function () {
                        that.resize();
                    };
                    $(window).on('resize' + NS, that._resizeHandler);
                }
                kendo.notify(that);
            },
            events: [
                CHANGE,
                'dataBinding',
                'cancel',
                DATABOUND,
                DETAILEXPAND,
                DETAILCOLLAPSE,
                DETAILINIT,
                FILTERMENUINIT,
                FILTERMENUOPEN,
                COLUMNMENUINIT,
                COLUMNMENUOPEN,
                EDIT,
                BEFOREEDIT,
                SAVE,
                REMOVE,
                SAVECHANGES,
                CELLCLOSE,
                COLUMNRESIZE,
                COLUMNREORDER,
                COLUMNSHOW,
                COLUMNHIDE,
                COLUMNLOCK,
                COLUMNUNLOCK,
                NAVIGATE,
                'page',
                'sort',
                'filter',
                'group',
                'groupExpand',
                'groupCollapse'
            ],
            setDataSource: function (dataSource) {
                var that = this;
                var scrollable = that.options.scrollable;
                var scrollableContent;
                that.options.dataSource = dataSource;
                that._dataSource();
                that._pageable();
                that._thead();
                if (scrollable) {
                    if (scrollable.virtual) {
                        scrollableContent = that.content.find('>.k-virtual-scrollable-wrap');
                        scrollableContent.scrollLeft(leftMostPosition(scrollableContent, isRtl));
                    } else {
                        scrollableContent = that.tbody;
                        that.content.scrollLeft(leftMostPosition(scrollableContent, isRtl));
                    }
                }
                if (that.options.groupable) {
                    that._groupable();
                }
                if (that.virtualScrollable) {
                    that.virtualScrollable.setDataSource(that.options.dataSource);
                }
                if (that.options.navigatable) {
                    that._navigatable();
                }
                if (that.options.selectable) {
                    that._selectable();
                }
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                }
            },
            options: {
                name: 'Grid',
                columns: [],
                toolbar: null,
                autoBind: true,
                filterable: false,
                scrollable: true,
                sortable: false,
                selectable: false,
                allowCopy: false,
                navigatable: false,
                pageable: false,
                persistSelection: false,
                editable: false,
                groupable: false,
                rowTemplate: '',
                altRowTemplate: '',
                noRecords: false,
                dataSource: {},
                height: null,
                resizable: false,
                reorderable: false,
                columnMenu: false,
                detailTemplate: null,
                columnResizeHandleWidth: 3,
                mobile: '',
                messages: {
                    editable: {
                        cancelDelete: CANCELDELETE,
                        confirmation: DELETECONFIRM,
                        confirmDelete: CONFIRMDELETE
                    },
                    commands: {
                        create: defaultCommands.create.text,
                        cancel: defaultCommands.cancel.text,
                        save: defaultCommands.save.text,
                        destroy: defaultCommands.destroy.text,
                        edit: defaultCommands.edit.text,
                        update: defaultCommands.update.text,
                        canceledit: defaultCommands.canceledit.text,
                        excel: defaultCommands.excel.text,
                        pdf: defaultCommands.pdf.text
                    },
                    noRecords: NORECORDS,
                    expandCollapseColumnHeader: '',
                    groupHeader: 'Press ctrl + space to group',
                    ungroupHeader: 'Press ctrl + space to ungroup'
                }
            },
            destroy: function () {
                var that = this, element;
                that._angularItems('cleanup');
                that._destroyColumnAttachments();
                Widget.fn.destroy.call(that);
                if (this._navigatableTables) {
                    this._navigatableTables.off(NS);
                    this._navigatableTables = null;
                }
                if (that._resizeHandler) {
                    $(window).off('resize' + NS, that._resizeHandler);
                }
                if (that.pager && that.pager.element) {
                    that.pager.destroy();
                }
                if (that.timer) {
                    clearTimeout(that.timer);
                }
                if (that._progressTimeOut) {
                    clearTimeout(that._progressTimeOut);
                }
                if (that._collapseGroupsTimeOut) {
                    clearTimeout(that._collapseGroupsTimeOut);
                }
                if (that._endlessFetchTimeOut) {
                    clearTimeout(that._endlessFetchTimeOut);
                }
                that.pager = null;
                that._destroyGroupable();
                if (that.options.reorderable) {
                    that.wrapper.data('kendoReorderable').destroy();
                }
                if (that.selectable && that.selectable.element) {
                    that.selectable.destroy();
                    that.clearArea();
                    that._selectedIds = null;
                    if (that.copyHandler) {
                        that.wrapper.off('keydown', that.copyHandler);
                        that.unbind(that.copyHandler);
                    }
                    if (that.updateClipBoardState) {
                        that.unbind(that.updateClipBoardState);
                        that.updateClipBoardState = null;
                    }
                    if (that.clearAreaHandler) {
                        that.wrapper.off('keyup', that.clearAreaHandler);
                    }
                }
                that.selectable = null;
                if (that.resizable) {
                    that.resizable.destroy();
                    if (that._resizeUserEvents) {
                        if (that._resizeHandleDocumentClickHandler) {
                            $(document).off('click', that._resizeHandleDocumentClickHandler);
                        }
                        that._resizeUserEvents.destroy();
                        that._resizeUserEvents = null;
                    }
                    that.resizable = null;
                }
                that._destroyVirtualScrollable();
                that._destroyEditable();
                if (that.dataSource) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler);
                    that._refreshHandler = that._progressHandler = that._errorHandler = null;
                }
                element = that.element.add(that.wrapper).add(that.table).add(that.thead).add(that.wrapper.find('>.k-grid-toolbar'));
                if (that.content) {
                    element = element.add(that.content).add(that.content.find('>.k-virtual-scrollable-wrap'));
                }
                if (that.lockedHeader) {
                    that._removeLockedContainers();
                }
                if (that.pane) {
                    that.pane.destroy();
                }
                if (that._isMobile) {
                    that.wrapper.off('transitionend' + NS);
                    that.wrapper.off('contextmenu' + NS);
                }
                if (that.minScreenResizeHandler) {
                    $(window).off('resize', that.minScreenResizeHandler);
                }
                that._detachColumnMediaResizeHandler();
                if (that._draggableInstance && that._draggableInstance.element) {
                    that._draggableInstance.destroy();
                }
                that._draggableInstance = null;
                element.off(NS);
                kendo.destroy(that.wrapper);
                that.rowTemplate = that.altRowTemplate = that.lockedRowTemplate = that.lockedAltRowTemplate = that.detailTemplate = that.footerTemplate = that.groupFooterTemplate = that.lockedGroupFooterTemplate = that.noRecordsTemplate = null;
                that.scrollables = that.thead = that.tbody = that.element = that.table = that.content = that.footer = that.wrapper = that.lockedTable = that.lockedContent = that.lockedHeader = that.lockedFooter = that._groupableClickHandler = that._groupRows = that._setContentWidthHandler = null;
            },
            getOptions: function () {
                var options = this.options;
                options.dataSource = null;
                var result = extend(true, {}, this.options);
                result.columns = kendo.deepExtend([], this.columns);
                var dataSource = this.dataSource;
                var initialData = dataSource.options.data && dataSource._data;
                dataSource.options.data = null;
                result.dataSource = $.extend(true, {}, dataSource.options);
                dataSource.options.data = initialData;
                result.dataSource.data = initialData;
                result.dataSource.page = dataSource.page();
                result.dataSource.filter = $.extend(true, {}, dataSource.filter());
                result.dataSource.pageSize = dataSource.pageSize();
                result.dataSource.sort = dataSource.sort();
                result.dataSource.group = dataSource.group();
                result.dataSource.aggregate = dataSource.aggregate();
                if (result.dataSource.transport) {
                    result.dataSource.transport.dataSource = null;
                }
                if (result.pageable && result.pageable.pageSize) {
                    result.pageable.pageSize = dataSource.pageSize();
                }
                result.$angular = undefined;
                return result;
            },
            setOptions: function (options) {
                var currentOptions = this.getOptions();
                kendo.deepExtend(currentOptions, options);
                if (!options.dataSource) {
                    currentOptions.dataSource = this.dataSource;
                }
                var wrapper = this.wrapper;
                var events = this._events;
                var element = this.element;
                this.destroy();
                this.options = null;
                if (this._isMobile) {
                    var mobileWrapper = wrapper.closest(kendo.roleSelector('pane')).parent();
                    mobileWrapper.after(wrapper);
                    mobileWrapper.remove();
                    wrapper.removeClass('k-grid-mobile');
                }
                if (wrapper[0] !== element[0]) {
                    wrapper.before(element);
                    wrapper.remove();
                }
                element.empty();
                this.init(element, currentOptions, events);
                this._setEvents(currentOptions);
            },
            items: function () {
                if (this.lockedContent) {
                    return this._items(this.tbody).add(this._items(this.lockedTable.children('tbody')));
                } else {
                    return this._items(this.tbody);
                }
            },
            _items: function (container) {
                return container.children().filter(function () {
                    var tr = $(this);
                    return !tr.hasClass('k-grouping-row') && !tr.hasClass('k-detail-row') && !tr.hasClass('k-group-footer');
                });
            },
            dataItems: function () {
                var dataItems = kendo.ui.DataBoundWidget.fn.dataItems.call(this);
                if (this.lockedContent) {
                    var n = dataItems.length, tmp = new Array(2 * n);
                    for (var i = n; --i >= 0;) {
                        tmp[i] = tmp[i + n] = dataItems[i];
                    }
                    dataItems = tmp;
                }
                return dataItems;
            },
            _destroyColumnAttachments: function () {
                var that = this;
                that.resizeHandle = null;
                if (!that.thead) {
                    return;
                }
                this.angular('cleanup', function () {
                    return { elements: that.thead.get() };
                });
                that.thead.add(that.lockedHeader).find('th').each(function () {
                    var th = $(this), filterMenu = th.data('kendoFilterMenu'), sortable = th.data('kendoColumnSorter'), columnMenu = th.data('kendoColumnMenu');
                    if (filterMenu) {
                        filterMenu.destroy();
                    }
                    if (sortable) {
                        sortable.destroy();
                    }
                    if (columnMenu) {
                        columnMenu.destroy();
                    }
                });
            },
            _attachCustomCommandsEvent: function () {
                var that = this, columns = leafColumns(that.columns || []), command, idx, length;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    command = columns[idx].command;
                    if (command) {
                        attachCustomCommandEvent(that, that.wrapper, command);
                    }
                }
            },
            _aria: function () {
                var id = this.element.attr('id') || 'aria';
                if (id) {
                    this._cellId = id + '_active_cell';
                }
            },
            _element: function () {
                var that = this, table = that.element;
                if (!table.is('table')) {
                    if (that.options.scrollable) {
                        table = that.element.find('> .k-grid-content > table');
                    } else {
                        table = that.element.children('table');
                    }
                    if (!table.length) {
                        table = $('<table />').appendTo(that.element);
                    }
                }
                if (isIE7) {
                    table.attr('cellspacing', 0);
                }
                that.table = table.attr('role', that._hasDetails() ? 'treegrid' : 'grid');
                that._wrapper();
            },
            _createResizeHandle: function (container, th) {
                var that = this;
                var indicatorWidth = that.options.columnResizeHandleWidth;
                var scrollable = that.options.scrollable;
                var resizeHandle = that.resizeHandle;
                var left;
                var top;
                if (resizeHandle && that.lockedContent && resizeHandle.data('th')[0] !== th[0]) {
                    resizeHandle.off(NS).remove();
                    resizeHandle = null;
                }
                if (!resizeHandle) {
                    resizeHandle = that.resizeHandle = $('<div class="k-resize-handle"><div class="k-resize-handle-inner"></div></div>');
                    container.append(resizeHandle);
                }
                left = th.offset().left - parseFloat(th.css('marginLeft')) - (container.offset().left + parseFloat(container.css('borderLeftWidth')));
                if (!isRtl) {
                    left += th[0].offsetWidth;
                } else {
                    if (scrollable) {
                        var headerWrap = th.closest('.k-grid-header-wrap, .k-grid-header-locked'), ieCorrection = browser.msie ? headerWrap.scrollLeft() : 0, webkitCorrection = browser.webkit ? headerWrap[0].scrollWidth - headerWrap[0].offsetWidth - headerWrap.scrollLeft() : 0, firefoxCorrection = browser.mozilla ? headerWrap[0].scrollWidth - headerWrap[0].offsetWidth - (headerWrap[0].scrollWidth - headerWrap[0].offsetWidth - headerWrap.scrollLeft()) : 0;
                        left -= webkitCorrection - firefoxCorrection + ieCorrection;
                    }
                }
                top = th.offset().top - parseFloat(th.css('marginTop')) - (container.offset().top + parseFloat(container.css('borderTopWidth')));
                resizeHandle.css({
                    top: top,
                    left: left - indicatorWidth * 3 / 2,
                    height: outerHeight(th),
                    width: indicatorWidth * 3
                }).data('th', th).show();
                resizeHandle.off('dblclick' + NS).on('dblclick' + NS, function () {
                    that._autoFitLeafColumn(th.data('index'));
                });
            },
            _positionColumnResizeHandle: function () {
                var that = this, lockedHead = that.lockedHeader ? that.lockedHeader.find('thead:first') : $();
                that.thead.add(lockedHead).on('mousemove' + NS, 'tr:not(.k-filter-row) > th', function (e) {
                    var button = typeof e.buttons !== 'undefined' ? e.buttons : e.which || e.button;
                    var th = $(this);
                    if (th.hasClass('k-group-cell') || th.hasClass('k-hierarchy-cell')) {
                        return;
                    }
                    if (typeof button !== 'undefined' && button !== 0) {
                        return;
                    }
                    if (th[0].hasAttribute(kendo.attr(COLSPAN))) {
                        return;
                    }
                    that._createResizeHandle(th.closest('div'), th);
                });
            },
            _resizeHandleDocumentClick: function (e) {
                if ($(e.target).closest('.k-column-active').length) {
                    return;
                }
                $(document).off(e);
                this._resetResizeHandleHeader();
                this._hideResizeHandle();
            },
            _resetResizeHandleHeader: function () {
                var th;
                if (!this.resizeHandle) {
                    return;
                }
                th = $(this.resizeHandle).data('th');
                if (th) {
                    th.find(DOT + LINK_CLASS).find(DOT + ICON_CLASS).show();
                    th.find(DOT + ORDER_CLASS).show();
                    th.find(DOT + HEADER_COLUMN_MENU_CLASS).show();
                    th.find(DOT + FILTER_MENU_CLASS).show();
                }
            },
            _hideResizeHandle: function () {
                if (this.resizeHandle) {
                    this.resizeHandle.data('th').removeClass('k-column-active');
                    if (this.lockedContent && !this._isMobile) {
                        this.resizeHandle.off(NS).remove();
                        this.resizeHandle = null;
                    } else {
                        this.resizeHandle.hide();
                    }
                }
            },
            _positionColumnResizeHandleTouch: function () {
                var that = this, lockedHead = that.lockedHeader ? that.lockedHeader.find('thead:first') : $();
                that._resizeUserEvents = new kendo.UserEvents(lockedHead.add(that.thead), {
                    filter: 'th:not(.k-group-cell):not(.k-hierarchy-cell)',
                    threshold: 10,
                    minHold: 500,
                    hold: function (e) {
                        var th = $(e.target);
                        e.preventDefault();
                        if (that.resizeHandle) {
                            that.resizeHandle.data('th').removeClass('k-column-active');
                            that._resetResizeHandleHeader();
                        }
                        th.addClass('k-column-active');
                        th.find(DOT + LINK_CLASS).find(DOT + ICON_CLASS).hide();
                        th.find(DOT + ORDER_CLASS).hide();
                        th.find(DOT + HEADER_COLUMN_MENU_CLASS).hide();
                        th.find(DOT + FILTER_MENU_CLASS).hide();
                        that._createResizeHandle(th.closest('div'), th);
                        if (!that._resizeHandleDocumentClickHandler) {
                            that._resizeHandleDocumentClickHandler = proxy(that._resizeHandleDocumentClick, that);
                        }
                        $(document).on('click', that._resizeHandleDocumentClickHandler);
                    }
                });
            },
            resizeColumn: function (column, columnWidth) {
                var that = this;
                var isLocked = !!column.locked;
                var isHidden = !!column.hidden;
                var options = this.options;
                var scrollbar = !kendo.support.mobileOS ? kendo.support.scrollbar() : 0;
                var index = isLocked ? inArray(column, visibleLockedColumns(that.columns)) : inArray(column, visibleNonLockedColumns(that.columns));
                var contentTable = isLocked ? that.lockedTable : that.table;
                var footer = that.footer || $();
                var header = isLocked ? that.lockedHeader.find('table') : that.thead.closest('table');
                var columnMinWidth = column.minResizableWidth || 10;
                var gridWidth = isLocked ? outerWidth(contentTable.find('tbody')) : outerWidth(that.tbody);
                var col;
                if (isHidden) {
                    column.width = columnWidth > columnMinWidth ? columnWidth : columnMinWidth;
                    return;
                }
                if (that.footer && that.lockedContent) {
                    footer = isLocked ? that.footer.children('.k-grid-footer-locked') : that.footer.children('.k-grid-footer-wrap');
                }
                if (options.scrollable) {
                    col = header.find('col:not(.k-group-col,.k-hierarchy-col):eq(' + index + ')').add(contentTable.children('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')')).add(footer.find('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')'));
                } else {
                    col = contentTable.find('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')');
                }
                if (options.scrollable) {
                    var constrain = false;
                    var totalWidth = that.wrapper.width() - scrollbar;
                    var width = columnWidth = columnWidth > columnMinWidth ? columnWidth : columnMinWidth;
                    if (isLocked && gridWidth - columnWidth + width > totalWidth) {
                        width = columnWidth + (totalWidth - gridWidth - scrollbar * 2);
                        if (width < 0) {
                            width = columnWidth;
                        }
                        constrain = true;
                    }
                    if (width > 10 && width >= columnMinWidth) {
                        col.css('width', width);
                        if (gridWidth) {
                            if (constrain) {
                                width = totalWidth - scrollbar * 2;
                            } else {
                                width = gridWidth + (columnWidth - column.width);
                            }
                            contentTable.add(header).add(footer).css('width', width);
                            if (!isLocked) {
                                that._footerWidth = width;
                            }
                        }
                    }
                    that._scrollVirtualWrapperOnColumnResize();
                } else if (columnWidth > 10 && columnWidth >= columnMinWidth) {
                    col.css('width', columnWidth);
                }
                column.width = columnWidth;
                that._applyLockedContainersWidth();
                that._syncLockedContentHeight();
                that._syncLockedHeaderHeight();
            },
            _resizable: function () {
                var that = this, options = that.options, container, columnStart, columnWidth, columnMinWidth, gridWidth, isMobile = this._isMobile, scrollbar = !kendo.support.mobileOS ? kendo.support.scrollbar() : 0, isLocked, col, th;
                if (options.resizable) {
                    container = options.scrollable ? that.wrapper.find('.k-grid-header-wrap:first') : that.wrapper;
                    if (isMobile) {
                        that._positionColumnResizeHandleTouch(container);
                    } else {
                        that._positionColumnResizeHandle(container);
                    }
                    if (that.resizable) {
                        that.resizable.destroy();
                    }
                    that.resizable = new ui.Resizable(container.add(that.lockedHeader), {
                        handle: (!!options.scrollable ? '' : '>') + '.k-resize-handle',
                        hint: function (handle) {
                            return $('<div class="k-grid-resize-indicator" />').css({ height: outerHeight(handle.data('th')) + that.tbody.attr('clientHeight') });
                        },
                        start: function (e) {
                            th = $(e.currentTarget).data('th');
                            if (isMobile) {
                                that._hideResizeHandle();
                            }
                            var header = th.closest('table'), index = $.inArray(th[0], leafDataCells(th.closest('thead')).filter(':visible'));
                            isLocked = header.parent().hasClass('k-grid-header-locked');
                            var contentTable = isLocked ? that.lockedTable : that.table, footer = that.footer || $();
                            if (that.footer && that.lockedContent) {
                                footer = isLocked ? that.footer.children('.k-grid-footer-locked') : that.footer.children('.k-grid-footer-wrap');
                            }
                            cursor(that.wrapper, 'col-resize');
                            if (options.scrollable) {
                                col = header.find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')').add(contentTable.children('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')')).add(footer.find('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')'));
                            } else {
                                col = contentTable.children('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')');
                            }
                            var columns = $.map(that.columns, function (a) {
                                return !a.hidden && (isLocked && a.locked || !isLocked && !a.locked) ? a : null;
                            });
                            columnStart = e.x.location;
                            columnWidth = outerWidth(th);
                            columnMinWidth = leafColumns(columns)[index].minResizableWidth || 10;
                            gridWidth = isLocked ? outerWidth(contentTable.children('tbody')) : outerWidth(that.tbody);
                            if (browser.webkit) {
                                that.wrapper.addClass('k-grid-column-resizing');
                            }
                        },
                        resize: function (e) {
                            var rtlMultiplier = isRtl ? -1 : 1, currentWidth = columnWidth + e.x.location * rtlMultiplier - columnStart * rtlMultiplier;
                            if (options.scrollable) {
                                var footer;
                                if (isLocked && that.lockedFooter) {
                                    footer = that.lockedFooter.children('table');
                                } else if (that.footer) {
                                    footer = that.footer.find('>.k-grid-footer-wrap>table');
                                }
                                if (!footer || !footer[0]) {
                                    footer = $();
                                }
                                var header = th.closest('table');
                                var contentTable = isLocked ? that.lockedTable : that.table;
                                var constrain = false;
                                var totalWidth = that.wrapper.width() - scrollbar;
                                var width = currentWidth;
                                if (isLocked && gridWidth - columnWidth + width > totalWidth) {
                                    width = columnWidth + (totalWidth - gridWidth - scrollbar * 2);
                                    if (width < 0) {
                                        width = currentWidth;
                                    }
                                    constrain = true;
                                }
                                if (width > 10 && width >= columnMinWidth) {
                                    col.css('width', width);
                                    if (gridWidth) {
                                        if (constrain) {
                                            width = totalWidth - scrollbar * 2;
                                        } else {
                                            width = gridWidth + e.x.location * rtlMultiplier - columnStart * rtlMultiplier;
                                        }
                                        contentTable.add(header).add(footer).css('width', width);
                                        if (!isLocked) {
                                            that._footerWidth = width;
                                        }
                                    }
                                }
                                that._scrollVirtualWrapperOnColumnResize();
                            } else if (currentWidth > 10 && currentWidth >= columnMinWidth) {
                                col.css('width', currentWidth);
                            }
                        },
                        resizeend: function () {
                            var newWidth = outerWidth(th), column, header;
                            cursor(that.wrapper, '');
                            if (browser.webkit) {
                                that.wrapper.removeClass('k-grid-column-resizing');
                            }
                            if (columnWidth != newWidth) {
                                header = that.lockedHeader ? that.lockedHeader.find('thead:first tr:first').add(that.thead.find('tr:first')) : th.parent();
                                var index = th.attr(kendo.attr('index'));
                                if (!index) {
                                    index = header.find('th:not(.k-group-cell):not(.k-hierarchy-cell)').index(th);
                                }
                                column = leafColumns(that.columns)[index];
                                column.width = newWidth;
                                that.trigger(COLUMNRESIZE, {
                                    column: column,
                                    oldWidth: columnWidth,
                                    newWidth: newWidth
                                });
                                that._applyLockedContainersWidth();
                                that._syncLockedContentHeight();
                                that._syncLockedHeaderHeight();
                            }
                            that._resetResizeHandleHeader();
                            that._hideResizeHandle();
                            th = null;
                        }
                    });
                }
            },
            _draggable: function () {
                var that = this;
                if (that.options.reorderable) {
                    if (that._draggableInstance) {
                        that._draggableInstance.destroy();
                    }
                    var header = that.wrapper.children('.k-grid-header');
                    that._draggableInstance = that.wrapper.kendoDraggable({
                        group: kendo.guid(),
                        autoScroll: true,
                        filter: that.content ? '.k-grid-header:first ' + HEADERCELLS : 'table:first>.k-grid-header ' + HEADERCELLS,
                        dragstart: function () {
                            header.children('.k-grid-header-wrap').unbind('scroll' + NS + 'scrolling').bind('scroll' + NS + 'scrolling', function (e) {
                                if (that.virtualScrollable) {
                                    that.content.find('>.k-virtual-scrollable-wrap').scrollLeft(this.scrollLeft);
                                } else {
                                    that.scrollables.not(e.currentTarget).scrollLeft(this.scrollLeft);
                                }
                            });
                        },
                        dragend: function () {
                            that._resetResizeHandleHeader();
                            header.children('.k-grid-header-wrap').unbind('scroll' + NS + 'scrolling');
                        },
                        drag: function () {
                            that._hideResizeHandle();
                        },
                        hint: function (target) {
                            var title = target.attr(kendo.attr('title'));
                            if (title) {
                                title = kendo.htmlEncode(title);
                            }
                            return $('<div class="k-header k-reorder-clue k-drag-clue" />').html(title || target.attr(kendo.attr('field')) || target.text()).prepend('<span class="k-icon k-drag-status k-i-cancel" />');
                        }
                    }).data('kendoDraggable');
                }
            },
            _reorderable: function () {
                var that = this;
                if (that.options.reorderable) {
                    if (that.wrapper.data('kendoReorderable')) {
                        that.wrapper.data('kendoReorderable').destroy();
                    }
                    that.wrapper.kendoReorderable({
                        draggable: that._draggableInstance,
                        dragOverContainers: function (sourceIndex, targetIndex) {
                            var columns = flatColumnsInDomOrder(that.columns);
                            return columns[sourceIndex].lockable !== false && targetParentContainerIndex(columns, that.columns, sourceIndex, targetIndex) > -1;
                        },
                        inSameContainer: function (e) {
                            return $(e.source).parent()[0] === $(e.target).parent()[0] && targetParentContainerIndex(flatColumnsInDomOrder(that.columns), that.columns, e.sourceIndex, e.targetIndex) > -1;
                        },
                        change: function (e) {
                            var columns = flatColumnsInDomOrder(that.columns);
                            var column = columns[e.oldIndex];
                            var newIndex = targetParentContainerIndex(columns, that.columns, e.oldIndex, e.newIndex);
                            that.trigger(COLUMNREORDER, {
                                newIndex: newIndex,
                                oldIndex: inArray(column, columns),
                                column: column
                            });
                            that.reorderColumn(newIndex, column, e.position === 'before');
                        }
                    });
                }
            },
            _reorderHeader: function (sources, target, before, container) {
                var that = this;
                var sourcePosition = columnPosition(sources[0], that.columns);
                var destPosition = columnPosition(target, that.columns);
                var action;
                var ths;
                var leafs = [];
                for (var idx = 0; idx < sources.length; idx++) {
                    if (sources[idx].columns) {
                        leafs = leafs.concat(sources[idx].columns);
                    }
                }
                if (container) {
                    ths = elements(container, container, 'tr:eq(' + sourcePosition.row + ')>th.k-header:not(.k-group-cell,.k-hierarchy-cell)');
                } else {
                    ths = elements(that.lockedHeader, that.thead, 'tr:eq(' + sourcePosition.row + ')>th.k-header:not(.k-group-cell,.k-hierarchy-cell)');
                }
                var sourceLockedColumns = lockedColumns(sources).length;
                var targetLockedColumns = lockedColumns([target]).length;
                if (leafs.length) {
                    if (sourceLockedColumns > 0 && targetLockedColumns === 0) {
                        action = 'prepend';
                        moveCellsBetweenContainers(sources, target, leafs, that.columns, that.lockedHeader.find('thead'), that.thead, this._groups(), action);
                    } else if (sourceLockedColumns === 0 && targetLockedColumns > 0) {
                        action = destPosition.cell === 0 && sources[0].columns && !target.columns && !that._group ? 'prepend' : 'append';
                        moveCellsBetweenContainers(sources, target, leafs, nonLockedColumns(that.columns), that.thead, that.lockedHeader.find('thead'), this._groups(), action);
                    }
                    if (target.columns || sourcePosition.cell - destPosition.cell > 1 || destPosition.cell - sourcePosition.cell > 1) {
                        target = findReorderTarget(that.columns, target, sources[0], before, that.columns);
                        if (target) {
                            if (sourceLockedColumns > 0 && targetLockedColumns === 0) {
                                that._reorderHeader(leafs, target, before, that.thead);
                            } else if (sourceLockedColumns === 0 && targetLockedColumns > 0) {
                                that._reorderHeader(leafs, target, before, that.lockedHead);
                            } else {
                                that._reorderHeader(leafs, target, before);
                            }
                        }
                    }
                } else if (sourceLockedColumns !== targetLockedColumns) {
                    updateCellRowSpan(ths[sourcePosition.cell], that.columns, sourceLockedColumns);
                }
                reorder(ths, sourcePosition.cell, destPosition.cell, before, sources.length);
            },
            _reorderContent: function (sources, destination, before) {
                var that = this;
                var lockedRows = $();
                var source = sources[0];
                var visibleSources = visibleColumns(sources);
                var sourceIndex = inArray(source, leafColumns(that.columns));
                var destIndex = inArray(destination, leafColumns(that.columns));
                var colSourceIndex = inArray(visibleSources[0], visibleLeafColumns(that.columns));
                var colDest = inArray(destination, visibleLeafColumns(that.columns));
                var lockedCount = lockedColumns(that.columns).length;
                var isLocked = !!destination.locked;
                var footer = that.footer || that.wrapper.find('.k-grid-footer');
                var headerCol, footerCol, beforeVisibleColumn;
                headerCol = footerCol = colDest;
                if (destination.hidden) {
                    var columnsArray = isLocked ? lockedColumns(that.columns) : nonLockedColumns(that.columns);
                    if (visibleColumns(columnsArray).length > 0) {
                        headerCol = footerCol = colDest = this._findClosestVisibleColumnIndex(columnsArray, destIndex);
                        beforeVisibleColumn = visibleColumns(columnsArray.slice(destIndex)).length > 0;
                    } else {
                        if (isLocked) {
                            colDest = that.lockedTable.find('colgroup');
                            headerCol = that.lockedHeader.find('colgroup');
                            footerCol = $(that.lockedFooter).find('>table>colgroup');
                        } else {
                            colDest = that.tbody.prev();
                            headerCol = that.thead.prev();
                            footerCol = footer.find('.k-grid-footer-wrap').find('>table>colgroup');
                        }
                    }
                }
                if (that._hasFilterRow()) {
                    reorder(that.wrapper.find('.k-filter-row th:not(.k-group-cell,.k-hierarchy-cell)'), sourceIndex, destIndex, before, sources.length);
                }
                if (colSourceIndex >= 0) {
                    reorder(elements(that.lockedHeader, that.thead.prev(), 'col:not(.k-group-col,.k-hierarchy-col)'), colSourceIndex, headerCol, beforeVisibleColumn ? beforeVisibleColumn : before, visibleSources.length);
                }
                if (that.options.scrollable) {
                    if (colSourceIndex >= 0) {
                        reorder(elements(that.lockedTable, that.tbody.prev(), 'col:not(.k-group-col,.k-hierarchy-col)'), colSourceIndex, colDest, beforeVisibleColumn ? beforeVisibleColumn : before, visibleSources.length);
                    }
                }
                if (footer && footer.length) {
                    if (colSourceIndex >= 0) {
                        reorder(elements(that.lockedFooter, footer.find('.k-grid-footer-wrap'), '>table>colgroup>col:not(.k-group-col,.k-hierarchy-col)'), colSourceIndex, footerCol, beforeVisibleColumn ? beforeVisibleColumn : before, visibleSources.length);
                    }
                    reorder(footer.find('.k-footer-template>td:not(.k-group-cell,.k-hierarchy-cell)'), sourceIndex, destIndex, before, sources.length);
                }
                var rows = that.tbody.children(':not(.k-grouping-row,.k-detail-row)');
                if (that.lockedTable) {
                    if (lockedCount > destIndex) {
                        if (lockedCount <= sourceIndex) {
                            updateColspan(that.lockedTable.find('>tbody>tr.k-grouping-row'), that.table.find('>tbody>tr.k-grouping-row'), sources.length);
                        }
                    } else if (lockedCount > sourceIndex) {
                        updateColspan(that.table.find('>tbody>tr.k-grouping-row'), that.lockedTable.find('>tbody>tr.k-grouping-row'), sources.length);
                    }
                    lockedRows = that.lockedTable.find('>tbody>tr:not(.k-grouping-row,.k-detail-row)');
                }
                for (var idx = 0, length = rows.length; idx < length; idx += 1) {
                    reorder(elements(lockedRows[idx], rows[idx], '>td:not(.k-group-cell,.k-hierarchy-cell)'), sourceIndex, destIndex, before, sources.length);
                }
            },
            _findClosestVisibleColumnIndex: function (columns, columnIndex) {
                var columnsArray = visibleColumns(columns.slice(columnIndex)).length > 0 ? columns.slice(columnIndex) : columns.slice(0, columnIndex + 1).reverse(), closestVisibleColumn = visibleColumns(columnsArray)[0];
                return inArray(closestVisibleColumn, visibleColumns(this.columns));
            },
            _autoFitLeafColumn: function (leafIndex) {
                this.autoFitColumn(leafColumns(this.columns)[leafIndex]);
            },
            autoFitColumn: function (column) {
                var that = this, options = that.options, columns = that.columns, index, th, headerTable, isLocked, visibleLocked = that.lockedHeader ? leafDataCells(that.lockedHeader.find('>table>thead')).filter(isCellVisible).length : 0, col, minWidth, contentDiv, scrollLeft, notGroupOrHierarchyCol = 'col:not(.k-group-col):not(.k-hierarchy-col)', notGroupOrHierarchyVisibleCell = 'td:visible:not(.k-group-cell):not(.k-hierarchy-cell)';
                if (typeof column == 'number') {
                    column = columns[column];
                } else if (isPlainObject(column)) {
                    column = grep(flatColumns(columns), function (item) {
                        return item === column;
                    })[0];
                } else {
                    column = grep(flatColumns(columns), function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || !isVisible(column)) {
                    return;
                }
                minWidth = column.minResizableWidth;
                index = inArray(column, leafColumns(columns));
                isLocked = column.locked;
                if (isLocked) {
                    headerTable = that.lockedHeader.children('table');
                } else {
                    headerTable = that.thead.parent();
                }
                th = headerTable.find('[data-index=\'' + index + '\']');
                var contentTable = isLocked ? that.lockedTable : that.table, footer = that.footer || $();
                if (that.footer && that.lockedContent) {
                    footer = isLocked ? that.footer.children('.k-grid-footer-locked') : that.footer.children('.k-grid-footer-wrap');
                }
                var footerTable = footer.find('table').first();
                if (that.lockedHeader && !isLocked) {
                    index -= visibleLocked;
                }
                for (var j = 0; j < columns.length; j++) {
                    if (columns[j] === column) {
                        break;
                    } else {
                        if (columns[j].hidden) {
                            index--;
                        }
                    }
                }
                if (options.scrollable) {
                    col = headerTable.find(notGroupOrHierarchyCol).eq(index).add(contentTable.children('colgroup').find(notGroupOrHierarchyCol).eq(index)).add(footerTable.find('colgroup').find(notGroupOrHierarchyCol).eq(index));
                    if (!isLocked) {
                        contentDiv = contentTable.parent();
                        scrollLeft = contentDiv.scrollLeft();
                    }
                } else {
                    col = contentTable.children('colgroup').find(notGroupOrHierarchyCol).eq(index);
                }
                var tables = headerTable.add(contentTable).add(footerTable);
                var oldColumnWidth = outerWidth(th);
                col.width('');
                tables.css('table-layout', 'fixed');
                col.width('auto');
                tables.addClass('k-autofitting');
                tables.css('table-layout', '');
                var newColumnWidth = Math.ceil(Math.max(outerWidth(th), outerWidth(contentTable.find('tr:not(.k-grouping-row)').eq(0).children(notGroupOrHierarchyVisibleCell).eq(index)), outerWidth(footerTable.find('tr').eq(0).children(notGroupOrHierarchyVisibleCell).eq(index)))) + 1;
                if (minWidth && minWidth > newColumnWidth) {
                    newColumnWidth = minWidth;
                }
                col.width(newColumnWidth);
                column.width = newColumnWidth;
                if (options.scrollable) {
                    var cols = headerTable.find('col'), colWidth, totalWidth = 0;
                    for (var idx = 0, length = cols.length; idx < length; idx += 1) {
                        colWidth = cols[idx].style.width;
                        if (colWidth && colWidth.indexOf('%') == -1) {
                            totalWidth += parseInt(colWidth, 10);
                        } else if (cols.eq(idx).hasClass('k-group-col')) {
                            totalWidth += parseInt(cols.eq(idx).width(), 10);
                        } else {
                            totalWidth = 0;
                            break;
                        }
                    }
                    if (totalWidth) {
                        tables.each(function () {
                            this.style.width = totalWidth + 'px';
                        });
                    }
                }
                if (browser.msie && browser.version == 8) {
                    tables.css('display', 'inline-table');
                    setTimeout(function () {
                        tables.css('display', 'table');
                    }, 1);
                }
                tables.removeClass('k-autofitting');
                if (scrollLeft) {
                    contentDiv.scrollLeft(scrollLeft);
                }
                that.trigger(COLUMNRESIZE, {
                    column: column,
                    oldWidth: oldColumnWidth,
                    newWidth: newColumnWidth
                });
                that._applyLockedContainersWidth();
                that._syncLockedContentHeight();
                that._syncLockedHeaderHeight();
            },
            reorderColumn: function (destIndex, column, before) {
                var that = this, parent = columnParent(column, that.columns), columns = parent ? parent.columns : that.columns, sourceIndex = inArray(column, columns), destColumn = columns[destIndex], lockChanged, isLocked = !!destColumn.locked, lockedCount = lockedColumns(that.columns).length, groupHeaderColumnTemplateColumns = grep(leafColumns(that.columns), function (column) {
                        return column.groupHeaderColumnTemplate;
                    });
                if (sourceIndex === destIndex) {
                    return;
                }
                if (!column.locked && isLocked && nonLockedColumns(that.columns).length == 1) {
                    return;
                }
                if (column.locked && !isLocked && lockedCount == 1) {
                    return;
                }
                that._hideResizeHandle();
                if (before === undefined) {
                    before = destIndex < sourceIndex;
                }
                var sourceColumns = [column];
                that._reorderHeader(sourceColumns, destColumn, before);
                if (that.lockedHeader) {
                    removeEmptyRows(that.thead);
                    removeEmptyRows(that.lockedHeader);
                }
                if (destColumn.columns) {
                    destColumn = leafColumns(destColumn.columns);
                    destColumn = destColumn[before ? 0 : destColumn.length - 1];
                }
                if (column.columns) {
                    sourceColumns = leafColumns(column.columns);
                }
                that._reorderContent(sourceColumns, destColumn, before);
                lockChanged = !!column.locked;
                lockChanged = lockChanged != isLocked;
                column.locked = isLocked;
                columns.splice(before ? destIndex : destIndex + 1, 0, column);
                columns.splice(sourceIndex < destIndex ? sourceIndex : sourceIndex + 1, 1);
                that._updateLockedCols();
                that._updateCols();
                that._templates();
                that._updateColumnCellIndex();
                that._updateColumnSorters();
                if (groupHeaderColumnTemplateColumns.length > 0) {
                    that._renderGroupRows();
                }
                that._updateTablesWidth();
                that._applyLockedContainersWidth();
                that._syncLockedHeaderHeight();
                that._syncLockedContentHeight();
                that._updateFirstColumnClass();
                if (!lockChanged) {
                    return;
                }
                if (isLocked) {
                    that.trigger(COLUMNLOCK, { column: column });
                } else {
                    that.trigger(COLUMNUNLOCK, { column: column });
                }
            },
            _updateColumnCellIndex: function () {
                var header;
                var offset = 0;
                if (this.lockedHeader) {
                    header = this.lockedHeader.find('thead');
                    offset = updateCellIndex(header, lockedColumns(this.columns));
                }
                updateCellIndex(this.thead, nonLockedColumns(this.columns), offset);
            },
            lockColumn: function (column) {
                var columns = this.columns;
                if (typeof column == 'number') {
                    column = columns[column];
                } else {
                    column = grep(columns, function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || column.locked || column.hidden) {
                    return;
                }
                var index = lockedColumns(columns).length - 1;
                this.reorderColumn(index, column, false);
            },
            unlockColumn: function (column) {
                var columns = this.columns;
                if (typeof column == 'number') {
                    column = columns[column];
                } else {
                    column = grep(columns, function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || !column.locked || column.hidden) {
                    return;
                }
                var index = lockedColumns(columns).length;
                this.reorderColumn(index, column, true);
            },
            cellIndex: function (td) {
                var lockedColumnOffset = 0;
                if (this.lockedTable && !$.contains(this.lockedTable[0], td[0])) {
                    lockedColumnOffset = leafColumns(lockedColumns(this.columns)).length;
                }
                return $(td).parent().children('td:not(.k-group-cell,.k-hierarchy-cell)').index(td) + lockedColumnOffset;
            },
            _modelForContainer: function (container) {
                container = $(container);
                if (!container.is('tr') && this._editMode() !== 'popup') {
                    container = container.closest('tr');
                }
                var id = container.attr(kendo.attr('uid'));
                return this.dataSource.getByUid(id);
            },
            _editable: function () {
                var that = this, selectable = that.selectable && that.selectable.options.multiple, editable = that.options.editable, handler = function () {
                        var target = activeElement(), cell = that._editContainer;
                        if (cell && cell[0] && !$.contains(cell[0], target) && cell[0] !== target && !$(target).closest('.k-animation-container').length) {
                            if (that.editable.end()) {
                                that.closeCell();
                            } else {
                                that._scrollVirtualWrapper();
                            }
                        }
                    };
                if (editable) {
                    this.wrapper.addClass('k-editable');
                    var mode = that._editMode();
                    if (mode === 'incell') {
                        that.table.add(that.lockedTable).on('mousedown' + NS, NAVROW + '>' + NAVCELL, function (e) {
                            var target = $(e.target);
                            if (that._editMode() === 'incell' && target.hasClass('k-checkbox-label') && target.prev().attr(kendo.attr('bind'))) {
                                e.preventDefault();
                            }
                        });
                        if (editable.update !== false) {
                            if (isMac) {
                                that.wrapper.on(CLICK + NS, '.k-edit-cell > input[type=\'checkbox\']', function (e) {
                                    $(e.target).focus();
                                }).on(CLICK + NS, '.k-edit-cell', function (e) {
                                    if (!$(e.target).is('input')) {
                                        $(e.currentTarget).find('input[type=\'checkbox\']').focus();
                                    }
                                }).on(MOUSEDOWN + NS, 'tr:not(.k-grouping-row) > td', function (e) {
                                    var editContainer = that._editContainer;
                                    if (editContainer && editContainer[0] && ($.contains(editContainer[0], e.target) || editContainer[0] === e.target)) {
                                        that._mousedownOnEditCell = true;
                                    } else {
                                        that._mousedownOnEditCell = false;
                                    }
                                });
                            }
                            that.wrapper.on(kendo.support.touch ? 'touchstart' + NS : CLICK + NS, 'tr:not(.k-grouping-row) > td', function (e) {
                                var td = $(this), isLockedCell = that.lockedTable && td.closest('table')[0] === that.lockedTable[0];
                                that._mousedownOnEditCell = false;
                                if (td.hasClass('k-hierarchy-cell') || td.hasClass('k-detail-cell') || td.hasClass('k-group-cell') || td.hasClass('k-edit-cell') || td.has('a.k-grid-delete').length || td.has('button.k-grid-delete').length || td.closest('tbody')[0] !== that.tbody[0] && !isLockedCell || $(e.target).is(':input')) {
                                    return;
                                }
                                if (that.editable) {
                                    if (that.editable.end()) {
                                        if (selectable) {
                                            $(activeElement()).blur();
                                        }
                                        that.closeCell();
                                        that.editCell(td);
                                    } else {
                                        that._scrollVirtualWrapper();
                                    }
                                } else {
                                    that.editCell(td);
                                }
                            }).on('focusin' + NS, function () {
                                if (!$.contains(this, activeElement())) {
                                    clearTimeout(that.timer);
                                    that.timer = null;
                                }
                            }).on('focusout' + NS, function (e) {
                                var shouldCloseCell = true;
                                if (isMac && that._mousedownOnEditCell) {
                                    shouldCloseCell = false;
                                }
                                that._mousedownOnEditCell = false;
                                if (shouldCloseCell) {
                                    that.timer = setTimeout(function () {
                                        handler(e);
                                    }, 1);
                                }
                            });
                        }
                    } else {
                        if (editable.update !== false) {
                            that.wrapper.on(CLICK + NS, 'tbody>tr:not(.k-detail-row,.k-grouping-row):visible a.k-grid-edit', function (e) {
                                e.preventDefault();
                                that.editRow($(this).closest('tr'));
                            });
                            if (that._isVirtualInlineEditable()) {
                                that.wrapper.on('focusout' + NS, 'tr:not(.k-grouping-row) > td', function () {
                                    if (that.editable && !that.editable.end()) {
                                        that._scrollVirtualWrapper();
                                    }
                                });
                            }
                        }
                    }
                    if (editable.destroy !== false) {
                        that.wrapper.on(CLICK + NS, 'tbody>tr:not(.k-detail-row,.k-grouping-row):visible .k-grid-delete', function (e) {
                            e.preventDefault();
                            e.stopPropagation();
                            that.removeRow($(this).closest('tr'));
                        });
                    } else {
                        that.wrapper.on(CLICK + NS, 'tbody>tr:not(.k-detail-row,.k-grouping-row):visible button.k-grid-delete', function (e) {
                            e.stopPropagation();
                            if (!that._confirmation()) {
                                e.preventDefault();
                            }
                        });
                    }
                }
            },
            editCell: function (cell) {
                cell = $(cell);
                var that = this, column = leafColumns(that.columns)[that.cellIndex(cell)], model = that._modelForContainer(cell);
                that.closeCell();
                if (model && isColumnEditable(column, model) && !column.command) {
                    if (that.trigger(BEFOREEDIT, { model: model })) {
                        return;
                    }
                    that._attachModelChange(model);
                    that._editContainer = cell;
                    if (that._shouldClearEditableState) {
                        that._clearEditableState();
                    }
                    that.editable = cell.addClass('k-edit-cell').kendoEditable({
                        fields: {
                            field: column.field,
                            format: column.format,
                            editor: column.editor,
                            values: column.values
                        },
                        model: model,
                        target: that,
                        change: function (e) {
                            if (that.trigger(SAVE, {
                                    values: e.values,
                                    container: cell,
                                    model: model
                                })) {
                                e.preventDefault();
                            }
                        },
                        skipFocus: that._isVirtualIncellEditable() && that._editableState ? true : false
                    }).data('kendoEditable');
                    var tr = cell.parent().addClass('k-grid-edit-row');
                    if (that.lockedContent) {
                        adjustRowHeight(tr[0], that._relatedRow(tr).addClass('k-grid-edit-row')[0]);
                    }
                    that.trigger(EDIT, {
                        container: cell,
                        model: model
                    });
                }
            },
            _adjustLockedHorizontalScrollBar: function () {
                var table = this.table, content = table.parent();
                var scrollbar = table[0].offsetWidth > content[0].clientWidth ? kendo.support.scrollbar() : 0;
                this.lockedContent.height(content[0].offsetHeight - scrollbar);
            },
            _syncLockedContentHeight: function () {
                if (this.lockedTable) {
                    if (!this.touchScroller) {
                        this._adjustLockedHorizontalScrollBar();
                    }
                    this._adjustRowsHeight(this.table, this.lockedTable);
                }
            },
            _syncLockedHeaderHeight: function () {
                if (this.lockedHeader) {
                    var lockedTable = this.lockedHeader.children('table');
                    var table = this.thead.parent();
                    this._adjustRowsHeight(lockedTable, table);
                    syncTableHeight(lockedTable, table);
                }
            },
            _syncLockedFooterHeight: function () {
                if (this.lockedFooter && this.footer && this.footer.length) {
                    this._adjustRowsHeight(this.lockedFooter.children('table'), this.footer.find('.k-grid-footer-wrap > table'));
                }
            },
            _destroyEditable: function () {
                var that = this;
                var destroy = function () {
                    if (that.editable) {
                        var container = that.editView ? that.editView.element : that._editContainer;
                        if (container) {
                            container.off(CLICK + NS, 'a.k-grid-cancel', that._editCancelClickHandler);
                            container.off(CLICK + NS, 'a.k-grid-update', that._editUpdateClickHandler);
                        }
                        that._detachModelChange();
                        that.editable.destroy();
                        that.editable = null;
                        that._editContainer = null;
                        that._destroyEditView();
                        that._editableIsClosing = null;
                    }
                };
                if (that.editable) {
                    if (that._editMode() === 'popup' && !that._isMobile) {
                        if (that._editableIsClosing) {
                            that._editContainer.data('kendoWindow').bind('deactivate', destroy);
                        } else {
                            that._editableIsClosing = true;
                            that._editContainer.data('kendoWindow').bind('deactivate', destroy).close();
                        }
                    } else {
                        destroy();
                    }
                }
                if (that._confirmDialog) {
                    that._confirmDialog.close();
                    that._confirmDialog.destroy();
                    that._confirmDialog = null;
                }
            },
            _destroyEditView: function () {
                if (this.editView) {
                    this.editView.purge();
                    this.editView = null;
                    this.pane.navigate('');
                }
            },
            _attachModelChange: function (model) {
                var that = this;
                that._modelChangeHandler = function (e) {
                    that._modelChange({
                        field: e.field,
                        model: this
                    });
                };
                model.bind('change', that._modelChangeHandler);
            },
            _detachModelChange: function () {
                var that = this, container = that._editContainer, model = that._modelForContainer(container);
                if (model) {
                    model.unbind(CHANGE, that._modelChangeHandler);
                }
            },
            closeCell: function (isCancel) {
                var that = this, cell = that._editContainer, column, tr, model;
                if (!cell) {
                    return;
                }
                model = that._modelForContainer(cell);
                if (isCancel && that.trigger('cancel', {
                        container: cell,
                        model: model
                    })) {
                    return;
                }
                that.trigger(CELLCLOSE, {
                    type: isCancel ? 'cancel' : 'save',
                    model: model,
                    container: cell
                });
                cell.removeClass('k-edit-cell');
                column = leafColumns(that.columns)[that.cellIndex(cell)];
                tr = cell.parent().removeClass('k-grid-edit-row');
                if (that.lockedContent) {
                    that._relatedRow(tr).removeClass('k-grid-edit-row');
                }
                that._destroyEditable();
                that._displayCell(cell, column, model);
                if (that._shouldClearEditableState) {
                    that._clearEditableState();
                }
                that.trigger('itemChange', {
                    item: tr,
                    data: model,
                    ns: ui
                });
                if (that.lockedContent) {
                    adjustRowHeight(tr.css('height', '')[0], that._relatedRow(tr).css('height', '')[0]);
                }
            },
            _displayCell: function (cell, column, dataItem) {
                var that = this, state = {
                        storage: {},
                        count: 0
                    }, settings = extend({}, kendo.Template, that.options.templateSettings), tmpl = kendo.template(that._cellTmpl(column, state), settings);
                if (state.count > 0) {
                    tmpl = proxy(tmpl, state.storage);
                }
                cell.empty().html(tmpl(dataItem));
                that.angular('compile', function () {
                    return {
                        elements: cell,
                        data: [{ dataItem: dataItem }]
                    };
                });
            },
            removeRow: function (row) {
                if (!this._confirmation(row)) {
                    return;
                }
                this._removeRow(row);
            },
            _removeRow: function (row) {
                var that = this, model, modelId, key, schema, mode = that._editMode();
                if (mode !== 'incell') {
                    that.cancelRow();
                }
                row = $(row);
                if (that.lockedContent) {
                    row = row.add(that._relatedRow(row));
                }
                row = row.hide();
                model = that._modelForContainer(row);
                if (model && !that.trigger(REMOVE, {
                        row: row,
                        model: model
                    })) {
                    schema = that.dataSource.options.schema;
                    if (that._selectedIds && schema && schema.model) {
                        modelId = isFunction(that.dataSource.options.schema.model) ? that.dataSource.options.schema.model.fn.idField : that.dataSource.options.schema.model.id;
                        key = model[modelId];
                        delete that._selectedIds[key];
                    }
                    that.dataSource.remove(model);
                    if (mode === 'inline' || mode === 'popup') {
                        that.dataSource.sync();
                    }
                } else if (mode === 'incell') {
                    that._destroyEditable();
                }
            },
            _editMode: function () {
                var mode = 'incell', editable = this.options.editable;
                if (editable !== true) {
                    if (typeof editable == 'string') {
                        mode = editable;
                    } else {
                        mode = editable.mode || mode;
                    }
                }
                return mode;
            },
            editRow: function (row) {
                var model;
                var that = this;
                if (row instanceof ObservableObject) {
                    model = row;
                } else {
                    row = $(row);
                    model = that._modelForContainer(row);
                }
                var mode = that._editMode();
                var container;
                that.cancelRow();
                if (model) {
                    row = that.tbody.children('[' + kendo.attr('uid') + '=' + model.uid + ']');
                    that._attachModelChange(model);
                    if (mode === 'popup') {
                        that._createPopupEditor(model);
                    } else if (mode === 'inline') {
                        that._createInlineEditor(row, model);
                    } else if (mode === 'incell') {
                        $(row).children(DATA_CELL).each(function () {
                            var cell = $(this);
                            var column = leafColumns(that.columns)[that.cellIndex(cell)];
                            model = that._modelForContainer(cell);
                            if (model && (!model.editable || model.editable(column.field)) && column.field && !column.selectable) {
                                that.editCell(cell);
                                return false;
                            }
                        });
                    }
                    container = that.editView ? that.editView.element : that._editContainer;
                    if (container) {
                        if (!this._editCancelClickHandler) {
                            this._editCancelClickHandler = proxy(this._editCancelClick, this);
                        }
                        container.on(CLICK + NS, 'a.k-grid-cancel', this._editCancelClickHandler);
                        if (!this._editUpdateClickHandler) {
                            this._editUpdateClickHandler = proxy(this._editUpdateClick, this);
                        }
                        container.on(CLICK + NS, 'a.k-grid-update', this._editUpdateClickHandler);
                    }
                }
            },
            _editUpdateClick: function (e) {
                e.preventDefault();
                e.stopPropagation();
                this.saveRow();
            },
            _editCancelClick: function (e) {
                var that = this;
                var navigatable = that.options.navigatable;
                var model = that.editable.options.model;
                var container = that.editView ? that.editView.element : that._editContainer;
                e.preventDefault();
                e.stopPropagation();
                if (that.trigger('cancel', {
                        container: container,
                        model: model
                    })) {
                    return;
                }
                var currentIndex = that.items().index($(that.current()).parent());
                that.cancelRow();
                if (navigatable) {
                    that._setCurrent(that.items().eq(currentIndex).children().filter(NAVCELL).first());
                    focusTable(that.table, true);
                }
            },
            _createPopupEditor: function (model) {
                var that = this;
                var html = '<div ' + kendo.attr('uid') + '="' + model.uid + '" class="k-popup-edit-form' + (that._isMobile ? ' k-mobile-list' : '') + '"><' + (that._isMobile ? 'ul' : 'div') + ' class="k-edit-form-container">';
                var column;
                var command;
                var fields = [];
                var idx;
                var length;
                var tmpl;
                var updateText;
                var cancelText;
                var updateIconClass;
                var cancelIconClass;
                var tempCommand;
                var columns = leafColumns(that.columns);
                var attr;
                var editMenuGuid = kendo.guid();
                var editable = that.options.editable;
                var template = editable.template;
                var options = isPlainObject(editable) ? editable.window : {};
                var settings = extend({}, kendo.Template, that.options.templateSettings);
                var state;
                if (that.trigger(BEFOREEDIT, { model: model })) {
                    return;
                }
                options = options || {};
                if (template) {
                    if (typeof template === STRING) {
                        template = window.unescape(template);
                    }
                    html += kendo.template(template, settings)(model);
                    for (idx = 0, length = columns.length; idx < length; idx++) {
                        column = columns[idx];
                        if (column.command) {
                            tempCommand = getCommand(column.command, 'edit');
                            if (tempCommand) {
                                command = tempCommand;
                            }
                        }
                    }
                } else {
                    for (idx = 0, length = columns.length; idx < length; idx++) {
                        column = columns[idx];
                        if (column.selectable) {
                            continue;
                        }
                        if (!column.command) {
                            if (!that._isMobile) {
                                html += '<div class="k-edit-label"><label for="' + column.field + '">' + (column.title || column.field || '') + '</label></div>';
                                if (isColumnEditable(column, model)) {
                                    fields.push({
                                        field: column.field,
                                        title: column.title,
                                        format: column.format,
                                        editor: column.editor,
                                        values: column.values
                                    });
                                    html += '<div ' + kendo.attr('container-for') + '="' + column.field + '" class="k-edit-field"></div>';
                                } else {
                                    state = {
                                        storage: {},
                                        count: 0
                                    };
                                    tmpl = kendo.template(that._cellTmpl(column, state), settings);
                                    if (state.count > 0) {
                                        tmpl = proxy(tmpl, state.storage);
                                    }
                                    html += '<div class="k-edit-field">' + tmpl(model) + '</div>';
                                }
                            } else {
                                html += '<li class="k-item">';
                                if (isColumnEditable(column, model)) {
                                    fields.push({
                                        field: column.field,
                                        title: column.title,
                                        format: column.format,
                                        editor: column.editor,
                                        values: column.values
                                    });
                                    html += '<label class="k-label"><span class="k-item-title">' + (column.title || column.field || '') + '</span>';
                                    html += '<div id="' + column.field + '_' + editMenuGuid + '" ' + kendo.attr('container-for') + '="' + column.field + '"></div>';
                                } else {
                                    state = {
                                        storage: {},
                                        count: 0
                                    };
                                    tmpl = kendo.template(that._cellTmpl(column, state), settings);
                                    if (state.count > 0) {
                                        tmpl = proxy(tmpl, state.storage);
                                    }
                                    html += '<label class="k-label k-no-click"><span class="k-item-title">' + (column.title || column.field || '') + '</span>';
                                    html += '<span class="k-no-editor">' + tmpl(model) + '</span>';
                                }
                                html += '</label></li>';
                            }
                        } else if (column.command) {
                            tempCommand = getCommand(column.command, 'edit');
                            if (tempCommand) {
                                command = tempCommand;
                            }
                        }
                    }
                }
                if (command) {
                    if (isPlainObject(command)) {
                        if (isPlainObject(command.text)) {
                            updateText = command.text.update;
                            cancelText = command.text.cancel;
                        }
                        if (isPlainObject(command.iconClass)) {
                            updateIconClass = command.iconClass.update;
                            cancelIconClass = command.iconClass.cancel;
                        }
                        if (command.attr) {
                            attr = command.attr;
                        }
                    }
                }
                var container;
                if (!that._isMobile) {
                    html += '<div class="k-edit-buttons k-state-default">';
                    html += that._createButton({
                        name: 'update',
                        text: updateText,
                        attr: attr,
                        iconClass: updateIconClass
                    }) + that._createButton({
                        name: 'canceledit',
                        text: cancelText,
                        attr: attr,
                        iconClass: cancelIconClass
                    });
                    html += '</div></div></div>';
                    container = that._editContainer = $(html).appendTo(that.wrapper).eq(0).kendoWindow(extend({
                        modal: true,
                        resizable: false,
                        draggable: true,
                        title: that.options.messages.commands.edit || 'Edit',
                        visible: false,
                        close: function (e) {
                            if (e.userTriggered) {
                                e.sender.element.focus();
                                if (that.trigger('cancel', {
                                        container: container,
                                        model: model
                                    })) {
                                    e.preventDefault();
                                    return;
                                }
                                var currentIndex = that.items().index($(that.current()).parent());
                                that._editableIsClosing = true;
                                that.cancelRow();
                                if (that.options.navigatable) {
                                    that._setCurrent(that.items().eq(currentIndex).children().filter(NAVCELL).first());
                                    focusTable(that.table, true);
                                }
                            }
                        }
                    }, options));
                } else {
                    html += '</ul></div>';
                    that.editView = that.pane.append('<div data-' + kendo.ns + 'role="view" class="k-grid-edit-form">' + '<div data-' + kendo.ns + 'role="header" class="k-header">' + '<a href="\\#" class="k-header-cancel k-link k-grid-cancel" title="#=messages.cancel#" ' + 'aria-label="#=messages.cancel#"><span class="k-icon k-i-arrow-chevron-left"></span></a>' + (that.options.messages.commands.edit || 'Edit') + '<a href="\\#" class="k-header-done k-link k-grid-update" title="#=messages.done#" ' + 'aria-label="#=messages.done#"><span class="k-icon k-i-check"></span></a>' + '</div>' + '<div data-' + kendo.ns + 'role="content" class="' + classNames.content + '">' + html + '</div>' + '</div>');
                    container = that._editContainer = that.editView.element.find('.k-popup-edit-form');
                }
                that.editable = that._editContainer.kendoEditable({
                    fields: fields,
                    model: model,
                    clearContainer: false,
                    target: that
                }).data('kendoEditable');
                that._openPopUpEditor();
                that.trigger(EDIT, {
                    container: container,
                    model: model
                });
            },
            _openPopUpEditor: function () {
                var that = this;
                var windowEditor = that._editContainer ? that._editContainer.data('kendoWindow') : null;
                var windowOptions = (that.options.editable || {}).window || {};
                if (!this._isMobile) {
                    if (windowEditor) {
                        if (!windowOptions.position) {
                            windowEditor.center();
                        }
                        windowEditor.open();
                    }
                } else {
                    this.pane.navigate(this.editView, this._editAnimation);
                }
            },
            _createInlineEditor: function (row, model) {
                var that = this;
                var column;
                var cell;
                var command;
                var fields = [];
                if (that.trigger(BEFOREEDIT, { model: model })) {
                    return;
                }
                if (that.lockedContent) {
                    row = row.add(that._relatedRow(row));
                }
                row.children(':not(.k-group-cell,.k-hierarchy-cell)').each(function () {
                    cell = $(this);
                    column = leafColumns(that.columns)[that.cellIndex(cell)];
                    if (!column.command && isColumnEditable(column, model)) {
                        fields.push({
                            field: column.field,
                            title: column.title,
                            format: column.format,
                            editor: column.editor,
                            values: column.values
                        });
                        cell.attr(kendo.attr('container-for'), column.field);
                        cell.empty();
                    } else if (column.command) {
                        command = getCommand(column.command, 'edit');
                        if (command) {
                            cell.empty();
                            var updateText, cancelText, updateIconClass, cancelIconClass, attr;
                            if (isPlainObject(command)) {
                                if (isPlainObject(command.text)) {
                                    updateText = command.text.update;
                                    cancelText = command.text.cancel;
                                }
                                if (isPlainObject(command.iconClass)) {
                                    updateIconClass = command.iconClass.update;
                                    cancelIconClass = command.iconClass.cancel;
                                }
                                if (command.attr) {
                                    attr = command.attr;
                                }
                            }
                            $(that._createButton({
                                name: 'update',
                                text: updateText,
                                attr: attr,
                                iconClass: updateIconClass
                            }) + that._createButton({
                                name: 'canceledit',
                                text: cancelText,
                                attr: attr,
                                iconClass: cancelIconClass
                            })).appendTo(cell);
                        }
                    }
                });
                that._editContainer = row;
                that._editContainer.addClass('k-grid-edit-row');
                if (that._shouldClearEditableState) {
                    that._clearEditableState();
                }
                that.editable = new kendo.ui.Editable(that._editContainer, {
                    target: that,
                    fields: fields,
                    model: model,
                    skipFocus: that._isVirtualInlineEditable() && that._editableState && that._editableState.field ? true : false,
                    clearContainer: false
                });
                if (row.length > 1) {
                    adjustRowHeight(row[0], row[1]);
                    that._applyLockedContainersWidth();
                }
                that.trigger(EDIT, {
                    container: row,
                    model: model
                });
            },
            cancelRow: function (notify) {
                var that = this, container = that._editContainer, model;
                if (container) {
                    model = that._modelForContainer(container);
                    if (!model || notify && that.trigger('cancel', {
                            container: container,
                            model: model
                        })) {
                        return;
                    }
                    that._destroyEditable();
                    that.dataSource.cancelChanges(model);
                    that._clearEditableState();
                    if (that._editMode() !== 'popup') {
                        that._displayRow(container);
                    } else {
                        that._displayRow(that.tbody.find('[' + kendo.attr('uid') + '=' + model.uid + ']'));
                    }
                }
            },
            saveRow: function () {
                var that = this;
                var container = this._editContainer;
                var model = this._modelForContainer(container);
                var deferred = $.Deferred();
                var valid;
                if (!container || !this.editable) {
                    return deferred.resolve().promise();
                }
                valid = that.editable && that.editable.end();
                if (!valid || this.trigger(SAVE, {
                        container: container,
                        model: model
                    })) {
                    if (!valid) {
                        that._scrollVirtualWrapper();
                    }
                    return deferred.reject().promise();
                }
                that._clearEditableState();
                return this.dataSource.sync();
            },
            _displayRow: function (row) {
                var that = this, model = that._modelForContainer(row), related, newRow, nextRow, isSelected = row.hasClass('k-state-selected'), isAlt = row.hasClass('k-alt');
                if (model) {
                    if (that.lockedContent) {
                        related = $((isAlt ? that.lockedAltRowTemplate : that.lockedRowTemplate)(model));
                        that._relatedRow(row.last()).replaceWith(related);
                    }
                    that.angular('cleanup', function () {
                        return { elements: row.get() };
                    });
                    newRow = $((isAlt ? that.altRowTemplate : that.rowTemplate)(model));
                    if (!row.is(':visible')) {
                        newRow.hide();
                    }
                    row.replaceWith(newRow);
                    that.trigger('itemChange', {
                        item: newRow,
                        data: model,
                        ns: ui
                    });
                    if (related && related.length) {
                        that.trigger('itemChange', {
                            item: related,
                            data: model,
                            ns: ui
                        });
                    }
                    var angularElements = newRow;
                    var angularData = [{ dataItem: model }];
                    if (related && related.length) {
                        angularElements = newRow.add(related);
                        angularData.push({ dataItem: model });
                    }
                    that.angular('compile', function () {
                        return {
                            elements: angularElements.get(),
                            data: angularData
                        };
                    });
                    if (isSelected && (that.options.selectable || that._checkBoxSelection)) {
                        that.select(newRow.add(related));
                    }
                    if (related) {
                        adjustRowHeight(newRow[0], related[0]);
                    }
                    nextRow = newRow.next();
                    if (nextRow.hasClass('k-detail-row') && nextRow.is(':visible')) {
                        newRow.find('.k-hierarchy-cell .k-icon').removeClass('k-i-expand').addClass('k-i-collapse');
                    }
                }
            },
            _showMessage: function (messages, row) {
                var that = this;
                if (!that._isMobile) {
                    return window.confirm(messages.title);
                }
                var confirmDialog = that._confirmDialog = new kendo.ui.Confirm($('<div />').appendTo(document.body), {
                    modal: { preventScroll: true },
                    closable: false,
                    title: false,
                    content: messages.title,
                    messages: {
                        okText: messages.confirmDelete,
                        cancel: messages.cancelDelete
                    },
                    open: function () {
                        that.content.data(OVERFLOW, that.content.css(OVERFLOW));
                        that.content.css(OVERFLOW, HIDDEN);
                    },
                    close: function () {
                        that.content.css(OVERFLOW, that.content.data(OVERFLOW));
                    }
                });
                confirmDialog.result.done(function () {
                    that._removeRow(row);
                }).fail(function () {
                    var confirmDialog = that._confirmDialog;
                    if (confirmDialog) {
                        confirmDialog.close();
                        confirmDialog.destroy();
                    }
                });
                return false;
            },
            _confirmation: function (row) {
                var that = this, editable = that.options.editable, confirmation = editable === true || typeof editable === STRING ? that.options.messages.editable.confirmation : editable.confirmation;
                if (isPlainObject(editable) && typeof editable.mode === STRING && typeof confirmation !== FUNCTION && typeof confirmation !== STRING && confirmation !== false) {
                    confirmation = that.options.messages.editable.confirmation;
                }
                if (confirmation !== false && confirmation != null) {
                    if (typeof confirmation === FUNCTION) {
                        confirmation = confirmation(that._modelForContainer(row));
                    }
                    return that._showMessage({
                        confirmDelete: editable.confirmDelete || that.options.messages.editable.confirmDelete,
                        cancelDelete: editable.cancelDelete || that.options.messages.editable.cancelDelete,
                        title: confirmation === true ? that.options.messages.editable.confirmation : confirmation
                    }, row);
                }
                return true;
            },
            cancelChanges: function () {
                var that = this;
                that.dataSource.cancelChanges();
                if (that._isVirtualEditable()) {
                    that._virtualPageToTop(function () {
                        that.virtualScrollable.scrollToTop();
                    });
                }
            },
            saveChanges: function () {
                var that = this;
                var valid = that.editable && that.editable.end();
                if ((valid || !that.editable) && !that.trigger(SAVECHANGES)) {
                    that.dataSource.sync();
                } else if (!valid) {
                    that._scrollVirtualWrapper();
                }
            },
            addRow: function () {
                var that = this, index, dataSource = that.dataSource, mode = that._editMode(), createAt = that.options.editable.createAt || '', pageSize = dataSource.pageSize(), view = dataSource.view() || [];
                var createAtBottom = createAt.toLowerCase() === BOTTOM;
                var model;
                var virtualEditable = that._isVirtualEditable();
                if (that.editable && that.editable.end() || !that.editable) {
                    if (mode != 'incell') {
                        that.cancelRow();
                    }
                    index = dataSource.indexOf(view[0]);
                    if (createAtBottom) {
                        index += view.length;
                        if (pageSize && !dataSource.options.serverPaging && pageSize <= view.length) {
                            index -= 1;
                        }
                    }
                    if (index < 0) {
                        if (dataSource.page() > dataSource.totalPages()) {
                            index = (dataSource.page() - 1) * pageSize;
                        } else {
                            index = 0;
                        }
                    }
                    if (that.options.navigatable && mode == 'incell') {
                        that._removeCurrent();
                    }
                    if (virtualEditable) {
                        that._virtualAddRow();
                    } else {
                        model = dataSource.insert(index, {});
                        that._editModel(model);
                    }
                } else {
                    that._scrollVirtualWrapper();
                }
            },
            _editModel: function (model) {
                var that = this;
                var createAt = that.options.editable.createAt || '';
                var mode = that._editMode();
                if (model) {
                    var id = model.uid, table = that.lockedContent ? that.lockedTable : that.table, row = table.find('tr[' + kendo.attr('uid') + '=' + id + ']'), cell = row.children('td:not(.k-group-cell,.k-hierarchy-cell)').eq(that._firstEditableColumnIndex(row));
                    if (mode === 'inline' && row.length) {
                        that.editRow(row);
                    } else if (mode === 'popup') {
                        that.editRow(model);
                    } else if (cell.length) {
                        that.editCell(cell);
                    }
                    if (createAt.toLowerCase() == 'bottom' && that.lockedContent) {
                        that.lockedContent[0].scrollTop = that.content[0].scrollTop = that.table[0].offsetHeight;
                    }
                }
            },
            _virtualAddRow: function () {
                var that = this;
                var createAtBottom = (that.options.editable.createAt || '').toLowerCase() === BOTTOM;
                that._clearEditableState();
                if (createAtBottom) {
                    that._virtualAddRowAtBottom();
                } else {
                    that._virtualAddRowAtTop();
                }
            },
            _virtualAddRowAtTop: function () {
                var that = this;
                var dataSource = that.dataSource;
                var virtualScrollable = that.virtualScrollable;
                var model;
                if (dataSource.page() === 1) {
                    model = dataSource.insert(0, {});
                    that._editModel(model);
                    virtualScrollable.scrollToTop();
                } else {
                    that._virtualPageToTop(function () {
                        model = dataSource.insert(0, {});
                        that._editModel(model);
                        virtualScrollable.scrollToTop();
                    });
                }
            },
            _virtualAddRowAtBottom: function () {
                var that = this;
                var dataSource = that.dataSource;
                var virtualScrollable = that.virtualScrollable;
                var index = dataSource.total();
                var model;
                if (dataSource.at(index - 1) instanceof ObservableObject) {
                    model = dataSource.insert(index, {});
                    that._virtualPageToBottom(function () {
                        that._editModel(model);
                        virtualScrollable.scrollToBottom();
                    });
                } else {
                    that._virtualPageToBottom(function () {
                        model = dataSource.insert(index, {});
                        that._editModel(model);
                        virtualScrollable.scrollToBottom();
                    });
                }
            },
            _virtualPageToTop: function (callback) {
                var that = this;
                that._virtualPage(0, that.dataSource.take(), function () {
                    callback();
                });
            },
            _virtualPageToBottom: function (callback) {
                var that = this;
                var dataSource = that.dataSource;
                var take = dataSource.take();
                var total = dataSource.total();
                var skip = total > take ? total - take : 0;
                that._virtualPage(skip, take, function () {
                    callback();
                });
            },
            _virtualPage: function (skip, take, callback) {
                var that = this;
                if (that._isVirtualEditable()) {
                    that.virtualScrollable._preventScroll = true;
                    that.virtualScrollable._page(skip, take, callback);
                }
            },
            _firstEditableColumnIndex: function (container) {
                var that = this, column, columns = leafColumns(that.columns), idx, length, model = that._modelForContainer(container);
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    column = columns[idx];
                    if (model && (!model.editable || model.editable(column.field)) && !column.command && column.field && column.hidden !== true) {
                        return idx;
                    }
                }
                return -1;
            },
            _toolbar: function () {
                var that = this, wrapper = that.wrapper, toolbar = that.options.toolbar, editable = that.options.editable, container;
                if (toolbar) {
                    container = that.wrapper.find('.k-grid-toolbar');
                    if (!container.length) {
                        if (!isFunction(toolbar)) {
                            toolbar = typeof toolbar === STRING ? toolbar : that._toolbarTmpl(toolbar).replace(templateHashRegExp, '\\#');
                            toolbar = proxy(kendo.template(toolbar), that);
                        }
                        container = $('<div class="k-header k-grid-toolbar" />').html(toolbar({})).prependTo(wrapper);
                        that.angular('compile', function () {
                            return { elements: container.get() };
                        });
                    }
                    if (editable && editable.create !== false) {
                        container.on(CLICK + NS, '.k-grid-add', function (e) {
                            e.preventDefault();
                            that.addRow();
                        }).on(CLICK + NS, '.k-grid-cancel-changes', function (e) {
                            e.preventDefault();
                            that.cancelChanges();
                        }).on(CLICK + NS, '.k-grid-save-changes', function (e) {
                            e.preventDefault();
                            that.saveChanges();
                        });
                    }
                    container.on(CLICK + NS, '.k-grid-excel', function (e) {
                        e.preventDefault();
                        that.saveAsExcel();
                    });
                    container.on(CLICK + NS, '.k-grid-pdf', function (e) {
                        e.preventDefault();
                        that.saveAsPDF();
                    });
                }
            },
            _toolbarTmpl: function (commands) {
                var that = this, idx, length, html = '';
                if (isArray(commands)) {
                    for (idx = 0, length = commands.length; idx < length; idx++) {
                        html += that._createButton(commands[idx]);
                    }
                }
                return html;
            },
            _createButton: function (command) {
                var template = command.template || COMMANDBUTTONTMPL, commandName = typeof command === STRING ? command : command.name || command.text, className = defaultCommands[commandName] ? defaultCommands[commandName].className : 'k-grid-' + (commandName || '').replace(/\s/g, ''), options = {
                        className: className,
                        text: commandName,
                        attr: '',
                        iconClass: ''
                    }, messages = this.options.messages.commands, attributeClassMatch;
                if (!commandName && !(isPlainObject(command) && command.template)) {
                    throw new Error('Custom commands should have name specified');
                }
                if (isPlainObject(command)) {
                    command = extend(true, {}, command);
                    if (command.className && inArray(options.className, command.className.split(' ')) < 0) {
                        command.className += ' ' + options.className;
                    } else if (command.className === undefined) {
                        command.className = options.className;
                    }
                    if (commandName === 'edit') {
                        command = extend(true, {}, command);
                        command.text = isPlainObject(command.text) ? command.text.edit : command.text;
                        command.iconClass = isPlainObject(command.iconClass) ? command.iconClass.edit : command.iconClass;
                    }
                    if (command.attr) {
                        if (isPlainObject(command.attr)) {
                            command.attr = stringifyAttributes(command.attr);
                        }
                        if (typeof command.attr === STRING) {
                            attributeClassMatch = command.attr.match(/class="(.+?)"/);
                            if (attributeClassMatch && inArray(attributeClassMatch[1], command.className.split(' ')) < 0) {
                                command.className += ' ' + attributeClassMatch[1];
                            }
                        }
                    }
                    options = extend(true, options, defaultCommands[commandName], { text: messages[commandName] }, command);
                } else {
                    options = extend(true, options, defaultCommands[commandName], { text: messages[commandName] });
                }
                return kendo.template(template)(options);
            },
            _hasFooters: function () {
                return !!this.footerTemplate || !!this.groupFooterTemplate || this.footer && this.footer.length > 0 || this.wrapper.find('.k-grid-footer').length > 0;
            },
            _groupable: function () {
                var that = this;
                if (that._groupableClickHandler) {
                    that.table.add(that.lockedTable).off(CLICK + NS, that._groupableClickHandler);
                } else {
                    that._groupableClickHandler = function (e) {
                        var element = $(this), groupRow = element.closest('tr');
                        var group = that._groupRows ? that._groupRows[that.wrapper.find('.k-grouping-row').index(groupRow)] : {};
                        if (element.hasClass('k-i-collapse')) {
                            if (!that.trigger('groupCollapse', {
                                    group: group,
                                    element: groupRow
                                })) {
                                that.collapseGroup(groupRow);
                            }
                        } else {
                            if (!that.trigger('groupExpand', {
                                    group: group,
                                    element: groupRow
                                })) {
                                that.expandGroup(groupRow);
                            }
                        }
                        e.preventDefault();
                        e.stopPropagation();
                    };
                }
                if (that._isLocked()) {
                    that.lockedTable.on(CLICK + NS, '.k-grouping-row .k-i-expand, .k-grouping-row .k-i-collapse', that._groupableClickHandler);
                } else {
                    that.table.on(CLICK + NS, '.k-grouping-row .k-i-expand, .k-grouping-row .k-i-collapse', that._groupableClickHandler);
                }
                that._attachGroupable();
            },
            _attachGroupable: function () {
                var that = this, wrapper = that.wrapper, groupable = that.options.groupable, draggables = HEADERCELLS + '[' + kendo.attr('field') + ']', filter = that.content ? '.k-grid-header:first ' + draggables : 'table:first>.k-grid-header ' + draggables;
                if (groupable && groupable.enabled !== false) {
                    if (!wrapper.has('div.k-grouping-header')[0]) {
                        $('<div>&nbsp;</div>').addClass('k-grouping-header').prependTo(wrapper);
                    }
                    if (that.groupable) {
                        that._destroyGroupable();
                    }
                    that.groupable = new ui.Groupable(wrapper, extend({}, groupable, {
                        draggable: that._draggableInstance,
                        groupContainer: '>div.k-grouping-header',
                        dataSource: that.dataSource,
                        draggableElements: filter,
                        filter: filter,
                        allowDrag: that.options.reorderable,
                        change: function (e) {
                            if (that.trigger('group', { groups: e.groups })) {
                                e.preventDefault();
                            } else {
                                that._clearEditableState();
                                if (that.dataSource.options.endless) {
                                    that.dataSource.options.endless = null;
                                    that._endlessPageSize = that.dataSource.options.pageSize;
                                    that.dataSource._skip = 0;
                                    that.dataSource._pageSize = that.dataSource._take = that._endlessPageSize;
                                    that.dataSource._page = 1;
                                }
                            }
                        }
                    }));
                    that._addGroupableOptionsToHeader();
                }
            },
            _addGroupableOptionsToHeader: function () {
                var that = this;
                var columns = flatColumns(that.columns);
                var columnFieldMap = {};
                var field = '';
                var headerCells = that._headerCells();
                var cellFieldAttr = '';
                var headerCell;
                var columnOptions;
                var i;
                for (i = 0; i < columns.length; i++) {
                    field = columns[i].field;
                    columnFieldMap[columns[i].field] = columns[i];
                }
                for (i = 0; i < headerCells.length; i++) {
                    headerCell = headerCells.eq(i);
                    cellFieldAttr = headerCell.attr(kendo.attr(FIELD));
                    columnOptions = columnFieldMap[cellFieldAttr];
                    if (columnOptions && columnOptions.groupable && columnOptions.groupable.sort) {
                        headerCell.data(GROUP_SORT, columnOptions.groupable.sort);
                    }
                }
            },
            _destroyGroupable: function () {
                var that = this;
                if (that.groupable && that.groupable.element) {
                    that.groupable.element.kendoGroupable('destroy');
                }
                that.groupable = null;
                that._removeGroupableOptionsFromHeader();
            },
            _removeGroupableOptionsFromHeader: function () {
                var that = this;
                var headerCells = that._headerCells();
                for (var i = 0; i < headerCells.length; i++) {
                    headerCells.eq(i).removeData(GROUP_SORT);
                }
            },
            _continuousItems: function (filter, cell) {
                if (!this.lockedContent) {
                    return;
                }
                var that = this;
                var elements = that.table.add(that.lockedTable);
                var lockedItems = $(filter, elements[0]);
                var nonLockedItems = $(filter, elements[1]);
                var columns = cell ? lockedColumns(that.columns).length : 1;
                var nonLockedColumns = cell ? that.columns.length - columns : 1;
                var result = [];
                for (var idx = 0; idx < lockedItems.length; idx += columns) {
                    push.apply(result, lockedItems.slice(idx, idx + columns));
                    push.apply(result, nonLockedItems.splice(0, nonLockedColumns));
                }
                return result;
            },
            _selectable: function () {
                var that = this, multi, cell, notString = [], isLocked = that._isLocked(), selectable = that.options.selectable;
                if (selectable) {
                    if (that.selectable) {
                        that.selectable.destroy();
                    }
                    that._selectedIds = {};
                    selectable = kendo.ui.Selectable.parseOptions(selectable);
                    multi = selectable.multiple;
                    cell = selectable.cell;
                    if (that._hasDetails()) {
                        notString[notString.length] = '.k-detail-row';
                    }
                    if (that.options.groupable || that._hasFooters() || that._groups()) {
                        notString[notString.length] = '.k-grouping-row,.k-group-footer';
                    }
                    notString = notString.join(',');
                    if (notString !== '') {
                        notString = ':not(' + notString + ')';
                    }
                    var elements = that.table;
                    if (isLocked) {
                        elements = elements.add(that.lockedTable);
                    }
                    var filter = '>' + (cell ? SELECTION_CELL_SELECTOR : 'tbody>tr' + notString);
                    that.selectable = new kendo.ui.Selectable(elements, {
                        filter: filter,
                        aria: true,
                        multiple: multi,
                        change: function () {
                            var selectedValues;
                            if (!cell) {
                                that._persistSelectedRows();
                            }
                            if (that._checkBoxSelection) {
                                selectedValues = that.selectable.value();
                                that._uncheckCheckBoxes();
                                that._checkRows(selectedValues);
                                if (selectedValues.length && selectedValues.length === that.items().length) {
                                    that._toggleHeaderCheckState(true);
                                } else {
                                    that._toggleHeaderCheckState(false);
                                }
                            }
                            that.trigger(CHANGE);
                        },
                        useAllItems: isLocked && multi && cell,
                        relatedTarget: function (items) {
                            if (cell || !isLocked) {
                                return;
                            }
                            var related;
                            var result = $();
                            for (var idx = 0, length = items.length; idx < length; idx++) {
                                related = that._relatedRow(items[idx]);
                                if (inArray(related[0], items) < 0) {
                                    result = result.add(related);
                                }
                            }
                            return result;
                        },
                        continuousItems: function () {
                            return that._continuousItems(filter, cell);
                        }
                    });
                    if (that.options.navigatable) {
                        elements.on('keydown' + NS, function (e) {
                            var current = that.current();
                            var target = e.target;
                            if (e.keyCode === keys.SPACEBAR && !e.shiftKey && $.inArray(target, elements) > -1 && !current.is('.k-edit-cell,.k-header') && current.parent().is(':not(.k-grouping-row,.k-detail-row,.k-group-footer)')) {
                                e.preventDefault();
                                e.stopPropagation();
                                current = cell ? current : current.parent();
                                if (isLocked && !cell) {
                                    current = current.add(that._relatedRow(current));
                                }
                                if (multi) {
                                    if (!e.ctrlKey) {
                                        that.selectable.clear();
                                    } else {
                                        if (current.hasClass(SELECTED)) {
                                            that._deselectCheckRows(current);
                                            return;
                                        }
                                    }
                                } else {
                                    that.selectable.clear();
                                }
                                if (!cell) {
                                    that.selectable._lastActive = current;
                                }
                                that.selectable.value(current);
                            } else if (!cell && ($(target).is('td') || $(target).is('table') && inArray(target, this._navigatableTables)) && (e.shiftKey && e.keyCode == keys.LEFT || e.shiftKey && e.keyCode == keys.RIGHT || e.shiftKey && e.keyCode == keys.UP || e.shiftKey && e.keyCode == keys.DOWN || e.keyCode === keys.SPACEBAR && e.shiftKey)) {
                                e.preventDefault();
                                e.stopPropagation();
                                current = current.parent();
                                if (isLocked) {
                                    current = current.add(that._relatedRow(current));
                                }
                                if (multi) {
                                    if (!that.selectable._lastActive) {
                                        that.selectable._lastActive = current;
                                    }
                                    that.selectable.selectRange(that.selectable._firstSelectee(), current);
                                } else {
                                    that.selectable.clear();
                                    that.selectable.value(current);
                                }
                            }
                        });
                    }
                }
            },
            _clipboard: function () {
                var options = this.options;
                var selectable = options.selectable;
                if (selectable && options.allowCopy) {
                    var grid = this;
                    if (!options.navigatable) {
                        grid.table.add(grid.lockedTable).attr('tabindex', 0).on('mousedown' + NS + ' keydown' + NS, '.k-detail-cell', function (e) {
                            if (e.target !== e.currentTarget) {
                                e.stopImmediatePropagation();
                            }
                        }).on('mousedown' + NS, NAVROW + '>' + NAVCELL, proxy(tableClick, grid));
                    }
                    grid.copyHandler = proxy(grid.copySelection, grid);
                    grid.updateClipBoardState = function () {
                        if (grid.areaClipBoard) {
                            grid.areaClipBoard.val(grid.getTSV()).focus().select();
                        }
                    };
                    grid.bind('change', grid.updateClipBoardState);
                    grid.wrapper.on('keydown', grid.copyHandler);
                    grid.clearAreaHandler = proxy(grid.clearArea, grid);
                    grid.wrapper.on('keyup', grid.clearAreaHandler);
                }
            },
            copySelection: function (e) {
                if (e instanceof jQuery.Event && !(e.ctrlKey || e.metaKey) || $(e.target).is('input:visible,textarea:visible') || window.getSelection && window.getSelection().toString() || document.selection && document.selection.createRange().text) {
                    return;
                }
                if (!this.areaClipBoard) {
                    this.areaClipBoard = $('<textarea />').css({
                        position: 'fixed',
                        top: '50%',
                        left: '50%',
                        opacity: 0,
                        width: 0,
                        height: 0
                    }).appendTo(this.wrapper);
                }
                this.areaClipBoard.val(this.getTSV()).focus().select();
            },
            getTSV: function () {
                var grid = this;
                var selected = grid.select();
                var delimeter = '\t';
                var allowCopy = grid.options.allowCopy;
                var onlyVisible = true;
                if ($.isPlainObject(allowCopy) && allowCopy.delimeter) {
                    delimeter = allowCopy.delimeter;
                }
                var text = '';
                if (selected.length) {
                    if (selected.eq(0).is('tr')) {
                        selected = selected.find('td:not(.k-group-cell)');
                    }
                    if (onlyVisible) {
                        selected.filter(':visible');
                    }
                    var result = [];
                    var cellsOffset = this.columns.length;
                    var lockedCols = grid._isLocked() && lockedColumns(grid.columns).length;
                    var inLockedArea = true;
                    $.each(selected, function (idx, cell) {
                        cell = $(cell);
                        var tr = cell.closest('tr');
                        var rowIndex = tr.index();
                        var cellIndex = cell.index();
                        if (onlyVisible) {
                            cellIndex -= cell.prevAll(':hidden').length;
                        }
                        if (lockedCols && inLockedArea) {
                            inLockedArea = $.contains(grid.lockedTable[0], cell[0]);
                        }
                        if (grid._groups() && inLockedArea) {
                            cellIndex -= grid._groups();
                        }
                        cellIndex = inLockedArea ? cellIndex : cellIndex + lockedCols;
                        if (cellsOffset > cellIndex) {
                            cellsOffset = cellIndex;
                        }
                        var cellText = cell.text();
                        if (!result[rowIndex]) {
                            result[rowIndex] = [];
                        }
                        result[rowIndex][cellIndex] = cellText;
                    });
                    var rowsOffset = result.length;
                    result = $.each(result, function (idx, val) {
                        if (val) {
                            result[idx] = val.slice(cellsOffset);
                            if (rowsOffset > idx) {
                                rowsOffset = idx;
                            }
                        }
                    });
                    $.each(result.slice(rowsOffset), function (idx, val) {
                        if (val) {
                            text += val.join(delimeter) + '\r\n';
                        } else {
                            text += '\r\n';
                        }
                    });
                }
                return text;
            },
            clearArea: function (e) {
                var table;
                if (this.areaClipBoard && e && e.target === this.areaClipBoard[0]) {
                    if (this.options.navigatable) {
                        table = $(this.current()).closest('table');
                    } else {
                        table = this.table;
                    }
                    focusTable(table, true);
                }
                if (this.areaClipBoard) {
                    this.areaClipBoard.remove();
                    this.areaClipBoard = null;
                }
            },
            _adaptiveColumns: function () {
                var that = this;
                if (that._anyColumnHasMediaQuery()) {
                    that._setColumnsMediaVisibility(that.columns);
                    that._attachColumnMediaResizeHandler();
                }
            },
            _anyColumnHasMediaQuery: function () {
                return this._columnsWithMediaQuery().length;
            },
            _columnsWithMediaQuery: function () {
                return columnsWithMedia(this.columns);
            },
            _attachColumnMediaResizeHandler: function () {
                var that = this;
                that._detachColumnMediaResizeHandler();
                that._columnMediaResizeHandler = proxy(that._onColumnMediaResize, that);
                $(window).on(RESIZE + NS, that._columnMediaResizeHandler);
            },
            _detachColumnMediaResizeHandler: function () {
                var that = this;
                if (that._columnMediaResizeHandler) {
                    $(window).off(RESIZE + NS, that._columnMediaResizeHandler);
                }
            },
            _onColumnMediaResize: function () {
                var that = this;
                that._setColumnsMediaVisibility(that.columns);
                that._setContentMediaWidth();
            },
            _setColumnsMediaVisibility: function (columns) {
                var cols = columns || [];
                for (var i = 0; i < cols.length; i++) {
                    this._setColumnMediaVisibility(cols[i]);
                }
            },
            _setColumnMediaVisibility: function (column) {
                var that = this;
                if (isUndefined(column.media)) {
                    that._setColumnsMediaVisibility(column.columns);
                } else {
                    if (columnMatchesMedia(column)) {
                        that._showColumnByMedia(column);
                        if (!column.hidden) {
                            that._setColumnsMediaVisibility(column.columns);
                        }
                    } else {
                        that._hideColumnByMedia(column);
                    }
                }
            },
            _showColumnByMedia: function (column) {
                if (!column.hidden) {
                    this.showColumn(column);
                }
                setColumnMatchesMedia(column);
            },
            _hideColumnByMedia: function (column) {
                var initiallyHidden = column.hidden;
                if (!initiallyHidden) {
                    column._hideByMedia = true;
                    this.hideColumn(column);
                    column._hideByMedia = false;
                    column.hidden = initiallyHidden;
                }
                setColumnMatchesMedia(column);
            },
            _setContentMediaWidth: function () {
                var that = this;
                var options = that.options;
                var isLocked = that._isLocked();
                var footer;
                if (options.scrollable && options.resizable) {
                    if (isLocked && that.lockedFooter) {
                        footer = that.lockedFooter.children('table');
                    } else if (that.footer) {
                        footer = that.footer.find('>.k-grid-footer-wrap>table');
                    }
                    if (!footer || !footer[0]) {
                        footer = $();
                    }
                    var header = isLocked ? that.wrapper.find('.k-grid-header-locked').find('table') : that.wrapper.find('.k-grid-header').find('table');
                    var contentTable = isLocked ? that.lockedTable : that.table;
                    var headerColumns = header.find('th');
                    var headerColgroup = header.find('colgroup');
                    var headerColumnsCount = headerColumns.length;
                    var visibleHeaderColumnsCount = headerColumns.filter(isCellVisible).length;
                    var hiddenHeaderColumnsCount = headerColumns.length - visibleHeaderColumnsCount;
                    var totalHeaderWidth = 0;
                    if (header[0].style.width !== '' && parseFloat(header[0].style.width) !== totalHeaderWidth) {
                        var currentHeaderWidth = header.css('width');
                        for (var i = 0; i < headerColumnsCount; i++) {
                            if (isElementVisible(headerColumns[i])) {
                                var columnWidth;
                                var cellIndex = Math.max(i, i - hiddenHeaderColumnsCount);
                                var colgroupChild = headerColgroup.children()[cellIndex];
                                var columnStyleWidth = colgroupChild ? colgroupChild.style.width : '';
                                if (columnStyleWidth !== '') {
                                    columnWidth = parseFloat(columnStyleWidth);
                                } else {
                                    header.css('width', 'auto');
                                    columnWidth = outerWidth(headerColumns.eq(i));
                                    header.css('width', currentHeaderWidth);
                                }
                                totalHeaderWidth += columnWidth;
                            }
                        }
                        contentTable.css('width', totalHeaderWidth - 1);
                        header.css('width', totalHeaderWidth);
                        footer.css('width', totalHeaderWidth);
                    }
                }
            },
            _minScreenSupport: function () {
                var any = this.hideMinScreenCols();
                if (any) {
                    this.minScreenResizeHandler = proxy(this.hideMinScreenCols, this);
                    $(window).on('resize', this.minScreenResizeHandler);
                }
            },
            hideMinScreenCols: function () {
                var cols = this.columns, screenWidth = window.innerWidth > 0 ? window.innerWidth : screen.width;
                return this._iterateMinScreenCols(cols, screenWidth);
            },
            _iterateMinScreenCols: function (cols, screenWidth) {
                var any = false;
                for (var i = 0; i < cols.length; i++) {
                    var col = cols[i];
                    var minWidth = col.minScreenWidth;
                    if (minWidth !== undefined && minWidth !== null) {
                        any = true;
                        if (minWidth > screenWidth) {
                            this.hideColumn(col);
                        } else {
                            this.showColumn(col);
                        }
                    }
                    if (!col.hidden && col.columns) {
                        any = this._iterateMinScreenCols(col.columns, screenWidth) || any;
                    }
                }
                return any;
            },
            _relatedRow: function (row) {
                var lockedTable = this.lockedTable;
                row = $(row);
                if (!lockedTable) {
                    return row;
                }
                var table = row.closest(this.table.add(this.lockedTable));
                var index = table.find('>tbody>tr').index(row);
                table = table[0] === this.table[0] ? lockedTable : this.table;
                return table.find('>tbody>tr').eq(index);
            },
            _relatedCell: function (cell) {
                var lockedTable = this.lockedTable;
                cell = $(cell);
                if (!lockedTable) {
                    return cell;
                }
                var table = cell.closest(this.table.add(this.lockedTable));
                var index = table.find('>tbody>tr>td').index(cell);
                table = table[0] === this.table[0] ? lockedTable : this.table;
                return table.find('>tbody>tr>td').index(index);
            },
            clearSelection: function () {
                var that = this;
                if (that.selectable && !that._checkBoxSelection) {
                    that.selectable.clear();
                }
                if (that._checkBoxSelection) {
                    that._deselectCheckRows(that.select());
                    return;
                }
                if (that.options.persistSelection) {
                    that._persistSelectedRows();
                } else {
                    that._selectedIds = {};
                }
                that.trigger(CHANGE);
            },
            select: function (items) {
                var that = this, selectable = that.selectable, selectableoptions = kendo.ui.Selectable.parseOptions(this.options.selectable), cell = selectableoptions.cell;
                items = that.table.add(that.lockedTable).find(items);
                if (items.length) {
                    if (selectable && !selectable.options.multiple) {
                        selectable.clear();
                        items = items.first();
                    }
                    if (that._isLocked()) {
                        items = items.add(items.map(function () {
                            if (cell) {
                                return that._relatedCell(this);
                            } else {
                                return that._relatedRow(this);
                            }
                        }));
                    }
                    if (selectable && !that._checkBoxSelection) {
                        selectable.value(items);
                    } else {
                        that._checkRows(items);
                        if (that.select().length === that.items().length) {
                            that._toggleHeaderCheckState(true);
                        }
                        if (!cell) {
                            that._persistSelectedRows();
                        }
                        that.trigger(CHANGE);
                    }
                    return;
                }
                return selectable ? selectable.value() : that.items().filter('.' + SELECTED);
            },
            _toggleHeaderCheckState: function (checked) {
                var that = this;
                if (checked) {
                    that.thead.add(that.lockedHeader).find('tr ' + CHECKBOXINPUT).prop('checked', true).attr('aria-checked', true).attr('aria-label', 'Deselect all rows');
                } else {
                    that.thead.add(that.lockedHeader).find('tr ' + CHECKBOXINPUT).prop('checked', false).attr('aria-checked', false).attr('aria-label', 'Select all rows');
                }
            },
            _uncheckCheckBoxes: function () {
                var that = this;
                var tables = that.table.add(that.lockedTable);
                tables.find('tbody ' + CHECKBOXINPUT).attr('aria-checked', false).prop('checked', false).attr('aria-label', 'Select row');
            },
            _deselectCheckRows: function (items) {
                var that = this;
                items = that.table.add(that.lockedTable).find(items);
                if (that._isLocked()) {
                    items = items.add(items.map(function () {
                        return that._relatedRow(this);
                    }));
                }
                items.each(function () {
                    $(this).removeClass(SELECTED).find(CHECKBOXINPUT).attr('aria-checked', false).prop('checked', false).attr('aria-label', 'Select row');
                });
                that._toggleHeaderCheckState(false);
                that._persistSelectedRows();
                that.trigger(CHANGE);
            },
            _checkRows: function (items) {
                items.each(function () {
                    $(this).addClass(SELECTED).find(CHECKBOXINPUT).prop('checked', true).attr('aria-label', 'Deselect row').attr('aria-checked', true);
                });
            },
            _persistSelectedRows: function () {
                var that = this, key, dataItem, allRows = that.items(), dataSourceOptions = that.dataSource.options, schema = dataSourceOptions.schema, modelId, selectedViewIds = {};
                if (!schema || !schema.model || !that._data) {
                    return;
                }
                modelId = isFunction(schema.model) ? schema.model.fn.idField : schema.model.id;
                if (!modelId) {
                    return;
                }
                that.select().each(function () {
                    dataItem = that.dataItem(this);
                    selectedViewIds[dataItem[modelId]] = true;
                });
                for (var i = 0; i < allRows.length; i++) {
                    dataItem = that.dataItem(allRows[i]);
                    key = dataItem[modelId];
                    if (selectedViewIds[key]) {
                        that._selectedIds[key] = true;
                    } else {
                        delete that._selectedIds[key];
                    }
                }
            },
            selectedKeyNames: function () {
                var that = this, ids = [];
                for (var property in that._selectedIds) {
                    ids.push(property);
                }
                ids.sort();
                return ids;
            },
            _updateCurrentAttr: function (current, next) {
                var headerId = $(current).data('headerId');
                $(current).removeClass(FOCUSED).closest('table').removeAttr('aria-activedescendant');
                if (headerId) {
                    headerId = headerId.replace(this._cellId, '');
                    $(current).attr('id', headerId);
                } else {
                    $(current).removeAttr('id');
                }
                next.data('headerId', next.attr('id')).attr('id', this._cellId).addClass(FOCUSED).closest('table').attr('aria-activedescendant', this._cellId);
                this._current = next;
            },
            _scrollCurrent: function () {
                var current = this._current;
                var scrollable = this.options.scrollable;
                if (!current || !scrollable) {
                    return;
                }
                var row = current.parent();
                var tableContainer = row.closest('table').parent();
                var isInLockedContainer = tableContainer.is('.k-grid-content-locked,.k-grid-header-locked');
                var isInContent = tableContainer.is('.k-grid-content-locked,.k-grid-content,.k-virtual-scrollable-wrap');
                var scrollableContainer = $(this.content).find('>.k-virtual-scrollable-wrap').addBack().last()[0];
                if (isInContent) {
                    if (scrollable.virtual) {
                        var rowIndex = Math.max(inArray(row[0], this._items(row.parent())), 0);
                        this._rowVirtualIndex = this.virtualScrollable.itemIndex(rowIndex);
                        this.virtualScrollable.scrollIntoView(row);
                    } else {
                        this._scrollTo(this._relatedRow(row)[0], scrollableContainer);
                    }
                }
                if (this.lockedContent) {
                    this.lockedContent[0].scrollTop = scrollableContainer.scrollTop;
                }
                if (!isInLockedContainer) {
                    this._scrollTo(current[0], scrollableContainer);
                }
            },
            current: function (next) {
                return this._setCurrent(next, true);
            },
            _setCurrent: function (next, preventTrigger, preventScroll) {
                var current = this._current;
                next = $(next);
                if (next.length) {
                    if (!current || current[0] !== next[0]) {
                        this._updateCurrentAttr(current, next);
                        if (!preventScroll) {
                            this._scrollCurrent();
                        }
                        if (!preventTrigger) {
                            this.trigger(NAVIGATE, { element: next });
                        }
                    }
                }
                if (next && next.length) {
                    this._lastCellIndex = next.parent().children(DATA_CELL).index(next);
                }
                return this._current;
            },
            _removeCurrent: function () {
                if (this._current) {
                    this._current.removeClass(FOCUSED);
                    this._current = null;
                }
            },
            _scrollTo: function (element, container) {
                var elementToLowercase = element.tagName.toLowerCase();
                var isHorizontal = elementToLowercase === 'td' || elementToLowercase === 'th';
                var elementOffset = element[isHorizontal ? 'offsetLeft' : 'offsetTop'];
                var elementOffsetDir = element[isHorizontal ? 'offsetWidth' : 'offsetHeight'];
                var containerScroll = container[isHorizontal ? 'scrollLeft' : 'scrollTop'];
                var containerOffsetDir = container[isHorizontal ? 'clientWidth' : 'clientHeight'];
                var bottomDistance = elementOffset + elementOffsetDir;
                var result = 0;
                var ieCorrection = 0;
                var firefoxCorrection = 0;
                if (isRtl && isHorizontal) {
                    var table = $(element).closest('table')[0];
                    if (browser.msie) {
                        ieCorrection = table.offsetLeft;
                    } else if (browser.mozilla) {
                        firefoxCorrection = table.offsetLeft - kendo.support.scrollbar();
                    }
                }
                containerScroll = Math.abs(containerScroll + ieCorrection - firefoxCorrection);
                if (containerScroll > elementOffset) {
                    result = elementOffset;
                } else if (bottomDistance > containerScroll + containerOffsetDir) {
                    if (elementOffsetDir <= containerOffsetDir) {
                        result = bottomDistance - containerOffsetDir;
                    } else {
                        result = elementOffset;
                    }
                } else {
                    result = containerScroll;
                }
                result = Math.abs(result + ieCorrection) + firefoxCorrection;
                container[isHorizontal ? 'scrollLeft' : 'scrollTop'] = result;
            },
            _navigatable: function () {
                var that = this;
                if (!that.options.navigatable) {
                    return;
                }
                var dataTables = that.table.add(that.lockedTable);
                var headerTables = that.thead.parent().add($('>table', that.lockedHeader));
                var tables = dataTables;
                if (that.options.scrollable) {
                    tables = tables.add(headerTables);
                    headerTables.attr(TABINDEX, -1);
                }
                this._navigatableTables = tables;
                tables.off('mousedown' + NS + ' focus' + NS + ' focusout' + NS + ' keydown' + NS);
                headerTables.on('keydown' + NS, proxy(that._openHeaderMenu, that)).find('a.k-link').attr('tabIndex', -1);
                dataTables.attr(TABINDEX, math.max(dataTables.attr(TABINDEX) || 0, 0)).on('keydown' + NS, '.k-detail-cell', function (e) {
                    if (e.target !== e.currentTarget) {
                        e.stopImmediatePropagation();
                    }
                });
                tables.on(kendo.support.touch ? 'touchstart' + NS : 'mousedown' + NS, NAVROW + '>' + NAVCELL, proxy(tableClick, that)).on('focus' + NS, proxy(that._tableFocus, that)).on('focusout' + NS, proxy(that._tableBlur, that)).on('keydown' + NS, proxy(that._tableKeyDown, that));
            },
            _openHeaderMenu: function (e) {
                if (e.altKey && e.keyCode == keys.DOWN) {
                    this.current().find('.k-grid-filter, .k-header-column-menu').click();
                    e.stopImmediatePropagation();
                }
            },
            _setTabIndex: function (table) {
                this._navigatableTables.attr(TABINDEX, -1);
                table.attr(TABINDEX, 0);
            },
            _tableFocus: function (e) {
                var current = this.current();
                var table = $(e.currentTarget);
                if (current && current.is(':visible')) {
                    current.addClass(FOCUSED);
                } else {
                    this._setCurrent(table.find(FIRSTNAVITEM));
                }
                this._setTabIndex(table);
            },
            _tableBlur: function () {
                var current = this.current();
                if (current) {
                    current.removeClass(FOCUSED);
                }
            },
            _tableKeyDown: function (e) {
                var current = this.current();
                var requestInProgress = this.virtualScrollable && this.virtualScrollable.fetching();
                var target = $(e.target);
                var canHandle = !e.isDefaultPrevented() && !target.is(':button,a,:input,a>.k-icon');
                if (requestInProgress) {
                    e.preventDefault();
                    return;
                }
                current = current ? current : $(this.lockedTable).add(this.options.scrollable ? this.table : this.tbody).find(FIRSTNAVITEM);
                if (!current.length) {
                    return;
                }
                var handled = false;
                if (canHandle && e.keyCode == keys.UP) {
                    handled = this._moveUp(current, e.shiftKey);
                }
                if (canHandle && e.keyCode == keys.DOWN) {
                    handled = this._moveDown(current, e.shiftKey);
                }
                if (canHandle && e.keyCode == (isRtl ? keys.LEFT : keys.RIGHT)) {
                    handled = this._moveRight(current, e.altKey, e.shiftKey, e.ctrlKey, e.currentTarget);
                }
                if (canHandle && e.keyCode == (isRtl ? keys.RIGHT : keys.LEFT)) {
                    handled = this._moveLeft(current, e.altKey, e.shiftKey, e.ctrlKey, e.currentTarget);
                }
                if (canHandle && e.keyCode == keys.PAGEDOWN) {
                    handled = this._handlePageDown();
                }
                if (canHandle && e.keyCode == keys.PAGEUP) {
                    handled = this._handlePageUp();
                }
                if (canHandle && e.keyCode == keys.HOME) {
                    handled = this._handleHome(current, e.ctrlKey);
                }
                if (canHandle && e.keyCode == keys.END) {
                    handled = this._handleEnd(current, e.ctrlKey);
                }
                if (canHandle && e.keyCode == keys.SPACEBAR) {
                    handled = this._handleSpaceKey(current, e.ctrlKey);
                }
                if (e.keyCode == keys.ENTER || e.keyCode == keys.F2) {
                    handled = this._handleEnterKey(current, e.currentTarget, target);
                }
                if (e.keyCode == keys.ESC) {
                    handled = this._handleEscKey(current, e.currentTarget);
                }
                if (e.keyCode == keys.TAB) {
                    handled = this._handleTabKey(current, e.currentTarget, e.shiftKey);
                }
                if (handled) {
                    e.preventDefault();
                    e.stopPropagation();
                }
            },
            _moveLeft: function (current, altKey, shiftKey, ctrlKey, currentTable) {
                var next, index;
                var row = current.parent();
                var container = row.parent();
                if (altKey) {
                    this.collapseRow(row);
                } else if (ctrlKey && current.is('.k-header') && this.options.reorderable) {
                    this._moveColumn(current, true);
                } else {
                    index = container.find(NAVROW).index(row);
                    next = this._prevHorizontalCell(container, current, index);
                    if (!next[0]) {
                        if (shiftKey) {
                            if (this.lockedTable) {
                                next = this._relatedRow(row);
                                if ($.contains(this.lockedTable[0], row[0])) {
                                    next = next.prevAll(ITEMROW + ':first');
                                }
                                next = next.children(DATA_CELL + ':last');
                            } else {
                                next = this._tabNext(current, currentTable, true);
                            }
                        } else {
                            container = this._horizontalContainer(container);
                            next = this._prevHorizontalCell(container, current, index);
                            if (next[0] !== current[0]) {
                                focusTable(container.parent(), true);
                            }
                        }
                    }
                    this._setCurrent(next);
                }
                return true;
            },
            _moveRight: function (current, altKey, shiftKey, ctrlKey, currentTable) {
                var next, index;
                var row = current.parent();
                var container = row.parent();
                if (altKey) {
                    this.expandRow(row);
                } else if (ctrlKey && current.is('.k-header') && this.options.reorderable) {
                    this._moveColumn(current, false);
                } else {
                    index = container.find(NAVROW).index(row);
                    next = this._nextHorizontalCell(container, current, index);
                    if (!next[0]) {
                        if (shiftKey) {
                            if (this.lockedTable) {
                                next = this._relatedRow(row);
                                if ($.contains(this.table[0], row[0])) {
                                    next = next.nextAll(ITEMROW + ':first');
                                }
                                next = next.children(DATA_CELL + ':first');
                            } else {
                                next = this._tabNext(current, currentTable, false);
                            }
                        } else {
                            container = this._horizontalContainer(container, true);
                            next = this._nextHorizontalCell(container, current, index);
                            if (next[0] !== current[0]) {
                                focusTable(container.parent(), true);
                            }
                        }
                    }
                    this._setCurrent(next);
                }
                return true;
            },
            _moveUp: function (current, shiftKey) {
                var container = current.parent().parent();
                var next;
                if (shiftKey) {
                    next = current.parent();
                    next = next.prevAll(ITEMROW + ':first');
                    next = current.parent().is(ITEMROW) ? next.children().eq(current.index()) : next.children(DATA_CELL + ':last');
                } else {
                    next = this._prevVerticalCell(container, current);
                    if (!next[0]) {
                        this._lastCellIndex = 0;
                        container = this._verticalContainer(container, true);
                        next = this._prevVerticalCell(container, current);
                        if (next[0]) {
                            focusTable(container.parent(), true);
                        }
                    }
                }
                var tmp = this._lastCellIndex || 0;
                this._setCurrent(next);
                this._lastCellIndex = tmp;
                return true;
            },
            _moveDown: function (current, shiftKey) {
                var container = current.parent().parent();
                var next;
                if (shiftKey) {
                    next = current.parent();
                    next = next.nextAll(ITEMROW + ':first');
                    next = current.parent().is(ITEMROW) ? next.children().eq(current.index()) : next.children(DATA_CELL + ':first');
                } else {
                    next = this._nextVerticalCell(container, current);
                    if (!next[0]) {
                        this._lastCellIndex = 0;
                        container = this._verticalContainer(container);
                        next = this._nextVerticalCell(container, current);
                        if (next[0]) {
                            focusTable(container.parent(), true);
                        }
                    }
                }
                var tmp = this._lastCellIndex || 0;
                this._setCurrent(next);
                this._lastCellIndex = tmp;
                return true;
            },
            _moveColumn: function (current, isLeft) {
                var elements = this.wrapper.data().kendoReorderable.element.find(this._draggableInstance.options.filter + ':visible');
                var columns = visibleColumns(flatColumnsInDomOrder(this.columns));
                var oldIndex = elements.index($(current));
                var offset = isLeft ? -1 : 1;
                var column = columns[oldIndex];
                var newIndex = targetParentContainerIndex(columns, this.columns, oldIndex, oldIndex + offset);
                if (newIndex >= 0) {
                    this.reorderColumn(newIndex, column, isLeft);
                }
            },
            _handleHome: function (current, ctrl) {
                var row = current.parent();
                var rowContainer = row.parent();
                var isInLockedTable = this.lockedTable && this.lockedTable.children('tbody')[0] === rowContainer[0];
                var isInBody = rowContainer[0] === this.tbody[0];
                var prev;
                if (ctrl) {
                    if (this.lockedTable) {
                        prev = this.lockedTable.find(FIRSTITEMROW + '>' + NAVCELL + ':first');
                    } else {
                        prev = this.table.find(FIRSTITEMROW + '>' + NAVCELL + ':first');
                    }
                } else if (isInBody || isInLockedTable) {
                    if (isInBody && this.lockedTable) {
                        row = this._relatedRow(row);
                    }
                    prev = row.children(DATA_CELL + ':first');
                }
                if (prev && prev.length) {
                    this._setCurrent(prev);
                    return true;
                }
            },
            _handleEnd: function (current, ctrl) {
                var row = current.parent();
                var rowContainer = row.parent();
                var isInLockedTable = this.lockedTable && this.lockedTable.children('tbody')[0] === rowContainer[0];
                var isInBody = rowContainer[0] === this.tbody[0];
                var next;
                if (ctrl) {
                    next = this.table.find(LASTITEMROW + '>' + NAVCELL + ':last');
                } else if (isInBody || isInLockedTable) {
                    if (!isInBody && this.lockedTable) {
                        row = this._relatedRow(row);
                    }
                    next = row.children(DATA_CELL + ':last');
                }
                if (next && next.length) {
                    this._setCurrent(next);
                    return true;
                }
            },
            _handlePageDown: function () {
                if (!this.options.pageable) {
                    return false;
                }
                this.dataSource.page(this.dataSource.page() + 1);
                return true;
            },
            _handlePageUp: function () {
                if (!this.options.pageable) {
                    return false;
                }
                this.dataSource.page(this.dataSource.page() - 1);
                return true;
            },
            _handleTabKey: function (current, currentTable, shiftKey) {
                var isInCell = this.options.editable && this._editMode() == 'incell';
                var cell;
                if (!isInCell || current.is('th')) {
                    return false;
                }
                cell = $(activeElement()).closest('.k-edit-cell');
                if (cell[0] && cell[0] !== current[0]) {
                    current = cell;
                }
                cell = this._tabNext(current, currentTable, shiftKey);
                if (cell.length) {
                    this._handleEditing(current, cell, cell.closest('table'));
                    return true;
                }
                return false;
            },
            _handleEscKey: function (current, currentTable) {
                var active = activeElement();
                var isInCell = this._editMode() == 'incell';
                if (!isInEdit(current)) {
                    if (current.has(active).length) {
                        focusTable(currentTable, true);
                        return true;
                    }
                    return false;
                }
                if (isInCell) {
                    this.closeCell(true);
                } else {
                    var currentIndex = $(current).parent().index();
                    if (active) {
                        active.blur();
                    }
                    this.cancelRow(true);
                    if (currentIndex >= 0) {
                        this._setCurrent(this.items().eq(currentIndex).children(NAVCELL).first());
                    }
                }
                if (browser.msie && browser.version < 9) {
                    document.body.focus();
                }
                focusTable(currentTable, true);
                return true;
            },
            _toggleCurrent: function (current, editable) {
                var row = current.parent();
                if (row.is('.k-grouping-row')) {
                    row.find('.k-icon:first').click();
                    return true;
                }
                if (!editable && row.is('.k-master-row')) {
                    row.find('.k-icon:first').click();
                    return true;
                }
                return false;
            },
            _handleSpaceKey: function (current, ctrlKey) {
                var that = this;
                if (!ctrlKey || !that.groupable || !current.hasClass('k-header')) {
                    return;
                }
                var descriptors = that.groupable.descriptors();
                var field = current.attr(kendo.attr('field'));
                var aggregates = that.groupable.aggregates();
                var label = current.attr(kendo.attr('title')) || field;
                if (that.groupable._canDrag(current)) {
                    descriptors.push({
                        field: field,
                        dir: 'asc',
                        aggregates: aggregates || []
                    });
                    label += ' ' + that.options.messages.ungroupHeader;
                } else {
                    descriptors = $.grep(descriptors, function (item) {
                        return item.field !== field;
                    });
                    label += ' ' + that.options.messages.groupHeader;
                }
                current.attr('aria-label', label);
                that.dataSource.group(descriptors);
                return true;
            },
            _handleEnterKey: function (current, currentTable, target) {
                var editable = this.options.editable && this.options.editable.update !== false;
                var container = target.closest('[role=gridcell]');
                var link;
                if (!target.is('table') && !$.contains(current[0], target[0])) {
                    current = container;
                }
                if (current.is('th')) {
                    link = current.find('.k-link');
                    if (link.length) {
                        link.click();
                    } else {
                        current.find(CHECKBOXINPUT).focus();
                    }
                    return true;
                }
                if (this._toggleCurrent(current, editable)) {
                    return true;
                }
                var focusable = current.find(':kendoFocusable:first');
                if (focusable[0] && !current.hasClass('k-edit-cell') && current.hasClass('k-state-focused')) {
                    focusable.focus();
                    return true;
                }
                if (editable && !target.is(':button,.k-button,textarea')) {
                    if (!container[0]) {
                        container = current;
                    }
                    this._handleEditing(container, false, currentTable);
                    return true;
                }
                return false;
            },
            _nextHorizontalCell: function (table, current, originalIndex) {
                var cells = current.nextAll(DATA_CELL);
                if (!cells.length) {
                    var rows = table.find(NAVROW);
                    var rowIndex = rows.index(current.parent());
                    if (rowIndex == -1) {
                        if (current.hasClass('k-header')) {
                            var headerRows = [];
                            mapColumnToCellRows([lockedColumns(this.columns)[0]], childColumnsCells(rows.eq(0).children(':visible').first()), headerRows, 0, 0);
                            if (headerRows[originalIndex]) {
                                return headerRows[originalIndex][0];
                            }
                            return current;
                        }
                        if (current.parent().hasClass('k-filter-row')) {
                            return rows.last().children(DATA_CELL).first();
                        }
                        return rows.eq(originalIndex).children(DATA_CELL).first();
                    }
                }
                return cells.first();
            },
            _prevHorizontalCell: function (table, current, originalIndex) {
                var cells = current.prevAll(DATA_CELL);
                if (!cells.length) {
                    var rows = table.find(NAVROW);
                    var rowIndex = rows.index(current.parent());
                    if (rowIndex == -1) {
                        if (current.hasClass('k-header')) {
                            var headerRows = [];
                            var columns = lockedColumns(this.columns);
                            mapColumnToCellRows([columns[columns.length - 1]], childColumnsCells(rows.eq(0).children().last()), headerRows, 0, 0);
                            if (headerRows[originalIndex]) {
                                return headerRows[originalIndex][0];
                            }
                            return current;
                        }
                        if (current.parent().hasClass('k-filter-row')) {
                            return rows.last().children(DATA_CELL).last();
                        }
                        return rows.eq(originalIndex).children(DATA_CELL).last();
                    }
                }
                return cells.first();
            },
            _currentDataIndex: function (table, current) {
                var index = current.attr('data-index');
                if (!index) {
                    return undefined;
                }
                var lockedColumnsCount = lockedColumns(this.columns).length;
                if (lockedColumnsCount && !table.closest('div').hasClass('k-grid-content-locked')[0]) {
                    return index - lockedColumnsCount;
                }
                return index;
            },
            _prevVerticalCell: function (container, current) {
                var cells;
                var row = current.parent();
                var rows = container.children(NAVROW);
                var rowIndex = rows.index(row);
                var index = this._currentDataIndex(container, current);
                if (index || current.hasClass('k-header')) {
                    cells = parentColumnsCells(current);
                    return cells.eq(cells.length - 2);
                }
                index = Math.max(row.children(DATA_CELL).index(current), this._lastCellIndex || 0);
                if (row.hasClass('k-filter-row')) {
                    return leafDataCells(container).filter(isCellVisible).eq(index);
                }
                if (rowIndex == -1) {
                    row = container.find('tr.k-filter-row:visible');
                    if (!row[0]) {
                        if ((this._hasDetails() || current.parent().find('.k-hierarchy-cell').length) && index) {
                            index--;
                        }
                        return leafDataCells(container).filter(isCellVisible).eq(index);
                    }
                } else {
                    row = rowIndex === 0 ? $() : rows.eq(rowIndex - 1);
                }
                cells = row.children(DATA_CELL);
                if (cells.length > index) {
                    return cells.eq(index);
                }
                return cells.eq(0);
            },
            _nextVerticalCell: function (container, current) {
                var cells;
                var row = current.parent();
                var rows = container.children(NAVROW);
                var rowIndex = rows.index(row);
                var index = this._currentDataIndex(container, current);
                if (rowIndex != -1 && index === undefined && current.hasClass('k-header')) {
                    return childColumnsCells(current).eq(1);
                }
                index = index ? parseInt(index, 10) : row.children(DATA_CELL).index(current);
                index = Math.max(index, this._lastCellIndex || 0);
                if (rowIndex == -1) {
                    row = rows.eq(0);
                    if (this._hasDetails() || row.find('.k-hierarchy-cell').length) {
                        index++;
                    }
                } else {
                    row = rows.eq(rowIndex + current[0].rowSpan);
                }
                var tmpIndex = index;
                if (this._currentDataIndex(container, current) !== undefined) {
                    var currentRowCells = row.children(':not(.k-group-cell):not(.k-hierarchy-cell)');
                    var hiddenColumns = currentRowCells.filter(':hidden');
                    for (var idx = 0, length = hiddenColumns.length; idx < length; idx++) {
                        if (currentRowCells.index(hiddenColumns[idx]) < index) {
                            tmpIndex--;
                        }
                    }
                }
                index = tmpIndex;
                cells = row.children(DATA_CELL);
                if (cells.length > index) {
                    return cells.eq(index);
                }
                return cells.eq(0);
            },
            _verticalContainer: function (container, up) {
                var table = container.parent();
                var length = this._navigatableTables.length;
                var step = Math.floor(length / 2);
                var index = inArray(table[0], this._navigatableTables);
                if (up) {
                    step *= -1;
                }
                index += step;
                if (index >= 0 || index < length) {
                    table = this._navigatableTables.eq(index);
                }
                return table.find(up ? '>thead' : '>tbody');
            },
            _horizontalContainer: function (container, right) {
                var length = this._navigatableTables.length;
                if (length <= 2) {
                    return container;
                }
                var table = container.parent();
                var index = inArray(table[0], this._navigatableTables);
                index += right ? 1 : -1;
                if (right && (index == 2 || index == length)) {
                    return container;
                }
                if (!right && (index == 1 || index < 0)) {
                    return container;
                }
                return this._navigatableTables.eq(index).find('thead, tbody');
            },
            _tabNext: function (current, currentTable, back) {
                var switchRow = true;
                var next = back ? current.prevAll(DATA_CELL + ':first') : current.nextAll(':visible:first');
                if (!next.length) {
                    next = current.parent();
                    if (this.lockedTable) {
                        switchRow = back && currentTable == this.lockedTable[0] || !back && currentTable == this.table[0];
                        next = this._relatedRow(next);
                    }
                    if (switchRow) {
                        next = next[back ? 'prevAll' : 'nextAll']('tr:not(.k-grouping-row):not(.k-detail-row):visible:first');
                    }
                    next = next.children(DATA_CELL + (back ? ':last' : ':first'));
                }
                return next;
            },
            _handleEditing: function (current, next, table) {
                var that = this, active = $(activeElement()), mode = that._editMode(), isIE = browser.msie, oldIE = isIE && browser.version < 9, editContainer = that._editContainer, focusable, editable = that.options.editable && that.options.editable.update !== false, isEdited;
                table = $(table);
                if (mode == 'incell') {
                    isEdited = current.hasClass('k-edit-cell');
                } else {
                    isEdited = current.parent().hasClass('k-grid-edit-row');
                }
                if (that.editable) {
                    if ($.contains(editContainer[0], active[0])) {
                        if (browser.opera || oldIE) {
                            active.blur().change().triggerHandler('blur');
                        } else {
                            active.blur();
                            if (isIE) {
                                active.blur();
                            }
                        }
                    }
                    if (!that.editable) {
                        focusTable(table);
                        return;
                    }
                    if (that.editable.end()) {
                        if (mode == 'incell') {
                            that.closeCell();
                        } else {
                            that.saveRow();
                            isEdited = true;
                        }
                    } else {
                        if (mode == 'incell') {
                            that._setCurrent(editContainer);
                        } else {
                            that._setCurrent(editContainer.children().filter(DATA_CELL).first());
                        }
                        focusable = editContainer.find(':kendoFocusable:first')[0];
                        if (focusable) {
                            focusable.focus();
                        }
                        return;
                    }
                }
                if (next) {
                    that._setCurrent(next);
                }
                if (oldIE) {
                    document.body.focus();
                }
                focusTable(table, true);
                if (!editable) {
                    return;
                }
                if (!isEdited && !next || next) {
                    if (mode === INCELL) {
                        if (!$(that.current()).hasClass(HIERARCHY_CELL_CLASS)) {
                            that.editCell(that.current());
                        }
                    } else {
                        that.editRow(that.current().parent());
                    }
                }
            },
            _wrapper: function () {
                var that = this, table = that.table, height = that.options.height, wrapper = that.element;
                if (!wrapper.is('div')) {
                    wrapper = wrapper.wrap('<div/>').parent();
                }
                that.wrapper = wrapper.addClass('k-grid k-widget k-display-block');
                if (height) {
                    that.wrapper.css(HEIGHT, height);
                    table.css(HEIGHT, 'auto');
                }
                that._initMobile();
            },
            _initMobile: function () {
                var options = this.options;
                var that = this;
                this._isMobile = options.mobile === true && kendo.support.mobileOS || options.mobile === 'phone' || options.mobile === 'tablet';
                if (this._isMobile) {
                    var html = this.wrapper.addClass('k-grid-mobile').wrap('<div data-' + kendo.ns + 'stretch="true" data-' + kendo.ns + 'role="view" ' + 'data-' + kendo.ns + 'init-widgets="false"></div>').parent();
                    this.pane = this._createPane(html);
                    this.view = this.pane.view();
                    if (options.height) {
                        this.pane.element.parent().css(HEIGHT, options.height);
                    } else {
                        this.pane.element.parent().css(HEIGHT, this.wrapper[0].style.height);
                    }
                    this._editAnimation = 'slide';
                    that.wrapper.on('transitionend' + NS, function (e) {
                        e.stopPropagation();
                    });
                    that.wrapper.on('contextmenu' + NS, 'th a', function (e) {
                        e.preventDefault();
                        return false;
                    });
                    this.view.bind('show', function () {
                        if (that._isLocked()) {
                            that._updateTablesWidth();
                            that._applyLockedContainersWidth();
                            that._syncLockedContentHeight();
                            that._syncLockedHeaderHeight();
                            that._syncLockedFooterHeight();
                        }
                    });
                }
            },
            _createPane: function (html) {
                var pane = kendo.Pane.wrap(html, {
                    viewEngine: {
                        viewOptions: {
                            renderOnInit: true,
                            wrap: false,
                            wrapInSections: true,
                            detachOnHide: false,
                            detachOnDestroy: false
                        }
                    }
                });
                return pane;
            },
            _tbody: function () {
                var that = this, table = that.table, tbody;
                tbody = table.find('>tbody');
                if (!tbody.length) {
                    tbody = $('<tbody/>').appendTo(table);
                }
                that.tbody = tbody.attr('role', 'rowgroup');
            },
            _scrollable: function () {
                var that = this, header, table, options = that.options, scrollable = options.scrollable, hasVirtualScroll = scrollable !== true && scrollable.virtual && !that.virtualScrollable, scrollbar = !kendo.support.kineticScrollNeeded || hasVirtualScroll ? kendo.support.scrollbar() : 0, headerWrap;
                if (scrollable) {
                    header = that.wrapper.children('.k-grid-header');
                    if (!header[0]) {
                        header = $('<div class="k-grid-header" />').insertBefore(that.table);
                    }
                    header.css(isRtl ? 'padding-left' : 'padding-right', scrollable.virtual ? scrollbar + 1 : scrollbar);
                    table = $('<table role="grid" />');
                    if (isIE7) {
                        table.attr('cellspacing', 0);
                    }
                    table.width(that.table[0].style.width);
                    table.append(that.thead);
                    header.empty().append($('<div class="k-grid-header-wrap k-auto-scrollable" />').append(table));
                    that.content = that.table.parent();
                    if (that.content.is('.k-virtual-scrollable-wrap, ' + DOT + classNames.scrollContainer)) {
                        that.content = that.content.parent();
                    }
                    if (!that.content.is('.k-grid-content, .k-virtual-scrollable-wrap')) {
                        that.content = that.table.wrap('<div class="k-grid-content k-auto-scrollable" />').parent();
                    }
                    if (hasVirtualScroll) {
                        that._createVirtualScrollable();
                    }
                    headerWrap = header.children('.k-grid-header-wrap');
                    that.scrollables = headerWrap.add(that.content);
                    var footer = that.wrapper.find('.k-grid-footer');
                    if (footer.length) {
                        that.scrollables = that.scrollables.add(footer.children('.k-grid-footer-wrap'));
                    }
                    headerWrap.unbind('scroll' + NS).bind('scroll' + NS, function (e) {
                        if (that._scrollLeft !== this.scrollLeft) {
                            that.scrollables.not(e.currentTarget).scrollLeft(this.scrollLeft);
                        }
                    });
                    if (scrollable.virtual) {
                        that.content.find('>.k-virtual-scrollable-wrap').unbind('scroll' + NS).bind('scroll' + NS, function () {
                            that.scrollables.scrollLeft(this.scrollLeft);
                            if (that.lockedContent) {
                                that.lockedContent[0].scrollTop = this.scrollTop;
                            }
                        });
                    } else {
                        var endless = scrollable.endless;
                        var originalPageSize = that.dataSource.options.pageSize;
                        if (endless) {
                            that._endlessPageSize = originalPageSize;
                        }
                        that.content.unbind('scroll' + NS).bind('scroll' + NS, function (e) {
                            that._scrollLeft = this.scrollLeft;
                            that.scrollables.not(e.currentTarget).scrollLeft(that._scrollLeft);
                            if (that.lockedContent && e.currentTarget == that.content[0]) {
                                that.lockedContent[0].scrollTop = this.scrollTop;
                            }
                            if (endless) {
                                if (this.scrollTop + this.clientHeight - this.scrollHeight >= -10 && !that._endlessFetchInProgress && that._endlessPageSize < that.dataSource.total()) {
                                    that._skipRerenderItemsCount = that._endlessPageSize;
                                    that._endlessPageSize = that._endlessPageSize + originalPageSize;
                                    that.dataSource.options.endless = true;
                                    that._endlessFetchInProgress = true;
                                    that.dataSource.pageSize(that._endlessPageSize);
                                }
                            }
                        });
                        var touchScroller = that.content.data('kendoTouchScroller');
                        if (touchScroller) {
                            touchScroller.destroy();
                        }
                        touchScroller = kendo.touchScroller(that.content);
                        if (touchScroller && touchScroller.movable) {
                            that.touchScroller = touchScroller;
                            touchScroller.movable.bind('change', function (e) {
                                that.scrollables.scrollLeft(-e.sender.x);
                                if (that.lockedContent) {
                                    that.lockedContent.scrollTop(-e.sender.y);
                                }
                            });
                            that.one(DATABOUND, function (e) {
                                e.sender.wrapper.addClass('k-grid-backface');
                            });
                        }
                    }
                }
            },
            _createVirtualScrollable: function () {
                var that = this;
                if (that.virtualScrollable) {
                    that.virtualScrollable.destroy();
                }
                that.virtualScrollable = new VirtualScrollable(that.content, {
                    dataSource: that.dataSource,
                    itemHeight: function () {
                        return that._averageRowHeight();
                    },
                    page: function () {
                        that._restoreEditableState();
                    },
                    scroll: function () {
                        that._focusEditable();
                    }
                });
                that.virtualScrollable.bind(PAGING, proxy(that._onVirtualPaging, that));
            },
            _onVirtualPaging: function () {
                var that = this;
                that._cacheEditableState();
                if (that._isVirtualIncellEditable()) {
                    that._shouldClearEditableState = false;
                    that.closeCell();
                    that._shouldClearEditableState = true;
                }
            },
            _isVirtualEditable: function () {
                return this._isVirtualIncellEditable() || this._isVirtualInlineEditable() || this._isVirtualPopupEditable();
            },
            _isVirtualInlineEditable: function () {
                return this.virtualScrollable && this._editMode() === INLINE;
            },
            _isVirtualIncellEditable: function () {
                return this.virtualScrollable && this._editMode() === INCELL;
            },
            _isVirtualPopupEditable: function () {
                return this.virtualScrollable && this._editMode() === 'popup';
            },
            _scrollVirtualWrapper: function () {
                var that = this;
                var scrollable = that.virtualScrollable;
                if (that._isVirtualInlineEditable() || that._isVirtualIncellEditable()) {
                    if (scrollable._isScrolledToBottom()) {
                        scrollable._scrollWrapperToBottom();
                    } else if (scrollable._isScrolledToTop()) {
                        scrollable._scrollWrapperToTop();
                    }
                }
            },
            _scrollVirtualWrapperOnColumnResize: function () {
                var virtualScrollable = this.virtualScrollable;
                if (virtualScrollable) {
                    virtualScrollable._scrollWrapperOnColumnResize();
                }
            },
            _restoreEditableState: function () {
                var that = this;
                var editableState = that._editableState || {};
                var editedModel = editableState.model;
                var dataSource = that.dataSource;
                var inlineMode = that._isVirtualInlineEditable();
                var incellMode = that._isVirtualIncellEditable();
                var row;
                var cell;
                if ((inlineMode || incellMode) && editedModel && dataSource._getByUid(editedModel.uid, dataSource.view())) {
                    if (inlineMode) {
                        that._shouldClearEditableState = false;
                        that.editRow(editedModel);
                        that._focusEditable();
                    } else if (incellMode) {
                        row = that.tbody.children(attrEquals(UNIQUE_ID, editedModel.uid));
                        cell = $(row).children(attrEquals(FIELD, editableState.field));
                        if (cell[0]) {
                            that._shouldClearEditableState = false;
                            that.editCell(cell);
                            that._focusEditable();
                        }
                    }
                }
                that._shouldClearEditableState = true;
            },
            _focusEditable: function () {
                var that = this;
                var editedField = (that._editableState || {}).field;
                var editContainer = that._editContainer;
                if (editContainer && !contains(editContainer[0], activeElement()) && that._canFocusEditable()) {
                    if (that._isVirtualInlineEditable()) {
                        editContainer.find(attrEquals(CONTAINER_FOR, editedField)).find(FOCUSABLE).eq(0).focus();
                    } else if (that._isVirtualIncellEditable()) {
                        editContainer.find(FOCUSABLE).eq(0).focus();
                    }
                }
            },
            _canFocusEditable: function () {
                var that = this;
                return (that._isVirtualIncellEditable() || that._isVirtualInlineEditable()) && that.virtualScrollable._isElementVisible(that._editContainer);
            },
            _cacheEditableState: function () {
                var that = this;
                var editContainer = that._editContainer;
                var editedModel = editContainer ? that._modelForContainer(editContainer) : null;
                var inlineMode = that._isVirtualInlineEditable();
                var incellMode = that._isVirtualIncellEditable();
                var active;
                var widget;
                if ((inlineMode || incellMode) && editedModel) {
                    that._clearEditableState();
                    active = $(activeElement());
                    if (editContainer && active[0] && contains(editContainer[0], active[0])) {
                        active.change();
                        widget = kendo.widgetInstance(active, kendo.ui);
                        if (widget && isFunction(widget.value) && active.is(INPUT)) {
                            widget.value(active.val());
                            widget.trigger(CHANGE);
                        }
                    }
                    if (inlineMode) {
                        that._editableState = {
                            model: editedModel,
                            field: active.closest('[' + kendo.attr(CONTAINER_FOR) + ']').attr(kendo.attr(CONTAINER_FOR))
                        };
                    } else if (incellMode) {
                        that._editableState = {
                            model: editedModel,
                            field: editContainer.attr(kendo.attr(FIELD))
                        };
                    }
                }
            },
            _clearEditableState: function () {
                var that = this;
                if (that.virtualScrollable) {
                    that._editableState = null;
                }
            },
            _destroyVirtualScrollable: function () {
                var that = this;
                that._clearEditableState();
                if (that.virtualScrollable && that.virtualScrollable.element) {
                    that.virtualScrollable.destroy();
                }
                that.virtualScrollable = null;
            },
            _renderNoRecordsContent: function () {
                var that = this;
                if (that.options.noRecords) {
                    var noRecordsElement = that.table.parent().children('.' + NORECORDSCLASS);
                    if (noRecordsElement.length) {
                        that.angular('cleanup', function () {
                            return { elements: noRecordsElement.get() };
                        });
                        noRecordsElement.remove();
                    }
                    if (!that.dataSource || !that.dataSource.view().length) {
                        noRecordsElement = $(that.noRecordsTemplate({})).insertAfter(that.table);
                        that.angular('compile', function () {
                            return {
                                elements: noRecordsElement.get(),
                                data: [{}]
                            };
                        });
                    }
                }
            },
            _setContentWidth: function (scrollLeft) {
                var that = this, hiddenDivClass = 'k-grid-content-expander', hiddenDiv = '<div class="' + hiddenDivClass + '"></div>', resizable = that.resizable, expander;
                if (that.options.scrollable && that.wrapper.is(':visible')) {
                    expander = that.table.parent().children('.' + hiddenDivClass);
                    that._setContentWidthHandler = proxy(that._setContentWidth, that);
                    if (!that.dataSource || !that.dataSource.view().length) {
                        if (!expander[0]) {
                            expander = $(hiddenDiv).appendTo(that.table.parent());
                            if (resizable) {
                                resizable.bind('resize', that._setContentWidthHandler);
                            }
                        }
                        if (that.thead) {
                            expander.width(that.thead.width());
                            if (!isNaN(parseFloat(scrollLeft, 10))) {
                                that.content.scrollLeft(scrollLeft);
                            }
                        }
                    } else if (expander[0]) {
                        expander.remove();
                        if (resizable) {
                            resizable.unbind('resize', that._setContentWidthHandler);
                        }
                    }
                    that._applyLockedContainersWidth();
                    that._syncLockedContentHeight();
                    if (that.lockedHeader && that.table[0].clientWidth === 0) {
                        that.table[0].style.width = '1px';
                    }
                }
            },
            _applyLockedContainersWidth: function () {
                if (this.options.scrollable && this.lockedHeader) {
                    var headerTable = this.thead.parent(), headerWrap = headerTable.parent(), contentWidth = this.wrapper[0].clientWidth, groups = this._groups(), scrollbar = kendo.support.scrollbar(), cols = this.lockedHeader.find('>table>colgroup>col:not(.k-group-col, .k-hierarchy-col)'), nonLockedCols = headerTable.find('>colgroup>col:not(.k-group-col, .k-hierarchy-col)'), width = columnsWidth(cols), nonLockedColsWidth = columnsWidth(nonLockedCols), footerWrap;
                    if (groups > 0) {
                        width += outerWidth(this.lockedHeader.find('.k-group-cell:first')) * groups;
                    }
                    if (width >= contentWidth) {
                        width = contentWidth - 3 * scrollbar;
                    }
                    this.lockedHeader.add(this.lockedContent).width(width);
                    headerWrap[0].style.width = headerWrap.parent().width() - width - 2 + 'px';
                    headerTable.add(this.table).width(nonLockedColsWidth);
                    if (this.virtualScrollable && !isIE11) {
                        contentWidth -= scrollbar;
                    }
                    this.content[0].style.width = contentWidth - width - 2 + 'px';
                    if (this.lockedFooter && this.lockedFooter.length) {
                        this.lockedFooter.width(width);
                        footerWrap = this.footer.find('.k-grid-footer-wrap');
                        footerWrap[0].style.width = headerWrap[0].clientWidth + 'px';
                        footerWrap.children().first().width(nonLockedColsWidth);
                    }
                }
            },
            _setContentHeight: function () {
                var that = this, options = that.options, height, header = that.wrapper.children('.k-grid-header'), scrollbar = kendo.support.scrollbar();
                var scrollableHeight = (options.scrollable || {}).height;
                if (options.scrollable && that.wrapper.is(':visible')) {
                    if (scrollableHeight && that.content[0].style.height === '') {
                        that.content[0].style.height = scrollableHeight;
                    }
                    height = that.wrapper.innerHeight();
                    height -= outerHeight(header);
                    if (that.pager && that.pager.element.is(':visible')) {
                        height -= outerHeight(that.pager.element);
                    }
                    if (options.groupable) {
                        height -= outerHeight(that.wrapper.children('.k-grouping-header'));
                    }
                    if (options.toolbar) {
                        height -= outerHeight(that.wrapper.children('.k-grid-toolbar'));
                    }
                    if (that.footerTemplate) {
                        height -= outerHeight(that.wrapper.children('.k-grid-footer'));
                    }
                    var isGridHeightSet = function (el) {
                        var initialHeight, newHeight;
                        if (el[0].style.height) {
                            return true;
                        } else {
                            initialHeight = el.height();
                        }
                        el.height('auto');
                        newHeight = el.height();
                        if (initialHeight != newHeight) {
                            el.height('');
                            return true;
                        }
                        el.height('');
                        return false;
                    };
                    if (isGridHeightSet(that.wrapper)) {
                        if (height > scrollbar * 2) {
                            if (that.lockedContent) {
                                scrollbar = that.table[0].offsetWidth > that.table.parent()[0].clientWidth ? scrollbar : 0;
                                that.lockedContent.height(height - scrollbar);
                            }
                            that.content.height(height);
                        } else {
                            that.content.height(scrollbar * 2 + 1);
                        }
                    }
                }
            },
            _averageRowHeight: function () {
                var that = this, itemsCount = that._items(that.tbody).length, rowHeight = that._rowHeight;
                if (itemsCount === 0) {
                    return rowHeight;
                }
                if (!that._rowHeight) {
                    that._rowHeight = rowHeight = outerHeight(that.table) / itemsCount;
                    that._sum = rowHeight;
                    that._measures = 1;
                }
                var currentRowHeight = outerHeight(that.table) / itemsCount;
                if (rowHeight !== currentRowHeight) {
                    that._measures++;
                    that._sum += currentRowHeight;
                    that._rowHeight = that._sum / that._measures;
                }
                return rowHeight;
            },
            _dataSource: function () {
                var that = this, options = that.options, pageable, dataSource = options.dataSource;
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                if (isPlainObject(dataSource)) {
                    extend(dataSource, {
                        table: that.table,
                        fields: that.columns
                    });
                    pageable = options.pageable;
                    if (isPlainObject(pageable) && pageable.pageSize !== undefined) {
                        dataSource.pageSize = pageable.pageSize;
                    }
                }
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler);
                } else {
                    that._refreshHandler = proxy(that.refresh, that);
                    that._progressHandler = proxy(that._requestStart, that);
                    that._errorHandler = proxy(that._error, that);
                }
                that.dataSource = DataSource.create(dataSource).bind(CHANGE, that._refreshHandler).bind(PROGRESS, that._progressHandler).bind(ERROR, that._errorHandler);
            },
            _error: function () {
                this._progress(false);
            },
            _requestStart: function () {
                this._progress(true);
            },
            _modelChange: function (e) {
                var that = this, tbody = that.tbody, model = e.model, row = that.tbody.find('tr[' + kendo.attr('uid') + '=' + model.uid + ']'), relatedRow, cell, column, isAlt = row.hasClass('k-alt'), tmp, idx = that._items(tbody).index(row), isLocked = that.lockedContent, selectable, selectableRow, childCells, originalCells, length;
                if (isLocked) {
                    relatedRow = that._relatedRow(row);
                }
                if (row.add(relatedRow).children('.k-edit-cell').length && !that.options.rowTemplate) {
                    row.add(relatedRow).children(':not(.k-group-cell,.k-hierarchy-cell)').each(function () {
                        cell = $(this);
                        column = leafColumns(that.columns)[that.cellIndex(cell)];
                        if (column.field === e.field) {
                            if (!cell.hasClass('k-edit-cell')) {
                                that._displayCell(cell, column, model);
                            } else {
                                cell.addClass('k-dirty-cell');
                            }
                        }
                    });
                } else if (!row.hasClass('k-grid-edit-row')) {
                    selectableRow = $().add(row);
                    if (isLocked) {
                        tmp = (isAlt ? that.lockedAltRowTemplate : that.lockedRowTemplate)(model);
                        selectableRow = selectableRow.add(relatedRow);
                        relatedRow.replaceWith(tmp);
                    }
                    that.angular('cleanup', function () {
                        return { elements: selectableRow.get() };
                    });
                    tmp = (isAlt ? that.altRowTemplate : that.rowTemplate)(model);
                    row.replaceWith(tmp);
                    tmp = that._items(tbody).eq(idx);
                    var angularData = [{ dataItem: model }];
                    if (isLocked) {
                        row = row.add(relatedRow);
                        relatedRow = that._relatedRow(tmp)[0];
                        adjustRowHeight(tmp[0], relatedRow);
                        tmp = tmp.add(relatedRow);
                        angularData.push({ dataItem: model });
                    }
                    that.angular('compile', function () {
                        return {
                            elements: tmp.get(),
                            data: angularData
                        };
                    });
                    selectable = that.options.selectable;
                    if ((selectable || that._checkBoxSelection) && row.hasClass('k-state-selected')) {
                        that.select(tmp);
                    }
                    originalCells = selectableRow.children(':not(.k-group-cell,.k-hierarchy-cell)');
                    childCells = tmp.children(':not(.k-group-cell,.k-hierarchy-cell)');
                    for (idx = 0, length = that.columns.length; idx < length; idx++) {
                        column = that.columns[idx];
                        cell = childCells.eq(idx);
                        if (selectable && originalCells.eq(idx).hasClass('k-state-selected')) {
                            cell.addClass('k-state-selected');
                        }
                    }
                    that.trigger('itemChange', {
                        item: tmp,
                        data: model,
                        ns: ui
                    });
                }
            },
            _pageable: function () {
                var that = this, wrapper, pageable = that.options.pageable;
                if (pageable) {
                    wrapper = that.wrapper.children('div.k-grid-pager');
                    if (!wrapper.length) {
                        wrapper = $('<div class="k-pager-wrap k-grid-pager"/>').appendTo(that.wrapper);
                    }
                    if (that.pager) {
                        that.pager.destroy();
                    }
                    if (typeof pageable === 'object' && pageable instanceof kendo.ui.Pager) {
                        that.pager = pageable;
                    } else {
                        that.pager = new kendo.ui.Pager(wrapper, extend({}, pageable, { dataSource: that.dataSource }));
                    }
                    that.pager.bind('pageChange', function (e) {
                        if (that.trigger('page', { page: e.index })) {
                            e.preventDefault();
                        }
                    });
                }
            },
            _footer: function () {
                var that = this, aggregates = that.dataSource.aggregates(), html = '', footerTemplate = that.footerTemplate, options = that.options, footerWrap, footer = that.footer || that.wrapper.find('.k-grid-footer');
                if (footerTemplate) {
                    html = $(that._wrapFooter(footerTemplate(aggregates)));
                    if (footer.length) {
                        var tmp = html;
                        that.angular('cleanup', function () {
                            return { elements: footer.get() };
                        });
                        footer.replaceWith(tmp);
                        footer = that.footer = tmp;
                    } else {
                        if (options.scrollable) {
                            footer = that.footer = options.pageable ? html.insertBefore(that.wrapper.children('div.k-grid-pager')) : html.appendTo(that.wrapper);
                        } else {
                            footer = that.footer = html.insertBefore(that.tbody);
                        }
                    }
                    that.angular('compile', function () {
                        return {
                            elements: footer.find('td:not(.k-group-cell, .k-hierarchy-cell)').get(),
                            data: map(that.columns, function (col) {
                                return {
                                    column: col,
                                    aggregate: aggregates[col.field]
                                };
                            })
                        };
                    });
                } else if (footer && !that.footer) {
                    that.footer = footer;
                }
                if (footer.length) {
                    if (options.scrollable) {
                        footerWrap = footer.attr('tabindex', -1).children('.k-grid-footer-wrap');
                        that.scrollables = $(that.scrollables.filter(function () {
                            return !$(this).is('.k-grid-footer-wrap');
                        }).toArray()).add(footerWrap);
                    }
                    if (that._footerWidth) {
                        footer.find('table').css('width', that._footerWidth);
                    }
                    if (footerWrap) {
                        var offset = that.content.scrollLeft();
                        if (options.scrollable !== true && options.scrollable.virtual) {
                            offset = that.wrapper.find('.k-virtual-scrollable-wrap').scrollLeft();
                        }
                        footerWrap.scrollLeft(offset);
                    }
                }
                if (that.lockedContent) {
                    that._appendLockedColumnFooter();
                    that._applyLockedContainersWidth();
                    that._syncLockedFooterHeight();
                }
            },
            _wrapFooter: function (footerRow) {
                var that = this, html = '', scrollbar = !kendo.support.mobileOS ? kendo.support.scrollbar() : 0;
                if (that.options.scrollable) {
                    html = $('<div class="k-grid-footer"><div class="k-grid-footer-wrap"><table' + (isIE7 ? ' cellspacing="0"' : '') + '><tbody>' + footerRow + '</tbody></table></div></div>');
                    that._appendCols(html.find('table'));
                    html.css(isRtl ? 'padding-left' : 'padding-right', scrollbar);
                    return html;
                }
                return '<tfoot class="k-grid-footer">' + footerRow + '</tfoot>';
            },
            _columnMenu: function () {
                var that = this, menu, columns = leafColumns(that.columns), column, options = that.options, columnMenu = options.columnMenu, menuOptions, sortable, filterable, cells, hasMultiColumnHeaders = grep(that.columns, function (item) {
                        return item.columns !== undefined;
                    }).length > 0, isMobile = this._isMobile, initCallback = function (e) {
                        that.trigger(COLUMNMENUINIT, {
                            field: e.field,
                            container: e.container
                        });
                    }, openCallback = function (e) {
                        that.trigger(COLUMNMENUOPEN, {
                            field: e.field,
                            container: e.container
                        });
                    }, closeCallback = function (element) {
                        focusTable(element.closest('table'), true);
                    }, sortHandler = function (e) {
                        if (that.trigger('sort', { sort: e.sort })) {
                            e.preventDefault();
                        } else {
                            that._clearEditableState();
                            if (that.dataSource.options.endless) {
                                that.dataSource.options.endless = null;
                                that._endlessPageSize = that.dataSource.options.pageSize;
                                that.dataSource.pageSize(that.dataSource.options.pageSize);
                            }
                        }
                    }, filterHandler = function (e) {
                        if (that.trigger('filter', {
                                filter: e.filter,
                                field: e.field
                            })) {
                            e.preventDefault();
                        } else {
                            that._clearEditableState();
                            if (that.dataSource.options.endless) {
                                that.dataSource.options.endless = null;
                                that._endlessPageSize = that.dataSource.options.pageSize;
                                that.dataSource.pageSize(that.dataSource.options.pageSize);
                            }
                        }
                    }, $angular = options.$angular;
                if (columnMenu) {
                    if (typeof columnMenu == 'boolean') {
                        columnMenu = {};
                    }
                    that._setColumnsMediaVisibility(columns);
                    cells = leafDataCells(that.thead);
                    for (var idx = 0, length = cells.length; idx < length; idx++) {
                        column = columns[idx];
                        var cell = cells.eq(idx);
                        if (!column.command && (column.field || cell.attr('data-' + kendo.ns + 'field'))) {
                            menu = cell.data('kendoColumnMenu');
                            if (menu) {
                                menu.destroy();
                            }
                            sortable = column.sortable !== false && columnMenu.sortable !== false && options.sortable !== false ? extend({}, options.sortable, { compare: (column.sortable || {}).compare }) : false;
                            filterable = options.filterable && column.filterable !== false && columnMenu.filterable !== false ? extend({ pane: that.pane }, options.filterable, column.filterable) : false;
                            if (column.filterable && column.filterable.dataSource) {
                                filterable.forceUnique = false;
                                filterable.checkSource = column.filterable.dataSource;
                            }
                            if (filterable) {
                                filterable.format = column.format;
                            }
                            menuOptions = {
                                dataSource: that.dataSource,
                                values: column.values,
                                columns: columnMenu.columns,
                                sortable: sortable,
                                filterable: filterable,
                                messages: columnMenu.messages,
                                owner: that,
                                closeCallback: closeCallback,
                                init: initCallback,
                                open: openCallback,
                                pane: that.pane,
                                sort: sortHandler,
                                filtering: filterHandler,
                                filter: isMobile ? ':not(.k-column-active)' : '',
                                lockedColumns: !hasMultiColumnHeaders && column.lockable !== false && lockedColumns(columns).length > 0
                            };
                            if ($angular) {
                                menuOptions.$angular = $angular;
                            }
                            cell.kendoColumnMenu(menuOptions);
                        }
                    }
                }
            },
            _headerCells: function () {
                return $(this.thead).find('th').filter(function () {
                    var th = $(this);
                    return !th.hasClass('k-group-cell') && !th.hasClass('k-hierarchy-cell');
                });
            },
            _filterable: function () {
                var that = this, columns = leafColumns(that.columns), filterMenu, cells, cell, filterInit = function (e) {
                        that.trigger(FILTERMENUINIT, {
                            field: e.field,
                            container: e.container
                        });
                    }, closeCallback = function (element) {
                        focusTable(element.closest('table'), true);
                    }, filterHandler = function (e) {
                        if (that.trigger('filter', {
                                filter: e.filter,
                                field: e.field
                            })) {
                            e.preventDefault();
                        } else {
                            that._clearEditableState();
                            if (that.dataSource.options.endless) {
                                that.dataSource.options.endless = null;
                                that._endlessPageSize = that.dataSource.options.pageSize;
                                that.dataSource.pageSize(that.dataSource.options.pageSize);
                            }
                        }
                    }, filterOpen = function (e) {
                        that.trigger(FILTERMENUOPEN, {
                            field: e.field,
                            container: e.container
                        });
                    }, filterable = that.options.filterable;
                if (filterable && typeof filterable.mode == STRING && filterable.mode.indexOf('menu') == -1) {
                    filterable = false;
                }
                if (filterable && !that.options.columnMenu) {
                    cells = leafDataCells(that.thead);
                    for (var idx = 0, length = cells.length; idx < length; idx++) {
                        cell = cells.eq(idx);
                        if (columns[idx].filterable !== false && !columns[idx].command && (columns[idx].field || cell.attr('data-' + kendo.ns + 'field'))) {
                            filterMenu = cell.data('kendoFilterMenu');
                            if (filterMenu) {
                                filterMenu.destroy();
                            }
                            filterMenu = cell.data('kendoFilterMultiCheck');
                            if (filterMenu) {
                                filterMenu.destroy();
                            }
                            var columnFilterable = columns[idx].filterable;
                            var options = extend({}, filterable, columnFilterable, {
                                dataSource: that.dataSource,
                                values: columns[idx].values,
                                format: columns[idx].format,
                                closeCallback: closeCallback,
                                title: columns[idx].title || columns[idx].field,
                                init: filterInit,
                                open: filterOpen,
                                pane: that.pane,
                                change: filterHandler
                            });
                            if (columnFilterable && columnFilterable.messages) {
                                options.messages = extend(true, {}, filterable.messages, columnFilterable.messages);
                            }
                            if (columnFilterable && columnFilterable.dataSource) {
                                options.forceUnique = false;
                                options.checkSource = columnFilterable.dataSource;
                            }
                            if (columnFilterable && columnFilterable.multi) {
                                cell.kendoFilterMultiCheck(options);
                            } else {
                                cell.kendoFilterMenu(options);
                            }
                        }
                    }
                }
            },
            _filterRow: function () {
                var that = this;
                if (!that._hasFilterRow()) {
                    return;
                }
                var settings;
                var $angular = that.options.$angular;
                var columns = leafColumns(that.columns), filterable = that.options.filterable, rowheader = that.thead.find('.k-filter-row'), filterHandler = function (e) {
                        if (that.trigger('filter', {
                                filter: e.filter,
                                field: e.field
                            })) {
                            e.preventDefault();
                        } else {
                            that._clearEditableState();
                            if (that.dataSource.options.endless) {
                                that.dataSource.options.endless = null;
                                that._endlessPageSize = that.dataSource.options.pageSize;
                                that.dataSource.pageSize(that.dataSource.options.pageSize);
                            }
                        }
                    };
                this._updateHeader(this.dataSource.group().length);
                for (var i = 0; i < columns.length; i++) {
                    var suggestDataSource, col = columns[i], operators = that.options.filterable.operators, customDataSource = false, th = $('<th/>'), field = col.field;
                    if (col.hidden) {
                        th.hide();
                    }
                    rowheader.append(th);
                    if (field && col.filterable !== false) {
                        var cellOptions = col.filterable && col.filterable.cell || {};
                        suggestDataSource = that.options.dataSource;
                        if (suggestDataSource instanceof DataSource) {
                            suggestDataSource = that.options.dataSource.options;
                        }
                        var messages = extend(true, {}, filterable.messages);
                        if (col.filterable) {
                            extend(true, messages, col.filterable.messages);
                        }
                        if (cellOptions.enabled === false) {
                            th.html('&nbsp;');
                            continue;
                        }
                        if (cellOptions.dataSource) {
                            suggestDataSource = cellOptions.dataSource;
                            customDataSource = true;
                        }
                        if (col.filterable && col.filterable.operators) {
                            operators = col.filterable.operators;
                        }
                        settings = {
                            column: col,
                            dataSource: that.dataSource,
                            suggestDataSource: suggestDataSource,
                            customDataSource: customDataSource,
                            field: field,
                            messages: messages,
                            values: col.values,
                            template: cellOptions.template,
                            delay: cellOptions.delay,
                            inputWidth: cellOptions.inputWidth,
                            suggestionOperator: cellOptions.suggestionOperator,
                            minLength: cellOptions.minLength,
                            dataTextField: cellOptions.dataTextField,
                            operator: cellOptions.operator,
                            operators: operators,
                            showOperators: cellOptions.showOperators,
                            change: filterHandler
                        };
                        if ($angular) {
                            settings.$angular = $angular;
                        }
                        $('<span/>').attr(kendo.attr('field'), field).appendTo(th).kendoFilterCell(settings);
                    } else {
                        th.html('&nbsp;');
                    }
                }
            },
            _sortable: function () {
                var that = this, columns = leafColumns(that.columns), column, sorterInstance, cell, sortable = that.options.sortable, sortHandler = function (e) {
                        if (that.trigger('sort', { sort: e.sort })) {
                            e.preventDefault();
                        } else {
                            that._clearEditableState();
                        }
                    };
                if (sortable) {
                    var cells = leafDataCells(that.thead);
                    for (var idx = 0, length = cells.length; idx < length; idx++) {
                        column = columns[idx];
                        if (column.sortable !== false && !column.command && column.field) {
                            cell = cells.eq(idx);
                            sorterInstance = cell.data('kendoColumnSorter');
                            if (sorterInstance) {
                                sorterInstance.destroy();
                            }
                            cell.attr('data-' + kendo.ns + 'field', column.field).kendoColumnSorter(extend({}, sortable, column.sortable, {
                                dataSource: that.dataSource,
                                aria: true,
                                filter: ':not(.k-column-active)',
                                change: sortHandler
                            }));
                        }
                    }
                    cells = null;
                }
            },
            _columns: function (columns) {
                var that = this, table = that.table, encoded, cols = table.find('col'), lockedCols, headers = that.element.find('thead:first th[data-index]'), columnLeafs, dataSource = that.options.dataSource;
                columns = columns.length ? columns : map(table.find('th'), function (th, idx) {
                    th = $(th);
                    var sortable = th.attr(kendo.attr('sortable')), filterable = th.attr(kendo.attr('filterable')), type = th.attr(kendo.attr('type')), groupable = th.attr(kendo.attr('groupable')), field = th.attr(kendo.attr('field')), title = th.attr(kendo.attr('title')), menu = th.attr(kendo.attr('menu'));
                    if (!field) {
                        field = th.text().replace(/\s|[^A-z0-9]/g, '');
                    }
                    return {
                        field: field,
                        type: type,
                        title: title,
                        sortable: sortable !== 'false',
                        filterable: filterable !== 'false',
                        groupable: groupable !== 'false',
                        menu: menu,
                        template: th.attr(kendo.attr('template')),
                        width: cols.eq(idx).css('width')
                    };
                });
                encoded = !(that.table.find('tbody tr').length > 0 && (!dataSource || !dataSource.transport));
                if (that.options.scrollable) {
                    var initialColumns = columns;
                    lockedCols = lockedColumns(columns);
                    columns = nonLockedColumns(columns);
                    if (lockedCols.length > 0 && columns.length === 0) {
                        throw new Error('There should be at least one non locked column');
                    }
                    normalizeHeaderCells(that.element.find('tr:has(th):first'), initialColumns);
                    columns = lockedCols.concat(columns);
                }
                that.columns = normalizeColumns(columns, encoded);
                if (headers.length && that.columns.length) {
                    columnLeafs = leafColumns(that.columns);
                    map(headers, function (th) {
                        th = $(th);
                        var id = th.attr('id');
                        var idx = kendo.parseInt(th.attr('data-index'));
                        if (id) {
                            columnLeafs[idx].headerAttributes = extend(columnLeafs[idx].headerAttributes, { id: id });
                        }
                    });
                }
                if ($.grep(leafColumns(that.columns), function (col) {
                        return col.selectable;
                    }).length) {
                    that._selectedIds = {};
                    that._checkBoxSelection = true;
                    that.wrapper.on(CLICK + NS, 'tbody > tr ' + CHECKBOXINPUT, proxy(that._checkboxClick, that));
                    that.wrapper.on(CLICK + NS, 'thead > tr ' + CHECKBOXINPUT, proxy(that._headerCheckboxClick, that));
                }
            },
            _headerCheckboxClick: function (e) {
                var that = this, checkBox = $(e.target), checked = checkBox.prop('checked'), parentGrid = checkBox.closest('.k-grid.k-widget').getKendoGrid();
                if (that !== parentGrid) {
                    return;
                }
                if (checked) {
                    that.select(parentGrid.items());
                } else {
                    that.clearSelection();
                }
            },
            _checkboxClick: function (e) {
                var that = this, row = $(e.target).closest('tr'), isSelecting = !row.hasClass(SELECTED);
                if (that !== row.closest('.k-grid.k-widget').getKendoGrid()) {
                    return;
                }
                if (isSelecting) {
                    that.select(row);
                } else {
                    that._deselectCheckRows(row);
                }
            },
            _groups: function () {
                var group = this.dataSource.group();
                return group ? group.length : 0;
            },
            _tmpl: function (rowTemplate, columns, alt, skipGroupCells) {
                var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), paramName = settings.paramName, idx, length = columns.length, template, state = {
                        storage: {},
                        count: 0
                    }, column, type, hasDetails = that._hasDetails(), className = [], groups = that._groups(), navigatable = that.options.navigatable;
                var fieldAttr = kendo.attr('field');
                var field;
                var dirtyCellTemplate = '';
                if (!rowTemplate) {
                    rowTemplate = '<tr';
                    if (alt) {
                        className.push('k-alt');
                    }
                    if (hasDetails) {
                        className.push('k-master-row');
                    }
                    if (className.length) {
                        rowTemplate += ' class="' + className.join(' ') + '"';
                    }
                    if (length) {
                        rowTemplate += ' ' + kendo.attr('uid') + '="#=' + kendo.expr('uid', settings.paramName) + '#"';
                    }
                    rowTemplate += ' role=\'row\'>';
                    if (groups > 0 && !skipGroupCells) {
                        rowTemplate += groupCells(groups);
                    }
                    if (hasDetails) {
                        rowTemplate += '<td class="k-hierarchy-cell" aria-expanded="false"><a class="k-icon k-i-expand" href="\\#" ' + ARIALABEL + '="' + EXPAND + '" tabindex="-1"></a></td>';
                    }
                    for (idx = 0; idx < length; idx++) {
                        column = columns[idx];
                        template = column.template;
                        type = typeof template;
                        field = column.field;
                        if (that._editMode() === INCELL && field) {
                            column.attributes = column.attributes || {};
                            if (that.virtualScrollable) {
                                column.attributes[fieldAttr] = field;
                            }
                            dirtyCellTemplate = that._dirtyCellTemplate(field, paramName);
                            column.attributes['class'] = column.attributes['class'] || '';
                            if (column.attributes['class'].indexOf(dirtyCellTemplate) < 0) {
                                column.attributes['class'] += dirtyCellTemplate;
                            }
                        }
                        if (column.command) {
                            column.attributes = column.attributes || {};
                            if (typeof column.attributes['class'] !== 'undefined') {
                                column.attributes['class'] += ' k-command-cell';
                            } else {
                                column.attributes['class'] = 'k-command-cell';
                            }
                        }
                        rowTemplate += '<td' + stringifyAttributes(column.attributes);
                        if (navigatable) {
                            rowTemplate += ' aria-describedby=\'' + column.headerAttributes.id + '\'';
                        }
                        rowTemplate += ' role=\'gridcell\'>';
                        rowTemplate += that._cellTmpl(column, state);
                        rowTemplate += '</td>';
                    }
                    rowTemplate += '</tr>';
                }
                rowTemplate = kendo.template(rowTemplate, settings);
                if (state.count > 0) {
                    return proxy(rowTemplate, state.storage);
                }
                return rowTemplate;
            },
            _dirtyCellTemplate: function (field, paramName) {
                var dirtyField;
                if (field && paramName) {
                    dirtyField = field.charAt(0) === '[' ? kendo.expr(field, paramName + '.dirtyFields') : paramName + '.dirtyFields[\'' + field + '\']';
                    return '#= ' + paramName + ' && ' + paramName + '.dirty && ' + paramName + '.dirtyFields && ' + dirtyField + ' ? \' k-dirty-cell\' : \'\' #';
                }
                return '';
            },
            _headerCellText: function (column) {
                var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), template = column.headerTemplate, type = typeof template, text = column.title || column.field || '';
                if (type === FUNCTION) {
                    text = kendo.template(template, settings)({});
                } else if (type === STRING) {
                    text = template;
                }
                return text;
            },
            _cellTmpl: function (column, state) {
                var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), template = column.template, paramName = settings.paramName, field = column.field, html = '', idx, length, format = column.format, type = typeof template, columnValues = column.values;
                if (column.command) {
                    if (isArray(column.command)) {
                        for (idx = 0, length = column.command.length; idx < length; idx++) {
                            if (column.command[idx].visible) {
                                html += kendo.format('#= {0}(data)? \'{1}\':\'\' #', column.command[idx].visible, that._createButton(column.command[idx]).replace(templateHashRegExp, '\\#').replace(/'/gi, '\\\''));
                            } else {
                                html += that._createButton(column.command[idx]).replace(templateHashRegExp, '\\#');
                            }
                        }
                        return html;
                    }
                    return that._createButton(column.command).replace(templateHashRegExp, '\\#');
                }
                if (column.selectable) {
                    return SELECTCOLUMNTMPL;
                }
                html += that._dirtyIndicatorTemplate(field, paramName);
                if (type === FUNCTION) {
                    state.storage['tmpl' + state.count] = template;
                    html += '#=this.tmpl' + state.count + '(' + paramName + ')#';
                    state.count++;
                } else if (type === STRING) {
                    html += template;
                } else if (columnValues && columnValues.length && isPlainObject(columnValues[0]) && 'value' in columnValues[0] && field) {
                    html += '#var v =' + kendo.stringify(convertToObject(columnValues)).replace(templateHashRegExp, '\\#') + '#';
                    html += '#var f = v[';
                    if (!settings.useWithBlock) {
                        html += paramName + '.';
                    }
                    html += field + ']#';
                    html += '${f != null ? f : \'\'}';
                } else {
                    html += column.encoded ? '#:' : '#=';
                    if (format) {
                        html += 'kendo.format("' + format.replace(formatRegExp, '\\$1') + '",';
                    }
                    if (field) {
                        field = kendo.expr(field, paramName);
                        html += field + '==null?\'\':' + field;
                    } else {
                        html += '\'\'';
                    }
                    if (format) {
                        html += ')';
                    }
                    html += '#';
                }
                return html;
            },
            _dirtyIndicatorTemplate: function (field, paramName) {
                var dirtyField;
                if (field && paramName) {
                    dirtyField = field.charAt(0) === '[' ? kendo.expr(field, paramName + '.dirtyFields') : paramName + '.dirtyFields[\'' + field + '\']';
                    return '#= ' + paramName + ' && ' + paramName + '.dirty && ' + paramName + '.dirtyFields && ' + dirtyField + ' ? \'<span class="k-dirty"></span>\' : \'\' #';
                }
                return '';
            },
            _templates: function () {
                var that = this, options = that.options, dataSource = that.dataSource, groups = dataSource.group(), footer = that.footer || that.wrapper.find('.k-grid-footer'), aggregates = dataSource.aggregate(), columnLeafs = leafColumns(that.columns), columnsLocked = leafColumns(lockedColumns(that.columns)), columns = options.scrollable ? leafColumns(nonLockedColumns(that.columns)) : columnLeafs, groupHeaderColumnTemplateLockedColumns = grep(visibleColumns(columnsLocked), function (column, index) {
                        return column.groupHeaderColumnTemplate && index !== 0;
                    }), groupHeaderColumnTemplateNonLockedColumns = grep(visibleColumns(columns), function (column) {
                        return column.groupHeaderColumnTemplate;
                    });
                if (options.scrollable && columnsLocked.length) {
                    if (options.rowTemplate || options.altRowTemplate) {
                        throw new Error('Having both row template and locked columns is not supported');
                    }
                    that.rowTemplate = that._tmpl(options.rowTemplate, columns, false, true);
                    that.altRowTemplate = that._tmpl(options.altRowTemplate || options.rowTemplate, columns, true, true);
                    that.lockedRowTemplate = that._tmpl(options.rowTemplate, columnsLocked);
                    that.lockedAltRowTemplate = that._tmpl(options.altRowTemplate || options.rowTemplate, columnsLocked, true);
                } else {
                    that.rowTemplate = that._tmpl(options.rowTemplate, columns);
                    that.altRowTemplate = that._tmpl(options.altRowTemplate || options.rowTemplate, columns, true);
                }
                if (that._hasDetails()) {
                    that.detailTemplate = that._detailTmpl(options.detailTemplate || '');
                }
                if (that._group && !isEmptyObject(aggregates) || !isEmptyObject(aggregates) && !footer.length || grep(columnLeafs, function (column) {
                        return column.footerTemplate;
                    }).length) {
                    that.footerTemplate = that._footerTmpl(columnLeafs, aggregates, 'footerTemplate', 'k-footer-template');
                }
                if (groups && grep(columnLeafs, function (column) {
                        return column.groupFooterTemplate;
                    }).length) {
                    aggregates = $.map(groups, function (g) {
                        return g.aggregates;
                    });
                    that.groupFooterTemplate = that._footerTmpl(columns, aggregates, 'groupFooterTemplate', 'k-group-footer', columnsLocked.length);
                    if (options.scrollable && columnsLocked.length) {
                        that.lockedGroupFooterTemplate = that._footerTmpl(columnsLocked, aggregates, 'groupFooterTemplate', 'k-group-footer');
                    }
                }
                if (groups && (groupHeaderColumnTemplateLockedColumns.length || groupHeaderColumnTemplateNonLockedColumns.length)) {
                    aggregates = $.map(groups, function (g) {
                        return g.aggregates;
                    });
                    that.groupHeaderColumnTemplate = that._groupHeaderTmpl(visibleColumns(columns), aggregates, 'groupHeaderColumnTemplate', 'k-grouping-row', columnsLocked.length, groupHeaderColumnTemplateNonLockedColumns);
                    if (options.scrollable && columnsLocked.length) {
                        that.lockedGroupHeaderColumnTemplate = that._groupHeaderTmpl(visibleColumns(columnsLocked), aggregates, 'groupHeaderColumnTemplate', 'k-grouping-row', 0, groupHeaderColumnTemplateLockedColumns);
                    }
                } else {
                    that.groupHeaderColumnTemplate = null;
                    that.lockedGroupHeaderColumnTemplate = null;
                }
                if (that.options.noRecords) {
                    that.noRecordsTemplate = that._noRecordsTmpl();
                }
            },
            _noRecordsTmpl: function () {
                var wrapper = '<div class="{0}">{1}</div>';
                var defaultTemplate = '<div class="k-grid-norecords-template"{1}>{0}</div>';
                var scrollableNoGridHeightStyles = this.options.scrollable && !this.wrapper[0].style.height ? ' style="margin:0 auto;position:static;"' : '';
                var state = {
                    storage: {},
                    count: 0
                };
                var settings = $.extend({}, kendo.Template, this.options.templateSettings);
                var paramName = settings.paramName;
                var template;
                var html = '';
                var type;
                var tmpl;
                if (this.options.noRecords.template) {
                    template = this.options.noRecords.template;
                } else {
                    template = kendo.format(defaultTemplate, this.options.messages.noRecords, scrollableNoGridHeightStyles);
                }
                type = typeof template;
                if (type === 'function') {
                    state.storage['tmpl' + state.count] = template;
                    html += '#=this.tmpl' + state.count + '(' + paramName + ')#';
                    state.count++;
                } else if (type === 'string') {
                    html += template;
                }
                tmpl = kendo.template(kendo.format(wrapper, NORECORDSCLASS, html), settings);
                if (state.count > 0) {
                    tmpl = $.proxy(tmpl, state.storage);
                }
                return tmpl;
            },
            _footerTmpl: function (columns, aggregates, templateName, rowClass, skipGroupCells) {
                var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), paramName = settings.paramName, html = '', idx, length, template, type, storage = {}, count = 0, scope = {}, groups = that._groups(), fieldsMap = that.dataSource._emptyAggregates(aggregates), column;
                html += '<tr class="' + rowClass + '">';
                if (groups > 0 && !skipGroupCells) {
                    html += groupCells(groups);
                }
                if (that._hasDetails()) {
                    html += '<td class="k-hierarchy-cell">&nbsp;</td>';
                }
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    column = columns[idx];
                    template = column[templateName];
                    type = typeof template;
                    html += '<td' + stringifyAttributes(column.footerAttributes) + '>';
                    if (template) {
                        if (type !== FUNCTION) {
                            scope = fieldsMap[column.field] ? extend({}, settings, { paramName: paramName + '[\'' + column.field + '\']' }) : {};
                            template = kendo.template(template, scope);
                        }
                        storage['tmpl' + count] = template;
                        html += '#=this.tmpl' + count + '(' + paramName + ')#';
                        count++;
                    } else {
                        html += '&nbsp;';
                    }
                    html += '</td>';
                }
                html += '</tr>';
                html = kendo.template(html, settings);
                if (count > 0) {
                    return proxy(html, storage);
                }
                return html;
            },
            _groupHeaderTmpl: function (columns, aggregates, templateName, rowClass, skipGroupCells, groupHeaderColumnTemplateColumns) {
                var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), paramName = settings.paramName, html = '', idx, length, template, type, storage = {}, count = 0, scope = {}, fieldsMap = that.dataSource._emptyAggregates(aggregates), column, headerTemplateIndex = groupHeaderColumnTemplateColumns.length ? inArray(groupHeaderColumnTemplateColumns[0], columns) : -1;
                html += '<tr role="row" class="' + rowClass + '">';
                if (!skipGroupCells) {
                    html += '# for (var i = 0; i < data.groupCells; i++) { #' + '<td class="k-group-cell">' + '&nbsp;' + '</td>' + '# } #';
                }
                if (that._hasDetails()) {
                    html += '<td class="k-hierarchy-cell">&nbsp;</td>';
                }
                if (headerTemplateIndex < 0) {
                    html += !skipGroupCells ? groupCellBuilder(columns.length) : '';
                    return;
                }
                if (headerTemplateIndex < MINCOLSPANVALUE && groupHeaderColumnTemplateColumns.length <= 1 && !skipGroupCells) {
                    html += !skipGroupCells ? groupCellBuilder(columns.length) : '';
                    return kendo.template(html, settings);
                }
                if (headerTemplateIndex < MINCOLSPANVALUE) {
                    headerTemplateIndex = !skipGroupCells ? 1 : 0;
                    html += !skipGroupCells ? groupCellBuilder(headerTemplateIndex) : '';
                } else {
                    html += !skipGroupCells ? groupCellBuilder(headerTemplateIndex) : groupCellLockedContentBuilder(headerTemplateIndex);
                }
                for (idx = headerTemplateIndex, length = columns.length; idx < length; idx++) {
                    column = columns[idx];
                    template = column[templateName];
                    type = typeof template;
                    html += '<td>';
                    if (template) {
                        if (type !== FUNCTION) {
                            scope = fieldsMap[column.field] ? extend({}, settings, { paramName: paramName + '[\'' + column.field + '\']' }) : {};
                            template = kendo.template(template, scope);
                        }
                        storage['tmpl' + count] = template;
                        html += '#=this.tmpl' + count + '(' + paramName + ')#';
                        count++;
                    } else {
                        html += '&nbsp;';
                    }
                    html += '</td>';
                }
                html += '</tr>';
                html = kendo.template(html, settings);
                if (count > 0) {
                    return proxy(html, storage);
                }
                return html;
            },
            _detailTmpl: function (template) {
                var that = this, html = '', settings = extend({}, kendo.Template, that.options.templateSettings), paramName = settings.paramName, templateFunctionStorage = {}, templateFunctionCount = 0, groups = that._groups(), colspan = visibleColumns(leafColumns(that.columns)).length, type = typeof template;
                html += '<tr class="k-detail-row">';
                if (groups > 0) {
                    html += groupCells(groups);
                }
                html += '<td class="k-hierarchy-cell"></td><td class="k-detail-cell"' + (colspan ? ' colspan="' + colspan + '"' : '') + '>';
                if (type === FUNCTION) {
                    templateFunctionStorage['tmpl' + templateFunctionCount] = template;
                    html += '#=this.tmpl' + templateFunctionCount + '(' + paramName + ')#';
                    templateFunctionCount++;
                } else {
                    html += template;
                }
                html += '</td></tr>';
                html = kendo.template(html, settings);
                if (templateFunctionCount > 0) {
                    return proxy(html, templateFunctionStorage);
                }
                return html;
            },
            _hasDetails: function () {
                var that = this;
                return that.options.detailTemplate !== null || (that._events[DETAILINIT] || []).length;
            },
            _hasFilterRow: function () {
                var filterable = this.options.filterable;
                var hasFiltering = filterable && typeof filterable.mode == STRING && filterable.mode.indexOf('row') != -1;
                var columns = this.columns;
                var columnsWithoutFiltering = $.grep(columns, function (col) {
                    return col.filterable === false;
                });
                if (columns.length && columnsWithoutFiltering.length == columns.length) {
                    hasFiltering = false;
                }
                return hasFiltering;
            },
            _details: function () {
                var that = this;
                if (that.options.scrollable && that._hasDetails() && lockedColumns(that.columns).length) {
                    throw new Error('Having both detail template and locked columns is not supported');
                }
                that.table.on(CLICK + NS, '.k-hierarchy-cell .k-i-expand, .k-hierarchy-cell .k-i-collapse', function (e) {
                    var button = $(this), cell = button.closest('td.k-hierarchy-cell'), expanding = button.hasClass('k-i-expand'), masterRow = button.closest('tr.k-master-row'), detailRow, detailTemplate = that.detailTemplate, data, hasDetails = that._hasDetails(), ariaLabelText = expanding ? COLLAPSE : EXPAND, ariaExpandText = expanding ? true : false;
                    button.toggleClass('k-i-expand', !expanding).toggleClass('k-i-collapse', expanding).attr(ARIALABEL, ariaLabelText);
                    cell.attr('aria-expanded', ariaExpandText);
                    detailRow = masterRow.next();
                    if (hasDetails && !detailRow.hasClass('k-detail-row')) {
                        data = that.dataItem(masterRow);
                        detailRow = $(detailTemplate(data)).addClass(masterRow.hasClass('k-alt') ? 'k-alt' : '').insertAfter(masterRow);
                        that.angular('compile', function () {
                            return {
                                elements: detailRow.get(),
                                data: [{ dataItem: data }]
                            };
                        });
                        that.trigger(DETAILINIT, {
                            masterRow: masterRow,
                            detailRow: detailRow,
                            data: data,
                            detailCell: detailRow.find('.k-detail-cell')
                        });
                    }
                    that.trigger(expanding ? DETAILEXPAND : DETAILCOLLAPSE, {
                        masterRow: masterRow,
                        detailRow: detailRow
                    });
                    detailRow.toggle(expanding);
                    e.preventDefault();
                    return false;
                });
            },
            dataItem: function (tr) {
                tr = $(tr)[0];
                if (!tr) {
                    return null;
                }
                var rows = this.tbody.children(), classesRegEx = /k-grouping-row|k-detail-row|k-group-footer/, idx = tr.sectionRowIndex, j, correctIdx;
                correctIdx = idx;
                for (j = 0; j < idx; j++) {
                    if (classesRegEx.test(rows[j].className)) {
                        correctIdx--;
                    }
                }
                return this._data[correctIdx];
            },
            expandRow: function (tr) {
                $(tr).find('> td .k-i-expand').click();
            },
            collapseRow: function (tr) {
                $(tr).find('> td .k-i-collapse').click();
            },
            _createHeaderCells: function (columns, rowSpan) {
                var that = this, idx, th, text, html = '', length, title, messages = that.options.messages, leafs = leafColumns(that.columns), groups = that.dataSource.group(), field;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    th = columns[idx].column || columns[idx];
                    text = that._headerCellText(th);
                    field = '';
                    var index = inArray(th, leafs);
                    if (th.selectable) {
                        html += '<th scope=\'col\'' + stringifyAttributes(th.headerAttributes);
                        if (rowSpan && !columns[idx].colSpan) {
                            html += ' rowspan=\'' + rowSpan + '\'';
                        }
                        if (index > -1) {
                            html += kendo.attr('index') + '=\'' + index + '\'';
                        }
                        text = th.headerTemplate ? text : kendo.template(SELECTCOLUMNHEADERTMPL)({});
                        html += '>' + text + '</th>';
                    } else if (th.command) {
                        html += '<th scope=\'col\'' + stringifyAttributes(th.headerAttributes);
                        if (rowSpan && !columns[idx].colSpan) {
                            html += ' rowspan=\'' + rowSpan + '\'';
                        }
                        if (index > -1) {
                            html += kendo.attr('index') + '=\'' + index + '\'';
                        }
                        html += '>' + text + '</th>';
                    } else {
                        if (th.field) {
                            field = kendo.attr('field') + '=\'' + th.field + '\' ';
                        }
                        html += '<th scope=\'col\' role=\'columnheader\' ' + field;
                        html += ' aria-haspopup=\'true\'';
                        if (rowSpan && !columns[idx].colSpan) {
                            html += ' rowspan=\'' + rowSpan + '\'';
                        }
                        if (columns[idx].colSpan > 1) {
                            html += 'colspan="' + (columns[idx].colSpan - hiddenLeafColumnsCount(th.columns)) + '" ';
                            html += kendo.attr('colspan') + '=\'' + columns[idx].colSpan + '\'';
                        } else if (columns[idx].colSpan === 1) {
                            html += kendo.attr('colspan') + '=\'' + columns[idx].colSpan + '\'';
                        }
                        if (th.title) {
                            title = th.title.replace('"', '&quot;').replace(/'/g, '\'');
                            html += kendo.attr('title') + '="' + title + '" ';
                        }
                        if (th.groupable !== undefined) {
                            html += kendo.attr('groupable') + '=\'' + th.groupable + '\' ';
                        }
                        if (isColumnGroupable(that, th)) {
                            html += 'aria-label=\'' + (title || th.field) + ' ';
                            html += isGroupedBy(groups, th.field) ? messages.ungroupHeader : messages.groupHeader;
                            html += '\' ';
                        }
                        if (th.aggregates && th.aggregates.length) {
                            html += kendo.attr('aggregates') + '=\'' + th.aggregates + '\'';
                        }
                        if (index > -1) {
                            html += kendo.attr('index') + '=\'' + index + '\'';
                        }
                        html += stringifyAttributes(th.headerAttributes);
                        html += '>' + text + '</th>';
                    }
                }
                return html;
            },
            _appendLockedColumnContent: function () {
                var columns = this.columns, idx, colgroup = this.table.find('colgroup'), cols = colgroup.find('col:not(.k-group-col,.k-hierarchy-col)'), length, lockedCols = $(), skipHiddenCount = 0, container, colSpan, spanIdx, colOffset = 0;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    if (columns[idx].locked) {
                        if (isVisible(columns[idx])) {
                            colSpan = 1;
                            if (columns[idx].columns) {
                                colSpan = leafColumns(columns[idx].columns).length - hiddenLeafColumnsCount(columns[idx].columns);
                            }
                            colSpan = colSpan || 1;
                            for (spanIdx = 0; spanIdx < colSpan; spanIdx++) {
                                lockedCols = lockedCols.add(cols.eq(idx + colOffset + spanIdx - skipHiddenCount));
                            }
                            colOffset += colSpan - 1;
                        } else {
                            skipHiddenCount++;
                        }
                    }
                }
                container = $('<div class="k-grid-content-locked"><table' + (isIE7 ? ' cellspacing="0"' : '') + '><colgroup/><tbody></tbody></table></div>');
                colgroup.detach();
                container.find('colgroup').append(lockedCols);
                colgroup.insertBefore(this.table.find('tbody'));
                this.lockedContent = container.insertBefore(this.content);
                this.lockedTable = container.children('table');
            },
            _appendLockedColumnFooter: function () {
                var that = this;
                var footer = that.footer;
                var cells = footer.find('.k-footer-template>td');
                var cols = footer.find('.k-grid-footer-wrap>table>colgroup>col');
                var html = $('<div class="k-grid-footer-locked"><table><colgroup /><tbody><tr class="k-footer-template"></tr></tbody></table></div>');
                var idx, length;
                var groups = that._groups();
                var lockedCells = $(), lockedCols = $();
                lockedCells = lockedCells.add(cells.filter('.k-group-cell'));
                for (idx = 0, length = leafColumns(lockedColumns(that.columns)).length; idx < length; idx++) {
                    lockedCells = lockedCells.add(cells.eq(idx + groups));
                }
                lockedCols = lockedCols.add(cols.filter('.k-group-col'));
                for (idx = 0, length = visibleColumns(leafColumns(visibleLockedColumns(that.columns))).length; idx < length; idx++) {
                    lockedCols = lockedCols.add(cols.eq(idx + groups));
                }
                lockedCells.appendTo(html.find('tr'));
                lockedCols.appendTo(html.find('colgroup'));
                that.lockedFooter = html.prependTo(footer);
            },
            _appendLockedColumnHeader: function (container) {
                var that = this, columns = this.columns, idx, html, length, colgroup, tr, trFilter, table, header, filtercellCells, rows = [], skipHiddenCount = 0, cols = $(), hasFilterRow = that._hasFilterRow(), filterCellOffset = 0, filterCells = $(), cell, leafColumnsCount = 0, cells = $();
                colgroup = that.thead.prev().find('col:not(.k-group-col,.k-hierarchy-col)');
                header = that.thead.find('tr:first .k-header:not(.k-group-cell,.k-hierarchy-cell)');
                filtercellCells = that.thead.find('.k-filter-row').find('th:not(.k-group-cell,.k-hierarchy-cell)');
                var colOffset = 0;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    if (columns[idx].locked) {
                        cell = header.eq(idx);
                        leafColumnsCount = leafColumns(columns[idx].columns || []).length;
                        if (isVisible(columns[idx])) {
                            var colSpan = null;
                            if (columns[idx].columns) {
                                colSpan = leafColumnsCount - hiddenLeafColumnsCount(columns[idx].columns);
                            }
                            colSpan = colSpan || 1;
                            for (var spanIdx = 0; spanIdx < colSpan; spanIdx++) {
                                cols = cols.add(colgroup.eq(idx + colOffset + spanIdx - skipHiddenCount));
                            }
                            colOffset += colSpan - 1;
                        }
                        mapColumnToCellRows([columns[idx]], childColumnsCells(cell), rows, 0, 0);
                        leafColumnsCount = leafColumnsCount || 1;
                        for (var j = 0; j < leafColumnsCount; j++) {
                            filterCells = filterCells.add(filtercellCells.eq(filterCellOffset + j));
                        }
                        filterCellOffset += leafColumnsCount;
                    }
                    if (columns[idx].columns) {
                        skipHiddenCount += hiddenLeafColumnsCount(columns[idx].columns);
                    }
                    if (!isVisible(columns[idx])) {
                        skipHiddenCount++;
                    }
                }
                if (rows.length) {
                    html = '<div class="k-grid-header-locked" style="width:1px"><table' + (isIE7 ? ' cellspacing="0"' : '') + '><colgroup/><thead>';
                    html += new Array(rows.length + 1).join('<tr></tr>');
                    html += (hasFilterRow ? '<tr class="k-filter-row" />' : '') + '</thead></table></div>';
                    table = $(html);
                    colgroup = table.find('colgroup');
                    colgroup.append(that.thead.prev().find('col.k-group-col').add(cols));
                    tr = table.find('thead tr:not(.k-filter-row)');
                    for (idx = 0, length = rows.length; idx < length; idx++) {
                        cells = toJQuery(rows[idx]);
                        tr.eq(idx).append(that.thead.find('tr:eq(' + idx + ') .k-group-cell').add(cells));
                    }
                    var count = removeEmptyRows(this.thead);
                    if (rows.length < count) {
                        removeRowSpanValue(table, count - rows.length);
                    }
                    trFilter = table.find('.k-filter-row');
                    trFilter.append(that.thead.find('.k-filter-row .k-group-cell').add(filterCells));
                    this.lockedHeader = table.prependTo(container);
                    this.thead.find('.k-group-cell').remove();
                    return true;
                }
                return false;
            },
            _removeLockedContainers: function () {
                var elements = this.lockedHeader.add(this.lockedContent).add(this.lockedFooter);
                kendo.destroy(elements);
                elements.off(NS).remove();
                this.lockedHeader = this.lockedContent = this.lockedFooter = null;
                this.selectable = null;
            },
            _thead: function () {
                var that = this, columns = that.columns, hasDetails = that._hasDetails() && columns.length, hasFilterRow = that._hasFilterRow(), idx, html = '', thead = that.table.find('>thead'), hasTHead = that.element.find('thead:first').length > 0, headerContent = that.options.messages.expandCollapseColumnHeader, tr;
                if (!thead.length) {
                    thead = $('<thead/>').insertBefore(that.tbody);
                }
                if (that.lockedHeader && that.thead) {
                    tr = that.thead.find('tr:has(th):not(.k-filter-row)').html('');
                    tr.remove();
                    tr = $();
                    that._removeLockedContainers();
                } else if (hasTHead) {
                    tr = that.element.find('thead:first tr:has(th):not(.k-filter-row)');
                } else {
                    tr = that.element.find('tr:has(th):first');
                }
                if (!tr.length) {
                    tr = thead.children().first();
                    if (!tr.length) {
                        var rows = [{
                                rowSpan: 1,
                                cells: [],
                                index: 0
                            }];
                        that._prepareColumns(rows, columns);
                        for (idx = 0; idx < rows.length; idx++) {
                            html += '<tr>';
                            if (hasDetails) {
                                html += '<th class="k-hierarchy-cell" scope="col">' + headerContent + '</th>';
                            }
                            html += that._createHeaderCells(rows[idx].cells, rows[idx].rowSpan);
                            html += '</tr>';
                        }
                        tr = $(html);
                    }
                } else {
                    for (idx = 0; idx < columns.length; idx++) {
                        var columnIndex = inArray(columns[idx], leafColumns(columns));
                        var cell = leafDataCells(tr.parent()).filter('th:not(.k-group-cell):not(.k-hierarchy-cell)').eq(columnIndex);
                        if (columns[idx].hidden && columnIndex >= 0) {
                            cell[0].style.display = 'none';
                        }
                    }
                }
                if (hasFilterRow) {
                    var filterRow = $('<tr/>');
                    filterRow.addClass('k-filter-row');
                    if (hasDetails || tr.find('.k-hierarchy-cell').length) {
                        filterRow.prepend('<th class="k-hierarchy-cell" scope="col">&nbsp;</th>');
                    }
                    var existingFilterRow = (that.thead || thead).find('.k-filter-row');
                    if (existingFilterRow.length) {
                        kendo.destroy(existingFilterRow);
                        existingFilterRow.remove();
                    }
                    thead.append(filterRow);
                }
                if (!tr.children().length) {
                    html = '';
                    if (hasDetails) {
                        html += '<th class="k-hierarchy-cell" scope="col">&nbsp;</th>';
                    }
                    html += that._createHeaderCells(columns);
                    tr.html(html);
                } else if (hasDetails && !tr.find('.k-hierarchy-cell')[0]) {
                    tr.prepend('<th class="k-hierarchy-cell" scope="col">' + (headerContent ? headerContent : '&nbsp;') + '</th>');
                }
                tr.attr('role', 'row').find('th').addClass('k-header');
                if (!that.options.scrollable) {
                    thead.addClass('k-grid-header');
                }
                tr.find('script').remove().end().prependTo(thead);
                if (that.thead) {
                    that._destroyColumnAttachments();
                }
                this.angular('cleanup', function () {
                    return { elements: thead.find('th' + NAVCELL).get() };
                });
                this.angular('compile', function () {
                    return {
                        elements: thead.find(HEADERCELLS).get(),
                        data: map(columns, function (col) {
                            return { column: col };
                        })
                    };
                });
                that.thead = thead.attr('role', 'rowgroup');
                that._sortable();
                that._filterable();
                that._filterRow();
                that._scrollable();
                that._columnMenu();
                var syncHeight;
                var hasLockedColumns = this.options.scrollable && lockedColumns(this.columns).length;
                if (hasLockedColumns) {
                    syncHeight = that._appendLockedColumnHeader(that.thead.closest('.k-grid-header'));
                    that._appendLockedColumnContent();
                    that.lockedContent.bind('DOMMouseScroll' + NS + ' mousewheel' + NS, proxy(that._wheelScroll, that));
                    that._updateLockedCols();
                }
                that._updateCols();
                that._updateColumnCellIndex();
                that._updateFirstColumnClass();
                that._resizable();
                that._draggable();
                that._reorderable();
                that._updateHeader(that._groups());
                if (hasLockedColumns) {
                    if (syncHeight) {
                        that._syncLockedHeaderHeight();
                    }
                    that._applyLockedContainersWidth();
                }
                if (that.groupable) {
                    that._attachGroupable();
                }
            },
            _retrieveFirstColumn: function (columns, rows) {
                var result = $();
                if (rows.length && columns[0]) {
                    var column = columns[0];
                    while (column.columns && column.columns.length) {
                        column = column.columns[0];
                        rows = rows.filter(':not(:first())');
                    }
                    result = result.add(rows);
                }
                return result;
            },
            _updateFirstColumnClass: function () {
                var that = this, columns = that.columns || [], hasDetails = that._hasDetails() && columns.length;
                if (!hasDetails && !that._groups()) {
                    var tr = that.thead.find('>tr:not(.k-filter-row):not(:first)');
                    columns = nonLockedColumns(columns);
                    var rows = that._retrieveFirstColumn(columns, tr);
                    if (that._isLocked()) {
                        tr = that.lockedHeader.find('thead>tr:not(.k-filter-row):not(:first)');
                        columns = lockedColumns(that.columns);
                        rows = rows.add(that._retrieveFirstColumn(columns, tr));
                    }
                    rows.each(function () {
                        var ths = $(this).find('th');
                        ths.removeClass('k-first');
                        ths.eq(0).addClass('k-first');
                    });
                }
            },
            _prepareColumns: function (rows, columns, parentCell, parentRow) {
                var row = parentRow || rows[rows.length - 1];
                var childRow = rows[row.index + 1];
                var totalColSpan = 0;
                for (var idx = 0; idx < columns.length; idx++) {
                    var cell = {
                        column: columns[idx],
                        colSpan: 0
                    };
                    row.cells.push(cell);
                    if (columns[idx].columns && columns[idx].columns.length) {
                        if (!childRow) {
                            childRow = {
                                rowSpan: 0,
                                cells: [],
                                index: rows.length
                            };
                            rows.push(childRow);
                        }
                        cell.colSpan = columns[idx].columns.length;
                        this._prepareColumns(rows, columns[idx].columns, cell, childRow);
                        totalColSpan += cell.colSpan - 1;
                        row.rowSpan = rows.length - row.index;
                    }
                }
                if (parentCell) {
                    parentCell.colSpan += totalColSpan;
                }
            },
            _wheelScroll: function (e) {
                if (e.ctrlKey) {
                    return;
                }
                var content = this.content;
                if (this.options.scrollable.virtual) {
                    content = this.virtualScrollable.verticalScrollbar;
                }
                var scrollTop = content.scrollTop(), delta = kendo.wheelDeltaY(e);
                if (delta) {
                    if (content[0].scrollHeight > content[0].clientHeight && (content[0].scrollTop < content[0].scrollHeight - content[0].clientHeight && delta < 0 || content[0].scrollTop > 0 && delta > 0)) {
                        e.preventDefault();
                    }
                    content.scrollTop(scrollTop + -delta);
                }
            },
            _isLocked: function () {
                return this.lockedHeader != null;
            },
            _updateHeaderCols: function () {
                var table = this.thead.parent().add(this.table);
                if (this._isLocked()) {
                    normalizeCols(table, visibleLeafColumns(visibleNonLockedColumns(this.columns)), this._hasDetails(), 0);
                } else {
                    normalizeCols(table, visibleLeafColumns(visibleColumns(this.columns)), this._hasDetails(), 0);
                }
            },
            _updateColumnSorters: function () {
                var that = this;
                var cells = leafDataCells(that.thead);
                var columns = leafColumns(that.columns);
                var column;
                var cell;
                var sorterInstance;
                if (!that.options.sortable) {
                    return;
                }
                for (var idx = 0, length = cells.length; idx < length; idx++) {
                    column = columns[idx];
                    if (column.sortable !== false && !column.command && column.field) {
                        cell = cells.eq(idx);
                        sorterInstance = cell.data('kendoColumnSorter');
                        if (sorterInstance) {
                            sorterInstance.refresh();
                        }
                    }
                }
            },
            _updateCols: function (table) {
                table = table || this.thead.parent().add(this.table);
                this._appendCols(table, this._isLocked());
            },
            _updateLockedCols: function (table) {
                if (this._isLocked()) {
                    table = table || this.lockedHeader.find('table').add(this.lockedTable);
                    normalizeCols(table, visibleLeafColumns(visibleLockedColumns(this.columns)), this._hasDetails(), this._groups());
                }
            },
            _appendCols: function (table, locked) {
                if (locked) {
                    normalizeCols(table, visibleLeafColumns(visibleNonLockedColumns(this.columns)), this._hasDetails(), 0);
                } else {
                    normalizeCols(table, visibleLeafColumns(visibleColumns(this.columns)), this._hasDetails(), this._groups());
                }
            },
            _autoColumns: function (schema) {
                if (schema && schema.toJSON) {
                    var that = this, field, encoded;
                    schema = schema.toJSON();
                    encoded = !(that.table.find('tbody tr').length > 0 && (!that.dataSource || !that.dataSource.transport));
                    for (field in schema) {
                        that.columns.push({
                            field: field,
                            encoded: encoded,
                            headerAttributes: { id: kendo.guid() }
                        });
                    }
                    that._thead();
                    that._templates();
                }
            },
            _rowsHtml: function (data, templates) {
                var that = this, html = '', idx, rowTemplate = templates.rowTemplate, altRowTemplate = templates.altRowTemplate, length;
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (that._skipRerenderItemsCount > 0) {
                        that._skipRerenderItemsCount--;
                    } else {
                        if (idx % 2) {
                            html += altRowTemplate(data[idx]);
                        } else {
                            html += rowTemplate(data[idx]);
                        }
                    }
                    that._data.push(data[idx]);
                }
                return html;
            },
            _groupData: function (group, skipFooter, firstColumn) {
                var that = this, footerDefaults = that._groupAggregatesDefaultObject || {}, groupItems = group.items, aggregates = extend({}, footerDefaults, group.aggregates), headerData = extend({}, {
                        field: group.field,
                        value: group.value,
                        items: groupItems,
                        aggregates: aggregates
                    }, group.aggregates[firstColumn ? firstColumn.field : group.field]), footerData = {};
                if (!skipFooter) {
                    for (var aggregate in aggregates) {
                        footerData[aggregate] = extend({}, aggregates[aggregate], {
                            group: {
                                field: group.field,
                                value: group.value,
                                items: groupItems
                            }
                        });
                    }
                }
                return extend({}, footerData, headerData);
            },
            _groupRowHtml: function (group, colspan, level, groupHeaderBuilder, templates, skipColspan, skipLastGroup) {
                var that = this, html = '', idx, length, field = group.field, column = grep(leafColumns(that.columns), function (column) {
                        return column.field == field;
                    })[0] || {}, template = column.groupHeaderTemplate ? column.groupHeaderTemplate : visibleColumns(that.columns)[0].groupHeaderColumnTemplate, text = (column.title || field) + ': ' + formatGroupValue(group.value, column.format, column.values, column.encoded), groupItems = group.items, groups = that._groups(), groupFooterTemplate = templates.groupFooterTemplate, groupHeaderColumnTemplate = templates.groupHeaderColumnTemplate, groupData;
                if (templates.groupFooterTemplate || templates.groupHeaderColumnTemplate || column.groupHeaderTemplate) {
                    groupData = that._groupData(group, false, !column.groupHeaderTemplate && visibleColumns(that.columns)[0].groupHeaderColumnTemplate ? visibleColumns(that.columns)[0] : false);
                }
                if (template && !skipColspan) {
                    text = typeof template === FUNCTION ? template(groupData) : kendo.template(template)(groupData);
                }
                if (!that._skipRerenderItemsCount) {
                    if (groupHeaderColumnTemplate) {
                        html += groupHeaderColumnTemplate(extend({}, groupData, {
                            groupCells: level,
                            colspan: groups - level,
                            text: text
                        }));
                    } else {
                        html += groupHeaderBuilder(colspan, level, text);
                    }
                } else {
                    groupHeaderBuilder(colspan, level, text);
                }
                if (group.hasSubgroups) {
                    for (idx = 0, length = groupItems.length; idx < length; idx++) {
                        html += that._groupRowHtml(groupItems[idx], skipColspan ? colspan : colspan - 1, level + 1, groupHeaderBuilder, templates, skipColspan, skipLastGroup && idx === groupItems.length - 1);
                    }
                } else {
                    html += that._rowsHtml(groupItems, templates);
                }
                if (groupFooterTemplate) {
                    if (skipLastGroup) {
                        if (!inArray(group.value, that._skippedGroups)) {
                            that._skippedGroups.push(group.value);
                        }
                    } else {
                        if (that._skippedGroups.length && that._skippedGroups[0] === group.value) {
                            that._skippedGroups.shift();
                        }
                        if (!that._skipRerenderItemsCount) {
                            html += groupFooterTemplate(groupData);
                        }
                    }
                }
                return html;
            },
            collapseGroup: function (group) {
                var level, that = this, groupToCollapse = group, groupable = this.options.groupable, showFooter = groupable.showFooter, footerCount = showFooter ? 0 : 1, offset, relatedGroup = $(), idx, length, tr;
                group = $(group);
                if (this._isLocked()) {
                    if (!group.closest('div').hasClass('k-grid-content-locked')) {
                        relatedGroup = group.nextAll('tr');
                        group = this.lockedTable.find('>tbody>tr:eq(' + group.index() + ')');
                    } else {
                        relatedGroup = this.tbody.children('tr:eq(' + group.index() + ')').nextAll('tr');
                    }
                }
                level = group.find('.k-group-cell').length;
                group.find('.k-i-collapse').addClass('k-i-expand').removeClass('k-i-collapse');
                group.find('td[aria-expanded=\'true\']:first').attr('aria-expanded', false).find('a').attr(ARIALABEL, EXPAND);
                group = group.nextAll('tr');
                var toHide = [];
                for (idx = 0, length = group.length; idx < length; idx++) {
                    tr = group.eq(idx);
                    offset = tr.find('.k-group-cell').length;
                    if (tr.hasClass('k-grouping-row')) {
                        footerCount++;
                    } else if (tr.hasClass('k-group-footer')) {
                        footerCount--;
                    }
                    if (offset <= level || tr.hasClass('k-group-footer') && footerCount < 0) {
                        break;
                    }
                    if (relatedGroup.length) {
                        toHide.push(relatedGroup[idx]);
                    }
                    toHide.push(tr[0]);
                }
                $(toHide).hide();
                if (this.options.scrollable.endless && this.content) {
                    clearTimeout(that._collapseGroupsTimeOut);
                    that._collapseGroupsTimeOut = setTimeout(function () {
                        that.content.scroll();
                        that._groupToCollapse = groupToCollapse;
                    });
                }
            },
            expandGroup: function (group) {
                group = $(group);
                var that = this, showFooter = that.options.groupable.showFooter, level, tr, offset, relatedGroup = $(), idx, length, footersVisibility = [], groupsCount = 1;
                if (this._isLocked()) {
                    if (!group.closest('div').hasClass('k-grid-content-locked')) {
                        relatedGroup = group.nextAll('tr');
                        group = this.lockedTable.find('>tbody>tr:eq(' + group.index() + ')');
                    } else {
                        relatedGroup = this.tbody.children('tr:eq(' + group.index() + ')').nextAll('tr');
                    }
                }
                level = group.find('.k-group-cell').length;
                group.find('.k-i-expand').addClass('k-i-collapse').removeClass('k-i-expand');
                group.find('td[aria-expanded=\'false\']:first').attr('aria-expanded', true).find('a').attr(ARIALABEL, COLLAPSE);
                group = group.nextAll('tr');
                for (idx = 0, length = group.length; idx < length; idx++) {
                    tr = group.eq(idx);
                    offset = tr.find('.k-group-cell').length;
                    if (offset <= level) {
                        break;
                    }
                    if (offset == level + 1 && !tr.hasClass('k-detail-row')) {
                        tr.show();
                        relatedGroup.eq(idx).show();
                        if (tr.hasClass('k-grouping-row') && tr.find('.k-icon').hasClass('k-i-collapse')) {
                            that.expandGroup(tr);
                        }
                        if (tr.hasClass('k-master-row') && tr.find('.k-icon').hasClass('k-i-collapse')) {
                            tr.next().show();
                            relatedGroup.eq(idx + 1).show();
                        }
                    }
                    if (tr.hasClass('k-grouping-row')) {
                        if (showFooter) {
                            footersVisibility.push(tr.is(':visible'));
                        }
                        groupsCount++;
                    }
                    if (tr.hasClass('k-group-footer')) {
                        if (showFooter) {
                            var toggleVisibility = footersVisibility.pop();
                            tr.toggle(toggleVisibility);
                            relatedGroup.eq(idx).toggle(toggleVisibility);
                        }
                        if (groupsCount == 1) {
                            tr.show();
                            relatedGroup.eq(idx).show();
                        } else {
                            groupsCount--;
                        }
                    }
                }
                if (level === 0 && that.options.scrollable.endless && this._isLocked()) {
                    that._syncLockedContentHeight();
                }
            },
            _updateHeader: function (groups) {
                var that = this, container = that._isLocked() ? that.lockedHeader.find('thead') : that.thead, filterCells = container.find('tr.k-filter-row').find('th.k-group-cell').length, length = container.find('tr:first').find('th.k-group-cell').length, rows = container.children('tr:not(:first)').filter(function () {
                        return !$(this).children(':visible').length;
                    });
                if (groups > length) {
                    $(new Array(groups - length + 1).join('<th class="k-group-cell k-header" scope="col">' + that.options.messages.expandCollapseColumnHeader + '</th>')).prependTo(container.children('tr:not(.k-filter-row)'));
                    if (that.element.is(':visible')) {
                        rows.find('th.k-group-cell').hide();
                    }
                } else if (groups < length) {
                    container.find('tr').each(function () {
                        $(this).find('th.k-group-cell').filter(':eq(' + groups + '),' + ':gt(' + groups + ')').remove();
                    });
                }
                if (groups > filterCells) {
                    $(new Array(groups - filterCells + 1).join('<th class="k-group-cell k-header" scope="col">&nbsp;</th>')).prependTo(container.find('.k-filter-row'));
                }
            },
            _firstDataItem: function (data, grouped) {
                if (data && grouped) {
                    if (data.hasSubgroups) {
                        data = this._firstDataItem(data.items[0], grouped);
                    } else {
                        data = data.items[0];
                    }
                }
                return data;
            },
            _updateTablesWidth: function () {
                var that = this, tables;
                if (!that._isLocked()) {
                    return;
                }
                tables = $('>.k-grid-footer>.k-grid-footer-wrap>table', that.wrapper).add(that.thead.parent()).add(that.table);
                that._footerWidth = tableWidth(tables.eq(0));
                tables.width(that._footerWidth);
                tables = $('>.k-grid-footer>.k-grid-footer-locked>table', that.wrapper).add(that.lockedHeader.find('>table')).add(that.lockedTable);
                tables.width(tableWidth(tables.eq(0)));
            },
            hideColumn: function (column) {
                var that = this, cell, tables, idx, cols, colWidth, position, width = 0, headerCellIndex, length, footer = that.footer || that.wrapper.find('.k-grid-footer'), columns = that.columns, visibleLocked = that.lockedHeader ? leafDataCells(that.lockedHeader.find('>table>thead')).filter(isCellVisible).length : 0, columnIndex, groupHeaderColumnTemplateColumns = grep(leafColumns(that.columns), function (column) {
                        return column.groupHeaderColumnTemplate;
                    });
                if (typeof column == 'number') {
                    column = columns[column];
                } else if (isPlainObject(column)) {
                    column = grep(flatColumns(columns), function (item) {
                        return item === column;
                    })[0];
                } else {
                    column = grep(flatColumns(columns), function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || !isVisible(column)) {
                    return;
                }
                var setColumnVisibility = that._columnVisibilitySetter(column);
                if (column.columns && column.columns.length) {
                    position = columnVisiblePosition(column, columns);
                    setColumnVisibility(column, false);
                    setCellVisibility(elements($('>table>thead', that.lockedHeader), that.thead, '>tr:eq(' + position.row + ')>th'), position.cell, false);
                    for (idx = 0; idx < column.columns.length; idx++) {
                        this.hideColumn(column.columns[idx]);
                    }
                    that.trigger(COLUMNHIDE, { column: column });
                    return;
                }
                columnIndex = inArray(column, visibleColumns(leafColumns(columns)));
                setColumnVisibility(column, false);
                that._setParentsVisibility(column, false);
                that._templates();
                that._updateCols();
                that._updateLockedCols();
                var container = that.thead;
                headerCellIndex = columnIndex;
                if (that.lockedHeader && visibleLocked > columnIndex) {
                    container = that.lockedHeader.find('>table>thead');
                } else {
                    headerCellIndex -= visibleLocked;
                }
                cell = leafDataCells(container).filter(isCellVisible).eq(headerCellIndex);
                cell[0].style.display = 'none';
                setCellVisibility(elements($('>table>thead', that.lockedHeader), that.thead, '>tr.k-filter-row>th'), columnIndex, false);
                if (footer[0]) {
                    that._updateCols(footer.find('>.k-grid-footer-wrap>table'));
                    that._updateLockedCols(footer.find('>.k-grid-footer-locked>table'));
                    setCellVisibility(footer.find('.k-footer-template>td'), columnIndex, false);
                }
                if (that.lockedTable && visibleLocked > columnIndex) {
                    hideColumnCells(that.lockedTable.find('>tbody>tr'), columnIndex);
                } else {
                    hideColumnCells(that.tbody.children(), columnIndex - visibleLocked);
                }
                if (that.lockedTable) {
                    that._updateTablesWidth();
                    that._applyLockedContainersWidth();
                    that._syncLockedContentHeight();
                    that._syncLockedHeaderHeight();
                    that._syncLockedFooterHeight();
                } else {
                    cols = that.thead.prev().find('col');
                    for (idx = 0, length = cols.length; idx < length; idx += 1) {
                        colWidth = cols[idx].style.width;
                        if (colWidth && colWidth.indexOf('%') == -1) {
                            width += parseInt(colWidth, 10);
                        } else {
                            width = 0;
                            break;
                        }
                    }
                    tables = $('>.k-grid-header table:first,>.k-grid-footer table:first', that.wrapper).add(that.table);
                    that._footerWidth = null;
                    if (width) {
                        tables.each(function () {
                            this.style.width = width + 'px';
                        });
                        that._footerWidth = width;
                    }
                    if (browser.msie && browser.version == 8) {
                        tables.css('display', 'inline-table');
                        setTimeout(function () {
                            tables.css('display', 'table');
                        }, 1);
                    }
                }
                that._updateFirstColumnClass();
                if (groupHeaderColumnTemplateColumns.length > 0) {
                    that._renderGroupRows();
                }
                that.trigger(COLUMNHIDE, { column: column });
            },
            _setParentsVisibility: function (column, visible) {
                var that = this;
                var columns = that.columns;
                var idx;
                var parents = [];
                var parent;
                var position;
                var cell;
                var colSpan;
                var setColumnVisibility = that._columnVisibilitySetter(column);
                var predicate = visible ? function (p) {
                    return visibleColumns(p.columns).length && p.hidden;
                } : function (p) {
                    return !visibleColumns(p.columns).length && !p.hidden;
                };
                if (columnParents(column, columns, parents) && parents.length) {
                    for (idx = parents.length - 1; idx >= 0; idx--) {
                        parent = parents[idx];
                        position = columnPosition(parent, columns);
                        cell = elements($('>table>thead', this.lockedHeader), this.thead, '>tr:eq(' + position.row + ')>th:not(.k-group-cell):not(.k-hierarchy-cell)').eq(position.cell);
                        if (predicate(parent)) {
                            setColumnVisibility(parent, visible);
                            cell[0].style.display = visible ? '' : 'none';
                        }
                        if (cell.filter('[' + kendo.attr('colspan') + ']').length) {
                            colSpan = parseInt(cell.attr(kendo.attr('colspan')), 10);
                            cell[0].colSpan = colSpan - hiddenLeafColumnsCount(parent.columns) || 1;
                        }
                    }
                }
            },
            showColumn: function (column) {
                var that = this, idx, length, cell, tables, width, headerCellIndex, position, colWidth, cols, columns = that.columns, footer = that.footer || that.wrapper.find('.k-grid-footer'), lockedColumnsCount = that.lockedHeader ? leafDataCells(that.lockedHeader.find('>table>thead')).length : 0, columnIndex, originalColumn, columnLeafIndex, groupHeaderColumnTemplateColumns = grep(leafColumns(that.columns), function (column) {
                        return column.groupHeaderColumnTemplate;
                    });
                if (typeof column == 'number') {
                    columnIndex = column;
                    column = columns[column];
                } else if (isPlainObject(column)) {
                    $.each(flatColumns(columns), function (index, item) {
                        if (item === column) {
                            column = item;
                            columnIndex = index;
                            return false;
                        }
                    });
                } else {
                    $.each(flatColumns(columns), function (index, item) {
                        if (item.field === column) {
                            column = item;
                            columnIndex = index;
                            return false;
                        }
                    });
                }
                if (!column || isVisible(column)) {
                    return;
                }
                var setColumnVisibility = that._columnVisibilitySetter(column);
                if (column.columns && column.columns.length) {
                    position = columnPosition(column, columns);
                    originalColumn = flatColumns(that.options.columns)[columnIndex];
                    setColumnVisibility(column, true);
                    setCellVisibility(elements($('>table>thead', that.lockedHeader), that.thead, '>tr:eq(' + position.row + ')>th'), position.cell, true);
                    for (idx = 0; idx < column.columns.length; idx++) {
                        if (!originalColumn.columns[idx].hidden) {
                            this.showColumn(column.columns[idx]);
                        }
                    }
                    that.trigger(COLUMNSHOW, { column: column });
                    return;
                }
                columnLeafIndex = inArray(column, leafColumns(columns));
                setColumnVisibility(column, true);
                that._setParentsVisibility(column, true);
                that._templates();
                that._updateCols();
                that._updateLockedCols();
                var container = that.thead;
                headerCellIndex = columnLeafIndex;
                if (that.lockedHeader && lockedColumnsCount > columnLeafIndex) {
                    container = that.lockedHeader.find('>table>thead');
                } else {
                    headerCellIndex -= lockedColumnsCount;
                }
                cell = leafDataCells(container).eq(headerCellIndex);
                cell[0].style.display = '';
                setCellVisibility(elements($('>table>thead', that.lockedHeader), that.thead, '>tr.k-filter-row>th'), columnLeafIndex, true);
                if (footer[0]) {
                    that._updateCols(footer.find('>.k-grid-footer-wrap>table'));
                    that._updateLockedCols(footer.find('>.k-grid-footer-locked>table'));
                    setCellVisibility(footer.find('.k-footer-template>td'), columnLeafIndex, true);
                }
                if (that.lockedTable && lockedColumnsCount > columnLeafIndex) {
                    showColumnCells(that.lockedTable.find('>tbody>tr'), columnLeafIndex);
                } else {
                    showColumnCells(that.tbody.children(), columnLeafIndex - lockedColumnsCount);
                }
                if (that.lockedTable) {
                    that._updateTablesWidth();
                    that._applyLockedContainersWidth();
                    that._syncLockedContentHeight();
                    that._syncLockedHeaderHeight();
                } else {
                    tables = $('>.k-grid-header table:first,>.k-grid-footer table:first', that.wrapper).add(that.table);
                    if (!column.width) {
                        tables.width('');
                    } else {
                        width = 0;
                        cols = that.thead.prev().find('col');
                        for (idx = 0, length = cols.length; idx < length; idx += 1) {
                            colWidth = cols[idx].style.width;
                            if (colWidth.indexOf('%') > -1) {
                                width = 0;
                                break;
                            }
                            width += parseInt(colWidth, 10);
                        }
                        that._footerWidth = null;
                        if (width) {
                            tables.each(function () {
                                this.style.width = width + 'px';
                            });
                            that._footerWidth = width;
                        }
                    }
                }
                that._updateFirstColumnClass();
                if (groupHeaderColumnTemplateColumns.length > 0) {
                    that._renderGroupRows();
                }
                that.trigger(COLUMNSHOW, { column: column });
            },
            _columnVisibilitySetter: function (column) {
                var col = column || {};
                if (isUndefined(col.media)) {
                    return setColumnVisibility;
                } else {
                    return setColumnMediaVisibility;
                }
            },
            _progress: function (toggle) {
                var element = this.element;
                var endless = this.options.scrollable && this.options.scrollable.endless;
                if (this._editContainer && this._editMode() === 'popup') {
                    element = this._editContainer;
                } else if (this.lockedContent || endless) {
                    element = this.wrapper;
                } else if (this.element.is('table')) {
                    element = this.element.parent();
                } else if (this.content && this.content.length) {
                    element = this.content;
                }
                if (endless && toggle) {
                    kendo.ui.progress(element, toggle, {
                        height: this.content.height(),
                        top: this.content[0].offsetTop,
                        opacity: true
                    });
                } else {
                    kendo.ui.progress(element, toggle);
                }
            },
            _resize: function (size, force) {
                this._syncLockedContentHeight();
                this._syncLockedHeaderHeight();
                if (this.content) {
                    this._setContentWidth();
                    this._setContentHeight();
                }
                if (this.lockedTable) {
                    this.lockedContent[0].scrollTop = this.content[0].scrollTop;
                    if (this.virtualScrollable) {
                        this.lockedContent[0].scrollTop = this.wrapper.find('.k-virtual-scrollable-wrap')[0].scrollTop;
                    }
                }
                if (this.virtualScrollable && (force || this._rowHeight)) {
                    if (force) {
                        this._rowHeight = null;
                    }
                    this.virtualScrollable.repaintScrollbar();
                }
                if (this.pager && this.pager.element) {
                    this.pager.resize(force);
                }
            },
            _isActiveInTable: function () {
                var active = activeElement();
                if (!active) {
                    return false;
                }
                return this.table[0] === active || $.contains(this.table[0], active) || this._isLocked() && (this.lockedTable[0] === active || $.contains(this.lockedTable[0], active));
            },
            refresh: function (e) {
                var that = this, data = that.dataSource.view(), navigatable = that.options.navigatable, currentIndex, current = $(that.current()), isCurrentInHeader = false, groups = (that.dataSource.group() || []).length, colspan = groups + visibleLeafColumns(visibleColumns(that.columns)).length, contentScrollLeft, cachedItemsToSkip;
                if (e && e.action === 'itemchange' && (that.editable || that.options.scrollable.endless)) {
                    if (this._editMode() != 'popup' || this._editMode() === 'popup' && !that._editableIsClosing) {
                        return;
                    }
                }
                if (e && e.action === 'remove' && that.editable && that.editable.options.model && inArray(that.editable.options.model, e.items) > -1) {
                    that.editable.options.model.unbind(CHANGE, that._modelChangeHandler);
                }
                e = e || {};
                if (that.trigger('dataBinding', {
                        action: e.action || 'rebind',
                        index: e.index,
                        items: e.items
                    })) {
                    return;
                }
                if (e.action === SYNC && that._isVirtualEditable()) {
                    that._destroyEditable();
                    that._clearEditableState();
                }
                that._angularItems('cleanup');
                if (!that._endlessFetchInProgress) {
                    if (navigatable && (that._isActiveInTable() || that._editContainer && that._editContainer.data('kendoWindow'))) {
                        isCurrentInHeader = current.is('th');
                        currentIndex = isCurrentInHeader ? current.parent().children(':not(.k-group-cell)').index(current[0]) : Math.max(that.cellIndex(current), 0);
                    }
                    that._destroyEditable();
                }
                if (that.options.scrollable && that.options.scrollable.endless) {
                    clearTimeout(that._progressTimeOut);
                    that._progressTimeOut = setTimeout(function () {
                        if (!that._endlessFetchInProgress) {
                            that._progress(false);
                        }
                    }, 100);
                } else {
                    that._progress(false);
                }
                that._hideResizeHandle();
                that._data = [];
                if (!that.columns.length) {
                    that._autoColumns(that._firstDataItem(data[0], groups));
                    colspan = groups + that.columns.length;
                }
                that._group = groups > 0 || that._group;
                if (that._group) {
                    that._templates();
                    that._updateCols();
                    that._updateLockedCols();
                    that._updateHeader(groups);
                    that._group = groups > 0;
                    that._groupRows = groupRows(data);
                }
                if (that.content) {
                    contentScrollLeft = that.content.scrollLeft();
                }
                cachedItemsToSkip = that._skipRerenderItemsCount;
                that._renderContent(data, colspan, groups);
                if (that.options.scrollable && that.options.scrollable.endless && this.lockedContent) {
                    that._skipRerenderItemsCount = cachedItemsToSkip;
                }
                that._renderLockedContent(data, colspan, groups);
                that._footer();
                that._renderNoRecordsContent();
                that._togglePagerVisibility();
                that._setContentHeight();
                that._setContentWidth(that.content && contentScrollLeft);
                if (that.lockedTable) {
                    if (that.options.scrollable.virtual) {
                        that.content.find('>.k-virtual-scrollable-wrap').trigger('scroll');
                    } else if (that.touchScroller) {
                        that.touchScroller.movable.trigger('change');
                    } else {
                        that.wrapper.one('scroll', function (e) {
                            e.stopPropagation();
                        });
                        that.content.trigger('scroll');
                    }
                }
                if (!that._endlessFetchInProgress) {
                    that._restoreCurrent(currentIndex, isCurrentInHeader);
                }
                if (that.touchScroller) {
                    that.touchScroller.contentResized();
                }
                if (that.selectable) {
                    that.selectable.resetTouchEvents();
                }
                that._muteAngularRebind(function () {
                    that._angularItems('compile');
                });
                if (that._checkBoxSelection) {
                    that._toggleHeaderCheckState(false);
                }
                if (that.options.persistSelection && (that.selectable && !kendo.ui.Selectable.parseOptions(that.options.selectable).cell || that._checkBoxSelection) && that.items().length) {
                    that._restoreSelection();
                } else {
                    that._selectedIds = {};
                }
                that.trigger(DATABOUND);
            },
            _restoreCurrent: function (currentIndex, isCurrentInHeader) {
                if (currentIndex === undefined || currentIndex < 0) {
                    return;
                }
                this._removeCurrent();
                if (isCurrentInHeader) {
                    this._setCurrent(this.thead.find('th:not(.k-group-cell)').eq(currentIndex));
                } else {
                    var rowIndex = 0;
                    if (this._rowVirtualIndex) {
                        rowIndex = this.virtualScrollable.position(this._rowVirtualIndex);
                    } else {
                        currentIndex = 0;
                    }
                    var row = $();
                    if (this.lockedTable) {
                        row = this.lockedTable.find('>tbody>tr').eq(rowIndex);
                    }
                    row = row.add(this.tbody.children().eq(rowIndex));
                    var td = row.find('>td:not(.k-group-cell):not(.k-hierarchy-cell)').eq(currentIndex);
                    this._setCurrent(td);
                }
                if (this._current) {
                    focusTable(this._current.closest('table')[0], true);
                }
            },
            _restoreSelection: function () {
                var that = this, allRows = that.items(), selectedRows, id = isFunction(that.dataSource.options.schema.model) ? that.dataSource.options.schema.model.fn.idField : that.dataSource.options.schema.model.id;
                selectedRows = grep(allRows, function (row) {
                    var dataItemKey = that.dataItem(row)[id];
                    if (that._selectedIds[dataItemKey]) {
                        return row;
                    }
                });
                that.select(selectedRows);
            },
            _angularItems: function (cmd) {
                kendo.ui.DataBoundWidget.fn._angularItems.call(this, cmd);
                if (cmd === 'cleanup' && (!this.dataSource || !this.dataSource.options.endless)) {
                    this._cleanupDetailItems();
                }
                this._angularGroupItems(cmd);
                this._angularGroupFooterItems(cmd);
            },
            _cleanupDetailItems: function () {
                var that = this;
                if (that._hasDetails()) {
                    that.angular('cleanup', function () {
                        return { elements: that.tbody.children('.k-detail-row') };
                    });
                    that.tbody.find('.k-detail-cell').empty();
                }
            },
            _angularGroupItems: function (cmd) {
                var that = this, container = that.tbody;
                if (that.lockedContent) {
                    container = that.lockedTable.find('tbody');
                }
                if (that._group) {
                    that.angular(cmd, function () {
                        return {
                            elements: container.children('.k-grouping-row'),
                            data: $.map(groupRows(that.dataSource.view()), function (dataItem) {
                                return { dataItem: dataItem };
                            })
                        };
                    });
                }
            },
            _angularGroupFooterItems: function (cmd) {
                var that = this, container = that.tbody;
                if (that.lockedContent) {
                    container = that.element;
                }
                if (that._group && that.groupFooterTemplate) {
                    that.angular(cmd, function () {
                        return {
                            elements: container.find('.k-group-footer'),
                            data: $.map(groupFooters(that.dataSource.view()), function (dataItem) {
                                return { dataItem: dataItem };
                            })
                        };
                    });
                }
            },
            _renderContent: function (data, colspan, groups) {
                var that = this, idx, length, html = '', isLocked = that.lockedContent != null, endlessAppend = null, skipLastGroup, flatViewLength, scrollable = that.options.scrollable, templates = {
                        rowTemplate: that.rowTemplate,
                        altRowTemplate: that.altRowTemplate,
                        groupFooterTemplate: that.groupFooterTemplate,
                        groupHeaderColumnTemplate: that.groupHeaderColumnTemplate
                    };
                if (scrollable && scrollable.endless && !that.dataSource.options.endless) {
                    that._skipRerenderItemsCount = 0;
                    if (that.content) {
                        that.content[0].scrollTop = 0;
                    }
                }
                endlessAppend = that._skipRerenderItemsCount > 0;
                colspan = isLocked ? colspan - visibleLeafColumns(visibleLockedColumns(that.columns)).length : colspan;
                if (groups > 0) {
                    colspan = isLocked ? colspan - groups : colspan;
                    if (that.detailTemplate) {
                        colspan++;
                    }
                    if (that.groupFooterTemplate) {
                        that._groupAggregatesDefaultObject = that.dataSource.aggregates();
                    }
                    if (that.options.scrollable.endless) {
                        flatViewLength = that.dataSource.flatView().length;
                    }
                    for (idx = 0, length = data.length; idx < length; idx++) {
                        if (!that._skippedGroups) {
                            that._skippedGroups = [];
                        }
                        skipLastGroup = flatViewLength && idx === data.length - 1 && flatViewLength !== that.dataSource.total();
                        html += that._groupRowHtml(data[idx], colspan, 0, isLocked ? groupRowLockedContentBuilder : groupRowBuilder, templates, isLocked, skipLastGroup);
                    }
                } else {
                    html += that._rowsHtml(data, templates);
                }
                if (endlessAppend) {
                    that.tbody.append(html);
                    clearTimeout(that._endlessFetchTimeOut);
                    that._endlessFetchTimeOut = setTimeout(function () {
                        if (that._groupToCollapse) {
                            that.collapseGroup(that._groupToCollapse);
                            that._groupToCollapse = null;
                        }
                    });
                    that._endlessFetchInProgress = null;
                } else {
                    that.tbody = appendContent(that.tbody, that.table, html, this.options.$angular);
                }
            },
            _renderGroupRows: function () {
                var that = this, data = that._groupRows, groupRows = that.wrapper.find('.k-grouping-row'), groups = that._groups(), groupRowBuilderFunc, isLocked = that.lockedContent != null, columns, colspan, group, field, column, template, text, groupHeaderData, tableContainer, isInLockedContainer, prevElement, newGroupRowElement, currentRow, level, groupHeaderColumnTemplate, firstColumnGroupData;
                groupRows.each(function (index, row) {
                    currentRow = $(row);
                    tableContainer = currentRow.closest('table').parent();
                    isInLockedContainer = tableContainer.is('.' + CONTENTRLOCKEDCONTAINER);
                    columns = isInLockedContainer ? visibleLeafColumns(visibleColumns(lockedColumns(that.columns))) : visibleLeafColumns(visibleColumns(nonLockedColumns(that.columns)));
                    level = currentRow.find('.' + GROUPCELLCLASS).length;
                    if (isLocked) {
                        groupRowBuilderFunc = isInLockedContainer ? groupRowBuilder : groupRowLockedContentBuilder;
                        colspan = isInLockedContainer ? columns.length + groups - level : columns.length;
                    } else {
                        groupRowBuilderFunc = groupRowBuilder;
                        colspan = columns.length + groups - level;
                    }
                    group = index >= data.length ? data[index - data.length] : data[index];
                    field = group.field;
                    column = grep(leafColumns(that.columns), function (column) {
                        return column.field == field;
                    })[0] || {};
                    firstColumnGroupData = !column.groupHeaderTemplate && visibleColumns(that.columns)[0].groupHeaderColumnTemplate ? visibleColumns(that.columns)[0] : false;
                    template = column.groupHeaderTemplate ? column.groupHeaderTemplate : visibleColumns(that.columns)[0].groupHeaderColumnTemplate;
                    text = (column.title || field) + ': ' + formatGroupValue(group.value, column.format, column.values, column.encoded);
                    groups = groups;
                    groupHeaderData = that._groupData(group, false, firstColumnGroupData);
                    groupHeaderColumnTemplate = isInLockedContainer ? that.lockedGroupHeaderColumnTemplate : that.groupHeaderColumnTemplate;
                    if (template) {
                        text = typeof template === FUNCTION ? template(groupHeaderData) : kendo.template(template)(groupHeaderData);
                    }
                    prevElement = currentRow.prev().length ? currentRow.prev() : currentRow.parent();
                    newGroupRowElement = $(groupHeaderColumnTemplate ? groupHeaderColumnTemplate(extend({}, groupHeaderData, {
                        groupCells: level,
                        colspan: groups - level,
                        text: text
                    })) : groupRowBuilderFunc(colspan, level, text));
                    if (prevElement.is('tbody')) {
                        prevElement.prepend(newGroupRowElement);
                    } else {
                        prevElement.after(newGroupRowElement);
                    }
                    currentRow.remove();
                });
            },
            _renderLockedContent: function (data, colspan, groups) {
                var html = '', idx, length, endlessAppend = null, templates = {
                        rowTemplate: this.lockedRowTemplate,
                        altRowTemplate: this.lockedAltRowTemplate,
                        groupFooterTemplate: this.lockedGroupFooterTemplate,
                        groupHeaderColumnTemplate: this.lockedGroupHeaderColumnTemplate
                    };
                if (this.lockedContent) {
                    var table = this.lockedTable;
                    endlessAppend = this._skipRerenderItemsCount > 0;
                    if (groups > 0) {
                        colspan = colspan - visibleColumns(leafColumns(nonLockedColumns(this.columns))).length;
                        for (idx = 0, length = data.length; idx < length; idx++) {
                            html += this._groupRowHtml(data[idx], colspan, 0, groupRowBuilder, templates, false, this.options.scrollable.endless && idx === data.length - 1);
                        }
                    } else {
                        html = this._rowsHtml(data, templates);
                    }
                    if (endlessAppend) {
                        table.children('tbody').append(html);
                    } else {
                        appendContent(table.children('tbody'), table, html, this.options.$angular);
                    }
                    this._syncLockedContentHeight();
                }
            },
            _togglePagerVisibility: function () {
                if (this.options.pageable.alwaysVisible === false) {
                    this.wrapper.find('.k-grid-pager').toggle(this.dataSource.total() >= this.dataSource.pageSize());
                }
            },
            _adjustRowsHeight: function (table1, table2) {
                var rows = table1[0].rows, length = rows.length, idx, rows2 = table2[0].rows, containers = table1.add(table2), containersLength = containers.length, heights = [];
                for (idx = 0; idx < length; idx++) {
                    if (!rows2[idx]) {
                        break;
                    }
                    if (rows[idx].style.height) {
                        rows[idx].style.height = rows2[idx].style.height = '';
                    }
                }
                for (idx = 0; idx < length; idx++) {
                    if (!rows2[idx]) {
                        break;
                    }
                    var offsetHeight1 = rows[idx].offsetHeight;
                    var offsetHeight2 = rows2[idx].offsetHeight;
                    var height = 0;
                    if (offsetHeight1 > offsetHeight2) {
                        height = offsetHeight1;
                    } else if (offsetHeight1 < offsetHeight2) {
                        height = offsetHeight2;
                    }
                    heights.push(height);
                }
                for (idx = 0; idx < containersLength; idx++) {
                    containers[idx].style.display = 'none';
                }
                for (idx = 0; idx < length; idx++) {
                    if (heights[idx]) {
                        rows[idx].style.height = rows2[idx].style.height = heights[idx] + 1 + 'px';
                    }
                }
                for (idx = 0; idx < containersLength; idx++) {
                    containers[idx].style.display = '';
                }
            }
        });
        if (kendo.ExcelMixin) {
            kendo.ExcelMixin.extend(Grid.prototype);
        }
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(Grid.prototype);
            Grid.prototype._drawPDF_autoPageBreak = function (progress) {
                var grid = this;
                var result = new $.Deferred();
                var dataSource = grid.dataSource;
                var allPages = grid.options.pdf.allPages;
                var origBody = grid.wrapper.find('table[role$="grid"] > tbody');
                var cont = $('<div>').css({
                    position: 'absolute',
                    left: -10000,
                    top: -10000
                });
                var clone = grid.wrapper.clone().css({
                    height: 'auto',
                    width: 'auto'
                }).appendTo(cont);
                clone.find('.k-grid-content').css({
                    height: 'auto',
                    width: 'auto',
                    overflow: 'visible'
                });
                clone.find('table[role$="grid"], .k-grid-footer table').css({
                    height: 'auto',
                    width: '100%',
                    overflow: 'visible'
                });
                clone.find('.k-grid-pager, .k-grid-toolbar, .k-grouping-header').remove();
                clone.find('.k-grid-header, .k-grid-footer').css({ paddingRight: 0 });
                this._initPDFProgress(progress);
                var body = clone.find('table[role$="grid"] > tbody').empty();
                var startingPage = dataSource.page();
                function resolve() {
                    if (allPages && startingPage !== undefined) {
                        dataSource.one('change', draw);
                        dataSource.page(startingPage);
                    } else {
                        grid.refresh();
                        draw();
                    }
                }
                function draw() {
                    cont.appendTo(document.body);
                    var options = $.extend({}, grid.options.pdf, {
                        _destructive: true,
                        progress: function (p) {
                            progress.notify({
                                page: p.page,
                                pageNumber: p.pageNum,
                                progress: 0.5 + p.pageNum / p.totalPages / 2,
                                totalPages: p.totalPages
                            });
                        }
                    });
                    kendo.drawing.drawDOM(clone, options).always(function () {
                        cont.remove();
                    }).then(function (group) {
                        result.resolve(group);
                    }).fail(function (err) {
                        result.reject(err);
                    });
                }
                function renderPage() {
                    var pageNum = dataSource.page();
                    var totalPages = allPages ? dataSource.totalPages() : 1;
                    body.append(origBody.find('tr'));
                    if (pageNum < totalPages) {
                        dataSource.page(pageNum + 1);
                    } else {
                        dataSource.unbind('change', renderPage);
                        resolve();
                    }
                }
                if (allPages) {
                    dataSource.bind('change', renderPage);
                    dataSource.page(1);
                } else {
                    renderPage();
                }
                return result.promise();
            };
            Grid.prototype._drawPDF = function (progress) {
                var grid = this;
                if (grid.options.pdf.paperSize && grid.options.pdf.paperSize != 'auto') {
                    return grid._drawPDF_autoPageBreak(progress);
                }
                var result = new $.Deferred();
                var dataSource = grid.dataSource;
                var allPages = grid.options.pdf.allPages;
                this._initPDFProgress(progress);
                var doc = new kendo.drawing.Group();
                var startingPage = dataSource.page();
                function resolve() {
                    if (allPages && startingPage !== undefined) {
                        dataSource.unbind('change', exportPage);
                        dataSource.one('change', function () {
                            result.resolve(doc);
                        });
                        dataSource.page(startingPage);
                    } else {
                        result.resolve(doc);
                    }
                }
                function exportPage() {
                    grid._drawPDFShadow({ width: grid.wrapper.width() }, { avoidLinks: grid.options.pdf.avoidLinks }).done(function (group) {
                        var pageNum = dataSource.page();
                        var totalPages = allPages ? dataSource.totalPages() : 1;
                        var args = {
                            page: group,
                            pageNumber: pageNum,
                            progress: pageNum / totalPages,
                            totalPages: totalPages
                        };
                        progress.notify(args);
                        doc.append(args.page);
                        if (pageNum < totalPages) {
                            dataSource.page(pageNum + 1);
                        } else {
                            resolve();
                        }
                    }).fail(function (err) {
                        result.reject(err);
                    });
                }
                if (allPages) {
                    dataSource.bind('change', exportPage);
                    dataSource.page(1);
                } else {
                    exportPage();
                }
                return result.promise();
            };
            Grid.prototype._initPDFProgress = function (deferred) {
                var loading = $('<div class=\'k-loading-pdf-mask\'><div class=\'k-loading-color\'/></div>');
                loading.prepend(this.wrapper.clone().css({
                    position: 'absolute',
                    top: 0,
                    left: 0
                }));
                this.wrapper.append(loading);
                var pb = $('<div class=\'k-loading-pdf-progress\'>').appendTo(loading).kendoProgressBar({
                    type: 'chunk',
                    chunkCount: 10,
                    min: 0,
                    max: 1,
                    value: 0
                }).data('kendoProgressBar');
                deferred.progress(function (e) {
                    pb.value(e.progress);
                }).always(function () {
                    kendo.destroy(loading);
                    loading.remove();
                });
            };
        }
        function syncTableHeight(table1, table2) {
            table1 = table1[0];
            table2 = table2[0];
            if (table1.rows.length !== table2.rows.length) {
                var lockedHeigth = table1.offsetHeight;
                var tableHeigth = table2.offsetHeight;
                var row;
                var diff;
                if (lockedHeigth > tableHeigth) {
                    row = table2.rows[table2.rows.length - 1];
                    if (filterRowRegExp.test(row.className)) {
                        row = table2.rows[table2.rows.length - 2];
                    }
                    diff = lockedHeigth - tableHeigth;
                } else {
                    row = table1.rows[table1.rows.length - 1];
                    if (filterRowRegExp.test(row.className)) {
                        row = table1.rows[table1.rows.length - 2];
                    }
                    diff = tableHeigth - lockedHeigth;
                }
                row.style.height = row.offsetHeight + diff + 'px';
            }
        }
        function adjustRowHeight(row1, row2) {
            var height;
            var offsetHeight1 = row1.offsetHeight;
            var offsetHeight2 = row2.offsetHeight;
            if (offsetHeight1 > offsetHeight2) {
                height = offsetHeight1 + 'px';
            } else if (offsetHeight1 < offsetHeight2) {
                height = offsetHeight2 + 'px';
            }
            if (height) {
                row1.style.height = row2.style.height = height;
            }
        }
        function getCommand(commands, name) {
            var idx, length, command;
            if (typeof commands === STRING && commands === name) {
                return commands;
            }
            if (isPlainObject(commands) && commands.name === name) {
                return commands;
            }
            if (isArray(commands)) {
                for (idx = 0, length = commands.length; idx < length; idx++) {
                    command = commands[idx];
                    if (typeof command === STRING && command === name || command.name === name) {
                        return command;
                    }
                }
            }
            return null;
        }
        function focusTable(table, direct) {
            if (direct === true) {
                table = $(table);
                var scrollLeft = table.parent().scrollLeft();
                kendo.focusElement(table);
                table.parent().scrollLeft(scrollLeft);
            } else {
                $(table).one('focusin', function (e) {
                    e.preventDefault();
                }).focus();
            }
        }
        function isColumnGroupable(grid, column) {
            return grid.options.groupable && (column.groupable || column.groupable === undefined);
        }
        function isGroupedBy(groups, field) {
            return !!$.grep(groups, function (item) {
                return item.field === field;
            }).length;
        }
        function isColumnEditable(column, model) {
            if (!column.field || column.selectable) {
                return false;
            }
            if (model.editable && !model.editable(column.field)) {
                return false;
            }
            if (column.editable && !column.editable(model)) {
                return false;
            }
            return true;
        }
        function isInputElement(element) {
            return $(element).is(':button,a,:input,a>.k-icon,textarea,span.k-select,span.k-icon,span.k-link,label.k-checkbox-label,.k-input,.k-multiselect-wrap,.k-picker-wrap,.k-picker-wrap>.k-selected-color,.k-tool-icon,.k-dropdown');
        }
        function tableClick(e) {
            var currentTarget = $(e.currentTarget), isHeader = currentTarget.is('th'), table = this.table.add(this.lockedTable), headerTable = this.thead.parent().add($('>table', this.lockedHeader)), isInput = isInputElement(e.target), preventScroll = $(e.target).is('.k-checkbox-label, .k-checkbox'), target = $(e.target), currentTable = currentTarget.closest('table')[0];
            if (isInput && currentTarget.find(kendo.roleSelector('filtercell')).length) {
                this._setCurrent(currentTarget);
                return;
            }
            if (currentTable !== table[0] && currentTable !== table[1] && currentTable !== headerTable[0] && currentTable !== headerTable[1]) {
                return;
            }
            if (target.is('a.k-i-expand, a.k-i-collapse')) {
                return;
            }
            if (this.options.navigatable) {
                this._setCurrent(currentTarget, false, preventScroll);
            }
            if (isHeader || !isInput) {
                setTimeout(function () {
                    if (!(isIE8 && $(kendo._activeElement()).hasClass('k-widget'))) {
                        if ($(kendo._activeElement()).is(CHECKBOXINPUT) || !isInputElement(kendo._activeElement()) || !$.contains(currentTable, kendo._activeElement())) {
                            focusTable(currentTable, true);
                        }
                    }
                });
            }
            if (isHeader && !kendo.support.touch) {
                e.preventDefault();
            }
        }
        function leftMostPosition(element, rtl) {
            if (!rtl) {
                return 0;
            }
            var result = 0;
            if (kendo.support.browser.webkit) {
                result = element.width();
            }
            return result;
        }
        function isInEdit(cell) {
            return cell && (cell.hasClass('k-edit-cell') || cell.parent().hasClass('k-grid-edit-row'));
        }
        function groupCellBuilder(headerTemplateIndex) {
            return '<td colspan="#=data.colspan +' + headerTemplateIndex + '#">' + '<p class="k-reset">' + '<a class="k-icon k-i-collapse" href="\\#" tabindex="-1" ' + ARIALABEL + '="' + COLLAPSE + '"></a>#=data.text#' + '</p></td>';
        }
        function groupCellLockedContentBuilder(headerTemplateIndex) {
            return '<td colspan="' + headerTemplateIndex + '">' + '<p class="k-reset">&nbsp;</p></td>';
        }
        function groupRowBuilder(colspan, level, text) {
            return '<tr role="row" class="k-grouping-row">' + groupCells(level) + '<td colspan="' + colspan + '" aria-expanded="true">' + '<p class="k-reset">' + '<a class="k-icon k-i-collapse" href="#" tabindex="-1" ' + ARIALABEL + '="' + COLLAPSE + '"></a>' + text + '</p></td></tr>';
        }
        function groupRowLockedContentBuilder(colspan) {
            return '<tr role="row" class="k-grouping-row">' + '<td colspan="' + colspan + '" aria-expanded="true">' + '<p class="k-reset">&nbsp;</p></td></tr>';
        }
        ui.plugin(Grid);
        ui.plugin(VirtualScrollable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.listview', [
        'kendo.data',
        'kendo.editable',
        'kendo.selectable'
    ], f);
}(function () {
    var __meta__ = {
        id: 'listview',
        name: 'ListView',
        category: 'web',
        description: 'The ListView widget offers rich support for interacting with data.',
        depends: ['data'],
        features: [
            {
                id: 'listview-editing',
                name: 'Editing',
                description: 'Support for record editing',
                depends: ['editable']
            },
            {
                id: 'listview-selection',
                name: 'Selection',
                description: 'Support for selection',
                depends: ['selectable']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, CHANGE = 'change', CANCEL = 'cancel', DATABOUND = 'dataBound', DATABINDING = 'dataBinding', Widget = kendo.ui.Widget, keys = kendo.keys, FOCUSSELECTOR = '>*:not(.k-loading-mask)', PROGRESS = 'progress', ERROR = 'error', FOCUSED = 'k-state-focused', SELECTED = 'k-state-selected', KEDITITEM = 'k-edit-item', EDIT = 'edit', REMOVE = 'remove', SAVE = 'save', MOUSEDOWN = 'mousedown', CLICK = 'click', TOUCHSTART = 'touchstart', NS = '.kendoListView', proxy = $.proxy, activeElement = kendo._activeElement, progress = kendo.ui.progress, DataSource = kendo.data.DataSource;
        var ListView = kendo.ui.DataBoundWidget.extend({
            init: function (element, options) {
                var that = this;
                options = $.isArray(options) ? { dataSource: options } : options;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                that.wrapper = element = that.element;
                if (element[0].id) {
                    that._itemId = element[0].id + '_lv_active';
                }
                that._element();
                that._dataSource();
                that._templates();
                that._navigatable();
                that._selectable();
                that._pageable();
                that._crudHandlers();
                that._scrollable();
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                }
                kendo.notify(that);
            },
            events: [
                CHANGE,
                CANCEL,
                DATABINDING,
                DATABOUND,
                EDIT,
                REMOVE,
                SAVE
            ],
            options: {
                name: 'ListView',
                autoBind: true,
                selectable: false,
                navigatable: false,
                height: null,
                template: '',
                altTemplate: '',
                editTemplate: ''
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._templates();
                if (this.selectable) {
                    this.selectable.destroy();
                    this.selectable = null;
                }
                this._selectable();
            },
            _templates: function () {
                var options = this.options;
                this.template = kendo.template(options.template || '');
                this.altTemplate = kendo.template(options.altTemplate || options.template);
                this.editTemplate = kendo.template(options.editTemplate || '');
            },
            _item: function (action) {
                return this.element.children()[action]();
            },
            items: function () {
                return this.element.children();
            },
            dataItem: function (element) {
                var attr = kendo.attr('uid');
                var uid = $(element).closest('[' + attr + ']').attr(attr);
                return this.dataSource.getByUid(uid);
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                if (this.options.autoBind) {
                    dataSource.fetch();
                }
            },
            _unbindDataSource: function () {
                var that = this;
                that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler);
            },
            _dataSource: function () {
                var that = this;
                if (that.dataSource && that._refreshHandler) {
                    that._unbindDataSource();
                } else {
                    that._refreshHandler = proxy(that.refresh, that);
                    that._progressHandler = proxy(that._progress, that);
                    that._errorHandler = proxy(that._error, that);
                }
                that.dataSource = DataSource.create(that.options.dataSource).bind(CHANGE, that._refreshHandler).bind(PROGRESS, that._progressHandler).bind(ERROR, that._errorHandler);
            },
            _progress: function (toggle) {
                var element = this.element;
                progress(element, toggle, { opacity: true });
            },
            _error: function () {
                progress(this.element, false);
            },
            _element: function () {
                var height = this.options.height;
                this.element.addClass('k-widget k-listview').attr('role', 'listbox');
                if (height) {
                    this.element.css('height', height);
                }
            },
            refresh: function (e) {
                var that = this, view = that.dataSource.view(), data, items, item, html = '', idx, length, template = that.template, altTemplate = that.altTemplate, active = activeElement(), endlessAppend = that._endlessFetchInProgress, index = endlessAppend ? that._skipRerenderItemsCount : 0, scrollable = that.options.scrollable;
                e = e || {};
                if (e.action === 'itemchange') {
                    if (!that._hasBindingTarget() && !that.editable) {
                        data = e.items[0];
                        item = that.items().filter('[' + kendo.attr('uid') + '=' + data.uid + ']');
                        if (item.length > 0) {
                            idx = item.index();
                            that.angular('cleanup', function () {
                                return { elements: [item] };
                            });
                            item.replaceWith(template(data));
                            item = that.items().eq(idx);
                            item.attr(kendo.attr('uid'), data.uid);
                            that.angular('compile', function () {
                                return {
                                    elements: [item],
                                    data: [{ dataItem: data }]
                                };
                            });
                            that.trigger('itemChange', {
                                item: item,
                                data: data
                            });
                        }
                    }
                    return;
                }
                if (that.trigger(DATABINDING, {
                        action: e.action || 'rebind',
                        items: e.items,
                        index: e.index
                    })) {
                    return;
                }
                that._angularItems('cleanup');
                if (!endlessAppend) {
                    that._destroyEditable();
                }
                for (idx = index, length = view.length; idx < length; idx++) {
                    if (idx % 2) {
                        html += altTemplate(view[idx]);
                    } else {
                        html += template(view[idx]);
                    }
                }
                if (endlessAppend) {
                    that.element.append(html);
                } else {
                    that.element.html(html);
                }
                items = that.items().not('.k-loading-mask');
                for (idx = index, length = view.length; idx < length; idx++) {
                    items.eq(idx).attr(kendo.attr('uid'), view[idx].uid).attr('role', 'option').attr('aria-selected', 'false');
                }
                if (that.element[0] === active && that.options.navigatable) {
                    if (that._focusNext) {
                        that.current(that.current().next());
                    } else {
                        if (!scrollable) {
                            that.current(items.eq(0));
                        }
                    }
                }
                that._angularItems('compile');
                that._progress(false);
                that._endlessFetchInProgress = null;
                that.trigger(DATABOUND, {
                    action: e.action || 'rebind',
                    items: e.items,
                    index: e.index
                });
            },
            _pageable: function () {
                var that = this, pageable = that.options.pageable, settings, pagerId;
                if ($.isPlainObject(pageable)) {
                    pagerId = pageable.pagerId;
                    settings = $.extend({}, pageable, {
                        dataSource: that.dataSource,
                        pagerId: null
                    });
                    that.pager = new kendo.ui.Pager($('#' + pagerId), settings);
                }
            },
            _selectable: function () {
                var that = this, multi, current, selectable = that.options.selectable, navigatable = that.options.navigatable;
                if (selectable) {
                    multi = kendo.ui.Selectable.parseOptions(selectable).multiple;
                    that.selectable = new kendo.ui.Selectable(that.element, {
                        aria: true,
                        multiple: multi,
                        filter: FOCUSSELECTOR,
                        change: function () {
                            that.trigger(CHANGE);
                        }
                    });
                    if (navigatable) {
                        that.element.on('keydown' + NS, function (e) {
                            if (e.keyCode === keys.SPACEBAR) {
                                current = that.current();
                                if (e.target == e.currentTarget) {
                                    e.preventDefault();
                                }
                                if (multi) {
                                    if (!e.ctrlKey) {
                                        that.selectable.clear();
                                    } else {
                                        if (current && current.hasClass(SELECTED)) {
                                            current.removeClass(SELECTED);
                                            return;
                                        }
                                    }
                                } else {
                                    that.selectable.clear();
                                }
                                that.selectable.value(current);
                            }
                        });
                    }
                }
            },
            _scrollable: function () {
                var that = this;
                var scrollable = that.options.scrollable;
                if (scrollable) {
                    that.element.css({
                        'overflow-y': 'scroll',
                        'position': 'relative',
                        '-webkit-overflow-scrolling': 'touch'
                    });
                    if (scrollable === 'endless') {
                        var originalPageSize = that._endlessPageSize = that.dataSource.options.pageSize;
                        that.element.off('scroll' + NS).on('scroll' + NS, function () {
                            if (this.scrollTop + this.clientHeight - this.scrollHeight >= -15 && !that._endlessFetchInProgress && that._endlessPageSize < that.dataSource.total()) {
                                that._skipRerenderItemsCount = that._endlessPageSize;
                                that._endlessPageSize = that._skipRerenderItemsCount + originalPageSize;
                                that.dataSource.options.endless = true;
                                that._endlessFetchInProgress = true;
                                that.dataSource.pageSize(that._endlessPageSize);
                            }
                        });
                    }
                }
            },
            current: function (candidate) {
                var that = this, element = that.element, current = that._current, id = that._itemId;
                if (candidate === undefined) {
                    return current;
                }
                if (current && current[0]) {
                    if (current[0].id === id) {
                        current.removeAttr('id');
                    }
                    current.removeClass(FOCUSED);
                    element.removeAttr('aria-activedescendant');
                }
                if (candidate && candidate[0]) {
                    id = candidate[0].id || id;
                    that._scrollTo(candidate[0]);
                    element.attr('aria-activedescendant', id);
                    candidate.addClass(FOCUSED).attr('id', id);
                }
                that._current = candidate;
            },
            _scrollTo: function (element) {
                var that = this, container, UseJQueryoffset = false, SCROLL = 'scroll';
                if (that.wrapper.css('overflow') == 'auto' || that.wrapper.css('overflow') == SCROLL || that.wrapper.css('overflow-y') == SCROLL) {
                    container = that.wrapper[0];
                } else {
                    container = window;
                    UseJQueryoffset = true;
                }
                var scrollDirectionFunc = function (direction, dimension) {
                    var elementOffset = UseJQueryoffset ? $(element).offset()[direction.toLowerCase()] : element['offset' + direction], elementDimension = element['client' + dimension], containerScrollAmount = $(container)[SCROLL + direction](), containerDimension = $(container)[dimension.toLowerCase()]();
                    if (elementOffset + elementDimension > containerScrollAmount + containerDimension) {
                        $(container)[SCROLL + direction](elementOffset + elementDimension - containerDimension);
                    } else if (elementOffset < containerScrollAmount) {
                        $(container)[SCROLL + direction](elementOffset);
                    }
                };
                scrollDirectionFunc('Top', 'Height');
                scrollDirectionFunc('Left', 'Width');
            },
            _navigatable: function () {
                var that = this, navigatable = that.options.navigatable, element = that.element, clickCallback = function (e) {
                        that.current($(e.currentTarget));
                        if (!$(e.target).is(':button,a,:input,a>.k-icon,textarea')) {
                            kendo.focusElement(element);
                        }
                    };
                if (navigatable) {
                    that._tabindex();
                    element.on('focus' + NS, function () {
                        var current = that._current;
                        if (!current || !current.is(':visible')) {
                            current = that._item('first');
                        }
                        that.current(current);
                    }).on('focusout' + NS, function () {
                        if (that._current) {
                            that._current.removeClass(FOCUSED);
                        }
                    }).on('keydown' + NS, function (e) {
                        var key = e.keyCode, current = that.current(), target = $(e.target), canHandle = !target.is(':button,textarea,a,a>.t-icon,input'), isTextBox = target.is(':text,:password'), preventDefault = kendo.preventDefault, editItem = element.find('.' + KEDITITEM), active = activeElement(), idx, scrollable = that.options.scrollable;
                        if (!canHandle && !isTextBox && keys.ESC != key || isTextBox && keys.ESC != key && keys.ENTER != key) {
                            return;
                        }
                        if (keys.UP === key || keys.LEFT === key) {
                            if (current && current[0]) {
                                current = current.prev();
                            }
                            if (current && current[0]) {
                                that.current(current);
                            } else if (!scrollable) {
                                that.current(that._item('last'));
                            }
                            preventDefault(e);
                        } else if (keys.DOWN === key || keys.RIGHT === key) {
                            if (scrollable) {
                                if (that.options.scrollable === 'endless' && !current.next().length) {
                                    that.element[0].scrollTop = that.element[0].scrollHeight;
                                    that._focusNext = true;
                                } else {
                                    current = current.next();
                                    if (current && current[0]) {
                                        that.current(current);
                                    }
                                }
                            } else {
                                current = current.next();
                                that.current(!current || !current[0] ? that._item('first') : current);
                            }
                            preventDefault(e);
                        } else if (keys.PAGEUP === key) {
                            that.current(null);
                            that.dataSource.page(that.dataSource.page() - 1);
                            preventDefault(e);
                        } else if (keys.PAGEDOWN === key) {
                            that.current(null);
                            that.dataSource.page(that.dataSource.page() + 1);
                            preventDefault(e);
                        } else if (keys.HOME === key) {
                            that.current(that._item('first'));
                            preventDefault(e);
                        } else if (keys.END === key) {
                            that.current(that._item('last'));
                            preventDefault(e);
                        } else if (keys.ENTER === key) {
                            if (editItem.length !== 0 && (canHandle || isTextBox)) {
                                idx = that.items().index(editItem);
                                if (active) {
                                    active.blur();
                                }
                                that.save();
                                var focusAgain = function () {
                                    that.element.trigger('focus');
                                    that.current(that.items().eq(idx));
                                };
                                that.one('dataBound', focusAgain);
                            } else if (that.options.editTemplate !== '') {
                                that.edit(current);
                            }
                        } else if (keys.ESC === key) {
                            editItem = element.find('.' + KEDITITEM);
                            if (editItem.length === 0) {
                                return;
                            }
                            idx = that.items().index(editItem);
                            that.cancel();
                            that.element.trigger('focus');
                            that.current(that.items().eq(idx));
                        }
                    });
                    element.on(MOUSEDOWN + NS + ' ' + TOUCHSTART + NS, FOCUSSELECTOR, proxy(clickCallback, that));
                }
            },
            clearSelection: function () {
                var that = this;
                that.selectable.clear();
                that.trigger(CHANGE);
            },
            select: function (items) {
                var that = this, selectable = that.selectable;
                items = $(items);
                if (items.length) {
                    if (!selectable.options.multiple) {
                        selectable.clear();
                        items = items.first();
                    }
                    selectable.value(items);
                    return;
                }
                return selectable.value();
            },
            _destroyEditable: function () {
                var that = this;
                if (that.editable) {
                    that.editable.destroy();
                    delete that.editable;
                }
            },
            _modelFromElement: function (element) {
                var uid = element.attr(kendo.attr('uid'));
                return this.dataSource.getByUid(uid);
            },
            _closeEditable: function () {
                var that = this, editable = that.editable, data, item, index, template = that.template;
                if (editable) {
                    if (editable.element.index() % 2) {
                        template = that.altTemplate;
                    }
                    that.angular('cleanup', function () {
                        return { elements: [editable.element] };
                    });
                    data = that._modelFromElement(editable.element);
                    that._destroyEditable();
                    index = editable.element.index();
                    editable.element.replaceWith(template(data));
                    item = that.items().eq(index);
                    item.attr(kendo.attr('uid'), data.uid);
                    if (that._hasBindingTarget()) {
                        kendo.bind(item, data);
                    }
                    that.angular('compile', function () {
                        return {
                            elements: [item],
                            data: [{ dataItem: data }]
                        };
                    });
                }
                return true;
            },
            edit: function (item) {
                var that = this, data = that._modelFromElement(item), container, uid = data.uid, index;
                that.cancel();
                item = that.items().filter('[' + kendo.attr('uid') + '=' + uid + ']');
                index = item.index();
                item.replaceWith(that.editTemplate(data));
                container = that.items().eq(index).addClass(KEDITITEM).attr(kendo.attr('uid'), data.uid);
                that.editable = container.kendoEditable({
                    model: data,
                    clearContainer: false,
                    errorTemplate: false,
                    target: that
                }).data('kendoEditable');
                that.trigger(EDIT, {
                    model: data,
                    item: container
                });
            },
            save: function () {
                var that = this, editable = that.editable, model;
                if (!editable) {
                    return;
                }
                var container = editable.element;
                model = that._modelFromElement(container);
                if (editable.end() && !that.trigger(SAVE, {
                        model: model,
                        item: container
                    })) {
                    that._closeEditable();
                    that.dataSource.sync();
                }
            },
            remove: function (item) {
                var that = this, dataSource = that.dataSource, data = that._modelFromElement(item);
                if (that.editable) {
                    dataSource.cancelChanges(that._modelFromElement(that.editable.element));
                    that._closeEditable();
                }
                if (!that.trigger(REMOVE, {
                        model: data,
                        item: item
                    })) {
                    item.hide();
                    dataSource.remove(data);
                    dataSource.sync();
                }
            },
            add: function () {
                var that = this, dataItem, dataSource = that.dataSource, index = dataSource.indexOf((dataSource.view() || [])[0]);
                if (index < 0) {
                    index = 0;
                }
                that.cancel();
                dataItem = dataSource.insert(index, {});
                that.edit(that.element.find('[data-uid=\'' + dataItem.uid + '\']'));
            },
            cancel: function () {
                var that = this, dataSource = that.dataSource;
                if (that.editable) {
                    var container = that.editable.element;
                    var model = that._modelFromElement(container);
                    if (!that.trigger(CANCEL, {
                            model: model,
                            container: container
                        })) {
                        dataSource.cancelChanges(model);
                        that._closeEditable();
                    }
                }
            },
            _crudHandlers: function () {
                var that = this, mousedownNs = MOUSEDOWN + NS, touchstartNs = TOUCHSTART + NS, clickNs = CLICK + NS;
                that.element.on(mousedownNs + ' ' + touchstartNs, '.k-edit-button', function (e) {
                    e.preventDefault();
                    var item = $(this).closest('[' + kendo.attr('uid') + ']');
                    setTimeout(function () {
                        that.edit(item);
                    });
                });
                that.element.on(mousedownNs + ' ' + touchstartNs, '.k-delete-button', function (e) {
                    e.preventDefault();
                    var item = $(this).closest('[' + kendo.attr('uid') + ']');
                    setTimeout(function () {
                        that.remove(item);
                    });
                });
                that.element.on(clickNs, '.k-update-button', function (e) {
                    that.save();
                    e.preventDefault();
                });
                that.element.on(clickNs, '.k-cancel-button', function (e) {
                    that.cancel();
                    e.preventDefault();
                });
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that._unbindDataSource();
                that._destroyEditable();
                that.element.off(NS);
                that._endlessFetchInProgress = that._endlessPageSize = that._skipRerenderItemsCount = that._focusNext = null;
                if (that.pager) {
                    that.pager.destroy();
                }
                kendo.destroy(that.element);
            }
        });
        kendo.ui.plugin(ListView);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.listbox', [
        'kendo.draganddrop',
        'kendo.data',
        'kendo.selectable'
    ], f);
}(function () {
    var __meta__ = {
        id: 'listbox',
        name: 'ListBox',
        category: 'web',
        depends: [
            'draganddrop',
            'data',
            'selectable'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var kendoAttr = kendo.attr;
        var data = kendo.data;
        var keys = kendo.keys;
        var kendoTemplate = kendo.template;
        var Widget = kendo.ui.Widget;
        var DataSource = data.DataSource;
        var Selectable = kendo.ui.Selectable;
        var DataBoundWidget = kendo.ui.DataBoundWidget;
        var Class = kendo.Class;
        var extend = $.extend;
        var noop = $.noop;
        var proxy = $.proxy;
        var DASH = '-';
        var DOT = '.';
        var SPACE = ' ';
        var HASH = '#';
        var KENDO_LISTBOX = 'kendoListBox';
        var NS = DOT + KENDO_LISTBOX;
        var DISABLED_STATE_CLASS = 'k-state-disabled';
        var SELECTED_STATE_CLASS = 'k-state-selected';
        var ENABLED_ITEM_SELECTOR = '.k-item:not(.k-state-disabled)';
        var ENABLED_ITEMS_SELECTOR = '.k-list:not(.k-state-disabled) >' + ENABLED_ITEM_SELECTOR;
        var TOOLBAR_CLASS = 'k-listbox-toolbar';
        var TOOL_SELECTOR = 'li > a.k-button:not(.k-state-disabled)';
        var FOCUSED_CLASS = 'k-state-focused';
        var DRAG_CLUE_CLASS = 'k-drag-clue';
        var DROP_HINT_CLASS = 'k-drop-hint';
        var LIST_CLASS = 'k-reset k-list';
        var LIST_SELECTOR = '.k-reset.k-list';
        var RESET = 'k-reset';
        var CLICK = 'click' + NS;
        var KEYDOWN = 'keydown' + NS;
        var BLUR = 'blur' + NS;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var CHANGE = 'change';
        var DATABOUND = 'dataBound';
        var ADD = 'add';
        var REMOVE = 'remove';
        var REORDER = 'reorder';
        var MOVE_UP = 'moveUp';
        var MOVE_DOWN = 'moveDown';
        var TRANSFER_TO = 'transferTo';
        var TRANSFER_FROM = 'transferFrom';
        var TRANSFER_ALL_TO = 'transferAllTo';
        var TRANSFER_ALL_FROM = 'transferAllFrom';
        var DRAGGEDCLASS = 'k-ghost';
        var UNIQUE_ID = 'uid';
        var TABINDEX = 'tabindex';
        var COMMAND = 'command';
        var MOVE_UP_OFFSET = -1;
        var MOVE_DOWN_OFFSET = 1;
        var DRAGSTART = 'dragstart';
        var DRAG = 'drag';
        var DROP = 'drop';
        var DRAGEND = 'dragend';
        var DEFAULT_FILTER = 'ul.k-reset.k-list>li.k-item';
        var RIGHT = 'right';
        var BOTTOM = 'bottom';
        var TOOLBAR_POSITION_CLASS_NAMES = [
            TOOLBAR_CLASS + DASH + 'left',
            TOOLBAR_CLASS + DASH + RIGHT,
            TOOLBAR_CLASS + DASH + 'top',
            TOOLBAR_CLASS + DASH + BOTTOM
        ];
        function getSortedDomIndices(items) {
            var indices = $.map(items, function (item) {
                return $(item).index();
            });
            return indices;
        }
        function isUndefined(value) {
            return typeof value === 'undefined';
        }
        function defaultHint(element) {
            return element.clone().removeClass(DRAGGEDCLASS).removeClass(FOCUSED_CLASS).addClass(kendo.format('{0} {1} {2}', SELECTED_STATE_CLASS, RESET, DRAG_CLUE_CLASS)).width(element.width());
        }
        function defaultPlaceholder() {
            return $('<li>').addClass(DROP_HINT_CLASS);
        }
        var ListBox = DataBoundWidget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that._wrapper();
                that._list();
                element = that.element.attr('multiple', 'multiple').hide();
                if (element[0] && !that.options.dataSource) {
                    that.options.dataTextField = that.options.dataTextField || 'text';
                    that.options.dataValueField = that.options.dataValueField || 'value';
                }
                that._templates();
                that._selectable();
                that._dataSource();
                that._createToolbar();
                that._createDraggable();
                that._createNavigatable();
            },
            destroy: function () {
                var that = this;
                DataBoundWidget.fn.destroy.call(that);
                if (!isNaN(that._listTabIndex)) {
                    that._getList().off();
                    that._listTabIndex = null;
                }
                that._unbindDataSource();
                that._destroySelectable();
                that._destroyToolbar();
                that.wrapper.off(NS);
                if (that._target) {
                    that._target = null;
                }
                if (that._draggable) {
                    that._draggable.destroy();
                    that.placeholder = null;
                }
                kendo.destroy(that.element);
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._templates();
                this._dataSource();
            },
            events: [
                CHANGE,
                DATABOUND,
                ADD,
                REMOVE,
                REORDER,
                DRAGSTART,
                DRAG,
                DROP,
                DRAGEND
            ],
            options: {
                name: 'ListBox',
                autoBind: true,
                template: '',
                dataTextField: '',
                dataValueField: '',
                selectable: 'single',
                draggable: null,
                dropSources: [],
                connectWith: '',
                navigatable: true,
                toolbar: {
                    position: RIGHT,
                    tools: []
                },
                messages: {
                    tools: {
                        remove: 'Delete',
                        moveUp: 'Move Up',
                        moveDown: 'Move Down',
                        transferTo: 'Transfer To',
                        transferFrom: 'Transfer From',
                        transferAllTo: 'Transfer All To',
                        transferAllFrom: 'Transfer All From'
                    }
                }
            },
            add: function (dataItems) {
                var that = this;
                var items = dataItems && dataItems.length ? dataItems : [dataItems];
                var itemsLength = items.length;
                var i;
                that._unbindDataSource();
                for (i = 0; i < itemsLength; i++) {
                    that._addItem(items[i]);
                }
                that._bindDataSource();
                that._syncElement();
            },
            _addItem: function (dataItem) {
                var that = this;
                var item = that.templates.itemTemplate({
                    item: dataItem,
                    r: that.templates.itemContent
                });
                $(item).attr(kendoAttr(UNIQUE_ID), dataItem.uid).appendTo(that._getList());
                if (typeof dataItem === typeof '') {
                    that.dataSource._data.push(dataItem);
                } else {
                    that.dataSource.add(dataItem);
                }
            },
            _addItemAt: function (dataItem, index) {
                var that = this;
                var item = that.templates.itemTemplate({
                    item: dataItem,
                    r: that.templates.itemContent
                });
                that._unbindDataSource();
                if (typeof dataItem === typeof '') {
                    that._insertElementAt(item, index);
                    that.dataSource._data.push(dataItem);
                } else {
                    that._insertElementAt($(item).attr(kendoAttr(UNIQUE_ID), dataItem.uid), index);
                    that.dataSource.add(dataItem);
                }
                that._bindDataSource();
                that._syncElement();
            },
            _insertElementAt: function (item, index) {
                var that = this;
                var list = that._getList();
                if (index > 0) {
                    $(item).insertAfter(list.children().eq(index - 1));
                } else {
                    $(list).prepend(item);
                }
            },
            _createNavigatable: function () {
                var that = this;
                var options = that.options;
                if (options.navigatable) {
                    that._getList().on(CLICK, ENABLED_ITEM_SELECTOR, proxy(that._click, that)).on(KEYDOWN, proxy(that._keyDown, that)).on(BLUR, proxy(that._blur, that));
                }
            },
            _getTabIndex: function () {
                var that = this;
                var tabindex;
                if (!isNaN(that._listTabIndex)) {
                    return that._listTabIndex;
                }
                tabindex = that.element.attr(TABINDEX);
                that._listTabIndex = !isNaN(tabindex) ? tabindex : 0;
                that.element.removeAttr(TABINDEX);
                return that._listTabIndex;
            },
            _blur: function () {
                if (this._target) {
                    this._target.removeClass(FOCUSED_CLASS);
                    this._getList().removeAttr('aria-activedescendant');
                }
                this._target = null;
            },
            _click: function (e) {
                var that = this;
                var target = $(e.currentTarget);
                var oldTarget = that._target;
                var isInput = isInputElement(e.target);
                if (oldTarget) {
                    oldTarget.removeClass(FOCUSED_CLASS);
                }
                that._target = target;
                target.addClass(FOCUSED_CLASS);
                that._getList().attr('aria-activedescendant', target.attr('id'));
                if (that._getList()[0] !== kendo._activeElement() && !isInput) {
                    that.focus();
                }
            },
            _getNavigatableItem: function (key) {
                var that = this;
                var current;
                if (!that._target) {
                    current = that.items().filter(ENABLED_ITEM_SELECTOR).first();
                } else {
                    current = that._target;
                }
                if (key === keys.UP && that._target) {
                    current = that._target.prevAll(ENABLED_ITEM_SELECTOR).first();
                }
                if (key === keys.DOWN && that._target) {
                    current = that._target.nextAll(ENABLED_ITEM_SELECTOR).first();
                }
                return current.length ? current : null;
            },
            _scrollIntoView: function (item) {
                if (!item) {
                    return;
                }
                if (item[0]) {
                    item = item[0];
                }
                var list = this._getList().parent()[0];
                var itemOffsetTop = item.offsetTop;
                var contentScrollTop = list.scrollTop;
                var contentOffsetHeight = list.clientHeight;
                var bottomDistance = itemOffsetTop + item.offsetHeight;
                if (contentScrollTop > itemOffsetTop) {
                    contentScrollTop = itemOffsetTop;
                } else if (bottomDistance > contentScrollTop + contentOffsetHeight) {
                    contentScrollTop = bottomDistance - contentOffsetHeight;
                }
                list.scrollTop = contentScrollTop;
            },
            _keyDown: function (e) {
                var that = this;
                var key = e.keyCode;
                var current = that._getNavigatableItem(key);
                var shouldPreventDefault;
                if (that._target) {
                    that._target.removeClass(FOCUSED_CLASS);
                }
                if (!(e.shiftKey && !e.ctrlKey && (key === keys.DOWN || key === keys.UP))) {
                    that._shiftSelecting = false;
                }
                if (key == keys.DELETE) {
                    that._executeCommand(REMOVE);
                    if (that._target) {
                        that._target.removeClass(FOCUSED_CLASS);
                        that._getList().removeAttr('aria-activedescendant');
                        that._target = null;
                    }
                    shouldPreventDefault = true;
                } else if (key === keys.DOWN || key === keys.UP) {
                    if (!current) {
                        e.preventDefault();
                        return;
                    }
                    if (e.shiftKey && !e.ctrlKey) {
                        if (!that._shiftSelecting) {
                            that.clearSelection();
                            that._shiftSelecting = true;
                        }
                        if (that._target && current.hasClass('k-state-selected')) {
                            that._target.removeClass(SELECTED_STATE_CLASS);
                            that.trigger(CHANGE);
                        } else if (that.options.selectable == 'single') {
                            that.select(current);
                        } else {
                            that.select(current.add(that._target));
                        }
                    } else if (e.shiftKey && e.ctrlKey) {
                        that._executeCommand(key === keys.DOWN ? MOVE_DOWN : MOVE_UP);
                        that._scrollIntoView(that._target);
                        e.preventDefault();
                        return;
                    } else if (!e.shiftKey && !e.ctrlKey) {
                        if (that.options.selectable === 'multiple') {
                            that.clearSelection();
                        }
                        that.select(current);
                    }
                    that._target = current;
                    if (that._target) {
                        that._target.addClass(FOCUSED_CLASS);
                        that._scrollIntoView(that._target);
                        that._getList().attr('aria-activedescendant', that._target.attr('id'));
                    } else {
                        that._getList().removeAttr('aria-activedescendant');
                    }
                    shouldPreventDefault = true;
                } else if (key == keys.SPACEBAR) {
                    if (e.ctrlKey && that._target) {
                        if (that._target.hasClass(SELECTED_STATE_CLASS)) {
                            that._target.removeClass(SELECTED_STATE_CLASS);
                            that.trigger(CHANGE);
                        } else {
                            that.select(that._target);
                        }
                    } else {
                        that.clearSelection();
                        that.select(that._target);
                    }
                    shouldPreventDefault = true;
                } else if (e.ctrlKey && key == keys.RIGHT) {
                    if (e.shiftKey) {
                        that._executeCommand(TRANSFER_ALL_TO);
                    } else {
                        that._executeCommand(TRANSFER_TO);
                    }
                    that._target = that.select().length ? that.select() : null;
                    shouldPreventDefault = true;
                } else if (e.ctrlKey && key == keys.LEFT) {
                    if (e.shiftKey) {
                        that._executeCommand(TRANSFER_ALL_FROM);
                    } else {
                        that._executeCommand(TRANSFER_FROM);
                    }
                    shouldPreventDefault = true;
                }
                if (shouldPreventDefault) {
                    e.preventDefault();
                }
            },
            focus: function () {
                kendo.focusElement(this._getList());
            },
            _createDraggable: function () {
                var that = this;
                var draggable = that.options.draggable;
                var hint;
                if (draggable) {
                    hint = draggable.hint;
                    if (!that.options.selectable) {
                        throw new Error('Dragging requires selection to be enabled');
                    }
                    if (!hint) {
                        hint = defaultHint;
                    }
                    that._draggable = new kendo.ui.Draggable(that.wrapper, {
                        filter: draggable.filter ? draggable.filter : DEFAULT_FILTER,
                        hint: kendo.isFunction(hint) ? hint : $(hint),
                        dragstart: proxy(that._dragstart, that),
                        dragcancel: proxy(that._clear, that),
                        drag: proxy(that._drag, that),
                        dragend: proxy(that._dragend, that)
                    });
                }
            },
            _dragstart: function (e) {
                var that = this;
                var draggedElement = that.draggedElement = e.currentTarget;
                var placeholder = that.options.draggable.placeholder;
                var dataItem = that.dataItem(draggedElement);
                var eventData = {
                    dataItems: dataItem,
                    items: $(draggedElement),
                    draggableEvent: e
                };
                if (that.options.draggable.enabled === false) {
                    e.preventDefault();
                    return;
                }
                if (!placeholder) {
                    placeholder = defaultPlaceholder;
                }
                that.placeholder = kendo.isFunction(placeholder) ? $(placeholder.call(that, draggedElement)) : $(placeholder);
                if (draggedElement.is(DOT + DISABLED_STATE_CLASS)) {
                    e.preventDefault();
                } else {
                    if (that.trigger(DRAGSTART, eventData)) {
                        e.preventDefault();
                    } else {
                        that.clearSelection();
                        that.select(draggedElement);
                        draggedElement.addClass(DRAGGEDCLASS);
                    }
                }
            },
            _clear: function () {
                this.draggedElement.removeClass(DRAGGEDCLASS);
                this.placeholder.remove();
            },
            _findElementUnderCursor: function (e) {
                var elementUnderCursor = kendo.elementUnderCursor(e);
                var draggable = e.sender;
                if ($.contains(draggable.hint[0], elementUnderCursor) || draggable.hint[0] === elementUnderCursor) {
                    draggable.hint.hide();
                    elementUnderCursor = kendo.elementUnderCursor(e);
                    draggable.hint.show();
                }
                return elementUnderCursor;
            },
            _findTarget: function (e) {
                var that = this;
                var element = that._findElementUnderCursor(e);
                var elementNode = $(element);
                var list = that._getList();
                var items;
                var node;
                if ($.contains(list[0], element)) {
                    items = that.items();
                    element = elementNode.is('li') ? element : elementNode.closest('li')[0];
                    node = items.filter(element)[0] || items.has(element)[0];
                    if (node) {
                        node = $(node);
                        return !node.hasClass(DISABLED_STATE_CLASS) ? {
                            element: node,
                            listBox: that
                        } : null;
                    } else {
                        return null;
                    }
                } else if (list[0] == element || list.parent()[0] == element) {
                    return {
                        element: $(list),
                        appendToBottom: true,
                        listBox: that
                    };
                } else {
                    return that._searchConnectedListBox(elementNode);
                }
            },
            _getElementCenter: function (element) {
                var center = element.length ? kendo.getOffset(element) : null;
                if (center) {
                    center.top += outerHeight(element) / 2;
                    center.left += outerWidth(element) / 2;
                }
                return center;
            },
            _searchConnectedListBox: function (element) {
                var connectedListBox;
                var items;
                var node;
                var originalElement = element;
                var closestContainer;
                if (element.hasClass('k-list-scroller k-selectable')) {
                    closestContainer = element;
                } else {
                    closestContainer = element.closest('.k-list-scroller.k-selectable');
                }
                if (closestContainer.length) {
                    connectedListBox = closestContainer.parent().find('[data-role=\'listbox\']').getKendoListBox();
                } else {
                    return null;
                }
                if (connectedListBox && $.inArray(this.element[0].id, connectedListBox.options.dropSources) !== -1) {
                    items = connectedListBox.items();
                    element = element.is('li') ? element[0] : element.closest('li')[0];
                    node = items.filter(element)[0] || items.has(element)[0];
                    if (node) {
                        node = $(node);
                        return !node.hasClass(DISABLED_STATE_CLASS) ? {
                            element: node,
                            listBox: connectedListBox
                        } : null;
                    } else if (!items.length || originalElement.hasClass('k-list-scroller k-selectable') || originalElement.hasClass('k-reset k-list')) {
                        return {
                            element: connectedListBox._getList(),
                            listBox: connectedListBox,
                            appendToBottom: true
                        };
                    } else {
                        return null;
                    }
                }
                return null;
            },
            _drag: function (e) {
                var that = this;
                var draggedElement = that.draggedElement;
                var target = that._findTarget(e);
                var cursorOffset = {
                    left: e.x.location,
                    top: e.y.location
                };
                var dataItem = that.dataItem(draggedElement);
                var eventData = {
                    dataItems: [dataItem],
                    items: $(draggedElement),
                    draggableEvent: e
                };
                var targetCenter;
                var offsetDelta;
                var direction;
                if (that.trigger(DRAG, eventData)) {
                    e.preventDefault();
                    return;
                }
                if (target) {
                    targetCenter = this._getElementCenter(target.element);
                    offsetDelta = {
                        left: Math.round(cursorOffset.left - targetCenter.left),
                        top: Math.round(cursorOffset.top - targetCenter.top)
                    };
                    if (target.appendToBottom) {
                        that._movePlaceholder(target, null, draggedElement);
                        return;
                    }
                    if (offsetDelta.top < 0) {
                        direction = 'prev';
                    } else if (offsetDelta.top > 0) {
                        direction = 'next';
                    }
                    if (direction) {
                        if (target.element[0] != that.placeholder[0]) {
                            that._movePlaceholder(target, direction, draggedElement);
                        }
                    }
                } else if (that.placeholder.parent().length) {
                    that.placeholder.remove();
                }
            },
            _movePlaceholder: function (target, direction, draggedElement) {
                var that = this;
                var placeholder = that.placeholder;
                var draggableOptions = target.listBox.options.draggable;
                if (placeholder.parent().length) {
                    that.placeholder.remove();
                    if (draggableOptions && draggableOptions.placeholder) {
                        that.placeholder = kendo.isFunction(draggableOptions.placeholder) ? $(draggableOptions.placeholder.call(that, draggedElement)) : $(draggableOptions.placeholder);
                    } else {
                        that.placeholder = $(defaultPlaceholder.call(that, draggedElement));
                    }
                }
                if (!direction) {
                    target.element.append(that.placeholder);
                } else if (direction === 'prev') {
                    target.element.before(that.placeholder);
                } else if (direction === 'next') {
                    target.element.after(that.placeholder);
                }
            },
            _dragend: function (e) {
                var that = this;
                var draggedItem = that.draggedElement;
                var items = that.items();
                var placeholderIndex = items.not(that.draggedElement).index(that.placeholder);
                var draggedIndex = items.not(that.placeholder).index(that.draggedElement);
                var dataItem = that.dataItem(draggedItem);
                var eventData = {
                    dataItems: [dataItem],
                    items: $(draggedItem)
                };
                var connectedListBox = that.placeholder.closest('.k-widget.k-listbox').find('[data-role=\'listbox\']').getKendoListBox();
                if (that.trigger(DROP, extend({}, eventData, { draggableEvent: e }))) {
                    e.preventDefault();
                    this._clear();
                    return;
                }
                if (placeholderIndex >= 0) {
                    if (placeholderIndex !== draggedIndex && !that.trigger(REORDER, extend({}, eventData, { offset: placeholderIndex - draggedIndex }))) {
                        draggedItem.removeClass(DRAGGEDCLASS);
                        that.reorder(draggedItem, placeholderIndex);
                    }
                } else if (connectedListBox) {
                    if (!that.trigger(REMOVE, eventData)) {
                        that.remove($(draggedItem));
                    }
                    if (!connectedListBox.trigger(ADD, eventData)) {
                        connectedListBox._addItemAt(dataItem, connectedListBox.items().index(that.placeholder));
                    }
                }
                that._clear();
                that._draggable.dropped = true;
                that.trigger(DRAGEND, extend({}, eventData, { draggableEvent: e }));
                that._updateToolbar();
                that._updateAllToolbars();
            },
            reorder: function (item, index) {
                var that = this;
                var dataSource = that.dataSource;
                var dataItem = that.dataItem(item);
                var dataItemAtIndex = dataSource.at(index);
                var itemAtIndex = that.items()[index];
                var listItem = $(item);
                if (dataItem && itemAtIndex && dataItemAtIndex) {
                    that._removeElement(listItem);
                    that._insertElementAt(listItem, index);
                    that._updateToolbar();
                }
            },
            remove: function (items) {
                var that = this;
                var listItems = that._getItems(items);
                var itemsLength = listItems.length;
                var i;
                that._unbindDataSource();
                for (i = 0; i < itemsLength; i++) {
                    that._removeItem($(listItems[i]));
                }
                that._bindDataSource();
                that._syncElement();
                that._updateToolbar();
                that._updateAllToolbars();
            },
            _removeItem: function (item) {
                var that = this;
                var dataSource = that.dataSource;
                var dataItem = that.dataItem(item);
                if (!dataItem || !dataSource) {
                    return;
                }
                if (typeof dataItem === typeof '') {
                    var data = dataSource._data;
                    for (var i = 0; i < data.length; i++) {
                        if (dataItem === data[i]) {
                            data[i] = data[data.length - 1];
                            data.pop();
                            break;
                        }
                    }
                } else {
                    dataSource.remove(dataItem);
                }
                that._removeElement(item);
            },
            _removeElement: function (item) {
                kendo.destroy(item);
                $(item).off().remove();
            },
            dataItem: function (element) {
                var uniqueIdAttr = kendoAttr(UNIQUE_ID);
                var uid = $(element).attr(uniqueIdAttr) || $(element).closest('[' + uniqueIdAttr + ']').attr(uniqueIdAttr);
                if (uid) {
                    return this.dataSource.getByUid(uid);
                } else {
                    return $(element).html();
                }
            },
            _dataItems: function (items) {
                var dataItems = [];
                var listItems = $(items);
                var itemsLength = listItems.length;
                var i;
                for (i = 0; i < itemsLength; i++) {
                    dataItems.push(this.dataItem(listItems.eq(i)));
                }
                return dataItems;
            },
            items: function () {
                var list = this._getList();
                return list.children();
            },
            select: function (items) {
                var that = this;
                var selectable = that.selectable;
                var enabledItems;
                if (isUndefined(items)) {
                    return selectable.value();
                }
                enabledItems = that.items().filter(items).filter(ENABLED_ITEMS_SELECTOR);
                if (!selectable.options.multiple) {
                    selectable.clear();
                    enabledItems = enabledItems.first();
                }
                return selectable.value(enabledItems);
            },
            clearSelection: function () {
                var that = this;
                var selectable = that.selectable;
                if (selectable) {
                    selectable.clear();
                }
            },
            enable: function (items, enable) {
                var that = this;
                var enabled = isUndefined(enable) ? true : !!enable;
                var listItems = that._getItems(items);
                var itemsLength = listItems.length;
                var i;
                for (i = 0; i < itemsLength; i++) {
                    that._enableItem($(listItems[i]), enabled);
                }
                that._updateAllToolbars();
            },
            _enableItem: function (item, enable) {
                var that = this;
                var dataItem = that.dataItem(item);
                if (dataItem) {
                    if (enable) {
                        $(item).removeClass(DISABLED_STATE_CLASS);
                    } else {
                        $(item).addClass(DISABLED_STATE_CLASS).removeClass(SELECTED_STATE_CLASS);
                    }
                }
            },
            setDataSource: function (dataSource) {
                var that = this;
                that.options.dataSource = dataSource;
                that._dataSource();
            },
            _dataSource: function () {
                var that = this;
                var options = that.options;
                var dataSource = options.dataSource || {};
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                dataSource.select = that.element;
                dataSource.fields = [
                    { field: options.dataTextField },
                    { field: options.dataValueField }
                ];
                that._unbindDataSource();
                that.dataSource = DataSource.create(dataSource);
                that._bindDataSource();
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                }
            },
            _bindDataSource: function () {
                var that = this;
                var dataSource = that.dataSource;
                that._dataChangeHandler = proxy(that.refresh, that);
                if (dataSource) {
                    dataSource.bind(CHANGE, that._dataChangeHandler);
                }
            },
            _unbindDataSource: function () {
                var that = this;
                var dataSource = that.dataSource;
                if (dataSource) {
                    dataSource.unbind(CHANGE, that._dataChangeHandler);
                }
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper = element.parent('div.k-listbox');
                if (!wrapper[0]) {
                    wrapper = element.wrap('<div class="k-widget k-listbox" unselectable="on" />').parent();
                    wrapper[0].style.cssText = element[0].style.cssText;
                    wrapper[0].title = element[0].title;
                    $('<div class="k-list-scroller" />').insertBefore(element);
                }
                that.wrapper = wrapper.addClass(element[0].className).css('display', '');
                that._innerWrapper = $(wrapper[0].firstChild);
            },
            _list: function () {
                var that = this;
                $('<ul class=\'' + LIST_CLASS + '\' role=\'listbox\'></ul>').appendTo(that._innerWrapper);
                if (that.options.navigatable) {
                    that._getList().attr(TABINDEX, that._getTabIndex());
                }
            },
            _templates: function () {
                var that = this;
                var options = this.options;
                var template;
                if (options.template && typeof options.template == 'string') {
                    template = kendo.template(options.template);
                } else if (!options.template) {
                    template = kendo.template('${' + kendo.expr(options.dataTextField, 'data') + '}', { useWithBlock: false });
                } else {
                    template = options.template;
                }
                that.templates = {
                    itemTemplate: kendo.template('# var item = data.item, r = data.r; # <li class=\'k-item\' role=\'option\' aria-selected=\'false\'>#=r(item)#</li>', { useWithBlock: false }),
                    itemContent: template,
                    toolbar: '<div class=\'' + TOOLBAR_CLASS + '\'></div>'
                };
            },
            refresh: function () {
                var that = this;
                var view = that.dataSource.view();
                var template = that.templates.itemTemplate;
                var html = '';
                for (var idx = 0; idx < view.length; idx++) {
                    html += template({
                        item: view[idx],
                        r: that.templates.itemContent
                    });
                }
                that._getList().html(html);
                that._setItemIds();
                that._createToolbar();
                that._syncElement();
                that._updateToolbar();
                that._updateAllToolbars();
                that.trigger(DATABOUND);
            },
            _syncElement: function () {
                var options = '';
                var view = this.dataSource.view();
                for (var idx = 0; idx < view.length; idx++) {
                    options += this._option(view[idx][this.options.dataValueField] || view[idx], view[idx][this.options.dataTextField] || view[idx], true);
                }
                this.element.html(options);
            },
            _option: function (dataValue, dataText) {
                var option = '<option';
                if (dataValue !== undefined) {
                    dataValue += '';
                    if (dataValue.indexOf('"') !== -1) {
                        dataValue = dataValue.replace(/"/g, '&quot;');
                    }
                    option += ' value="' + dataValue + '"';
                }
                option += ' selected>';
                if (dataText !== undefined) {
                    option += kendo.htmlEncode(dataText);
                }
                return option += '</option>';
            },
            _setItemIds: function () {
                var that = this;
                var items = that.items();
                var view = that.dataSource.view();
                var viewLength = view.length;
                var i;
                for (i = 0; i < viewLength; i++) {
                    items.eq(i).attr(kendoAttr(UNIQUE_ID), view[i].uid).attr('id', view[i].uid);
                }
            },
            _selectable: function () {
                var that = this;
                var selectable = that.options.selectable;
                var selectableOptions = Selectable.parseOptions(selectable);
                if (selectableOptions.multiple) {
                    that.element.attr('aria-multiselectable', 'true');
                }
                that.selectable = new Selectable(that._innerWrapper, {
                    aria: true,
                    multiple: selectableOptions.multiple,
                    filter: ENABLED_ITEM_SELECTOR,
                    change: proxy(that._onSelect, that)
                });
            },
            _onSelect: function () {
                var that = this;
                that._updateToolbar();
                that._updateAllToolbars();
                that.trigger(CHANGE);
            },
            _destroySelectable: function () {
                var that = this;
                if (that.selectable && that.selectable.element) {
                    that.selectable.destroy();
                    that.selectable = null;
                }
            },
            _getList: function () {
                return this.wrapper.find(LIST_SELECTOR);
            },
            _getItems: function (items) {
                return this.items().filter(items);
            },
            _createToolbar: function () {
                var that = this;
                var toolbarOptions = that.options.toolbar;
                var position = toolbarOptions.position || RIGHT;
                var toolbarInsertion = position === BOTTOM ? 'insertAfter' : 'insertBefore';
                var tools = toolbarOptions.tools || [];
                var messages = that.options.messages;
                that._destroyToolbar();
                that.wrapper.removeClass(TOOLBAR_POSITION_CLASS_NAMES.join(SPACE));
                if (tools.length && tools.length > 0) {
                    var toolbarElement = $(that.templates.toolbar)[toolbarInsertion](that._innerWrapper);
                    that.toolbar = new ToolBar(toolbarElement, extend({}, toolbarOptions, {
                        listBox: that,
                        messages: messages
                    }));
                    that.wrapper.addClass(TOOLBAR_CLASS + DASH + position);
                }
            },
            _destroyToolbar: function () {
                var that = this;
                if (that.toolbar) {
                    that.toolbar.destroy();
                    that.toolbar = null;
                }
            },
            _executeCommand: function (commandName) {
                var that = this;
                var command = CommandFactory.current.create(commandName, { listBox: that });
                if (command) {
                    command.execute();
                    that._updateToolbar();
                    that._updateAllToolbars();
                }
            },
            _updateToolbar: function () {
                var toolbar = this.toolbar;
                if (toolbar) {
                    toolbar._updateToolStates();
                }
            },
            _updateAllToolbars: function () {
                var listBoxElements = $('select[data-role=\'listbox\']');
                var elementsLength = listBoxElements.length;
                var listBox;
                var i;
                for (i = 0; i < elementsLength; i++) {
                    listBox = $(listBoxElements[i]).data(KENDO_LISTBOX);
                    if (listBox) {
                        listBox._updateToolbar();
                    }
                }
            }
        });
        kendo.ui.plugin(ListBox);
        var CommandFactory = Class.extend({
            init: function () {
                this._commands = [];
            },
            register: function (commandName, commandType) {
                this._commands.push({
                    commandName: commandName,
                    commandType: commandType
                });
            },
            create: function (commandName, options) {
                var commands = this._commands;
                var itemsLength = commands.length;
                var name = commandName ? commandName.toLowerCase() : '';
                var match;
                var command;
                var i;
                for (i = 0; i < itemsLength; i++) {
                    command = commands[i];
                    if (command.commandName.toLowerCase() === name) {
                        match = command;
                        break;
                    }
                }
                if (match) {
                    return new match.commandType(options);
                }
            }
        });
        CommandFactory.current = new CommandFactory();
        var ListBoxCommand = Class.extend({
            init: function (options) {
                var that = this;
                that.options = extend({}, that.options, options);
                that.listBox = that.options.listBox;
            },
            options: { listBox: null },
            getItems: function () {
                return $(this.listBox.select());
            },
            execute: noop,
            canExecute: noop
        });
        var RemoveItemsCommand = ListBoxCommand.extend({
            execute: function () {
                var that = this;
                var listBox = that.listBox;
                var items = that.getItems();
                if (!listBox.trigger(REMOVE, {
                        dataItems: listBox._dataItems(items),
                        items: items
                    })) {
                    listBox.remove(items);
                }
            },
            canExecute: function () {
                return this.listBox.select().length > 0;
            }
        });
        CommandFactory.current.register(REMOVE, RemoveItemsCommand);
        var MoveItemsCommand = ListBoxCommand.extend({
            execute: function () {
                var that = this;
                if (that.canExecute()) {
                    that.moveItems();
                }
            },
            canExecute: noop,
            moveItems: function () {
                var that = this;
                var listBox = that.listBox;
                var options = that.options;
                var items = that.getItems();
                var offset = options.offset;
                var indecesInDom = getSortedDomIndices(items);
                var movedItems = $.makeArray(items.sort(that.itemComparer));
                var moveAction = options.moveAction;
                var movedItem;
                if (!listBox.trigger(REORDER, {
                        dataItems: listBox._dataItems(movedItems),
                        items: $(movedItems),
                        offset: offset
                    })) {
                    while (movedItems.length > 0 && indecesInDom.length > 0) {
                        movedItem = movedItems[moveAction]();
                        listBox.reorder(movedItem, indecesInDom[moveAction]() + offset);
                    }
                }
            },
            options: {
                offset: 0,
                moveAction: 'pop'
            },
            itemComparer: function (item1, item2) {
                var indexItem1 = $(item1).index();
                var indexItem2 = $(item2).index();
                if (indexItem1 === indexItem2) {
                    return 0;
                } else {
                    return indexItem1 > indexItem2 ? 1 : -1;
                }
            }
        });
        var MoveUpItemsCommand = MoveItemsCommand.extend({
            options: {
                offset: MOVE_UP_OFFSET,
                moveAction: 'shift'
            },
            canExecute: function () {
                var items = this.getItems();
                var domIndices = getSortedDomIndices(items);
                return domIndices.length > 0 && domIndices[0] > 0;
            }
        });
        CommandFactory.current.register(MOVE_UP, MoveUpItemsCommand);
        var MoveDownItemsCommand = MoveItemsCommand.extend({
            options: {
                offset: MOVE_DOWN_OFFSET,
                moveAction: 'pop'
            },
            canExecute: function () {
                var that = this;
                var items = that.getItems();
                var domIndices = getSortedDomIndices(items);
                return domIndices.length > 0 && $(domIndices).last()[0] < that.listBox.items().length - 1;
            }
        });
        CommandFactory.current.register(MOVE_DOWN, MoveDownItemsCommand);
        var TransferItemsCommand = ListBoxCommand.extend({
            options: { filter: ENABLED_ITEM_SELECTOR },
            execute: function () {
                var that = this;
                var sourceListBox = that.getSourceListBox();
                var items = that.getItems().filter(that.options.filter);
                var dataItems = sourceListBox ? sourceListBox._dataItems(items) : [];
                var destinationListBox = that.getDestinationListBox();
                var updatedSelection = that.getUpdatedSelection(items);
                if (destinationListBox && items.length > 0) {
                    if (!destinationListBox.trigger(ADD, {
                            dataItems: dataItems,
                            items: items
                        })) {
                        destinationListBox.add(dataItems);
                    }
                    if (!sourceListBox.trigger(REMOVE, {
                            dataItems: dataItems,
                            items: items
                        })) {
                        sourceListBox.remove(items);
                        that.updateSelection(updatedSelection);
                    }
                }
            },
            getUpdatedSelection: function (items) {
                var that = this;
                var itemFilter = that.options.filter;
                var sourceListBox = that.getSourceListBox();
                var lastEnabledItem = sourceListBox ? sourceListBox.items().filter(itemFilter).last() : null;
                var containsLastItem = $(items).filter(lastEnabledItem).length > 0;
                var itemToSelect = containsLastItem ? $(items).prevAll(itemFilter)[0] : $(items).nextAll(itemFilter)[0];
                if ($(items).length === 1 && itemToSelect) {
                    return itemToSelect;
                } else {
                    return null;
                }
            },
            updateSelection: function (item) {
                var sourceListBox = this.getSourceListBox();
                if (sourceListBox && item) {
                    $(sourceListBox.select($(item)));
                    sourceListBox._scrollIntoView(item);
                }
            },
            getSourceListBox: noop,
            getDestinationListBox: noop
        });
        var TransferItemsToCommand = TransferItemsCommand.extend({
            canExecute: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.select().length > 0 : false;
            },
            getSourceListBox: function () {
                return this.listBox;
            },
            getDestinationListBox: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox && sourceListBox.options.connectWith ? $(HASH + sourceListBox.options.connectWith).data(KENDO_LISTBOX) : null;
            },
            getItems: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? $(sourceListBox.select()) : $();
            }
        });
        CommandFactory.current.register(TRANSFER_TO, TransferItemsToCommand);
        var TransferItemsFromCommand = TransferItemsCommand.extend({
            canExecute: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.select().length > 0 : false;
            },
            getSourceListBox: function () {
                var destinationListBox = this.getDestinationListBox();
                return destinationListBox && destinationListBox.options.connectWith ? $(HASH + destinationListBox.options.connectWith).data(KENDO_LISTBOX) : null;
            },
            getDestinationListBox: function () {
                return this.listBox;
            },
            getItems: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? $(sourceListBox.select()) : $();
            }
        });
        CommandFactory.current.register(TRANSFER_FROM, TransferItemsFromCommand);
        var TransferAllItemsToCommand = TransferItemsToCommand.extend({
            canExecute: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.items().filter(ENABLED_ITEM_SELECTOR).length > 0 : false;
            },
            getItems: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.items() : $();
            },
            getUpdatedSelection: noop,
            updateSelection: noop
        });
        CommandFactory.current.register(TRANSFER_ALL_TO, TransferAllItemsToCommand);
        var TransferAllItemsFromCommand = TransferItemsFromCommand.extend({
            canExecute: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.items().filter(ENABLED_ITEM_SELECTOR).length > 0 : false;
            },
            getItems: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.items() : $();
            },
            getUpdatedSelection: noop,
            updateSelection: noop
        });
        CommandFactory.current.register(TRANSFER_ALL_FROM, TransferAllItemsFromCommand);
        var ToolBar = Class.extend({
            init: function (element, options) {
                var that = this;
                that.element = $(element).addClass(TOOLBAR_CLASS);
                that.options = extend({}, that.options, options);
                that.listBox = that.options.listBox;
                that._initTemplates();
                that._createTools();
                that._updateToolStates();
                that._attachEventHandlers();
            },
            destroy: function () {
                var that = this;
                that._detachEventHandlers();
                kendo.destroy(that.element);
                that.element.remove();
                that.element = null;
            },
            options: {
                position: RIGHT,
                tools: []
            },
            _initTemplates: function () {
                this.templates = { tool: kendoTemplate('<li>' + '<a href=\'\\\\#\' class=\'k-button k-button-icon\' data-command=\'#= command #\' title=\'#= text #\' aria-label=\'#= text #\' role=\'button\'>' + '<span class=\'k-icon #= iconClass #\'></span>' + '</a>' + '</li>') };
            },
            _createTools: function () {
                var that = this;
                var tools = that.options.tools;
                var toolsLength = tools.length;
                var toolsMessages = that.options.messages.tools;
                var toolList = that._createToolList();
                var tool;
                var i;
                for (i = 0; i < toolsLength; i++) {
                    tool = extend({}, ToolBar.defaultTools[tools[i]], { text: toolsMessages[tools[i]] });
                    if (tool) {
                        toolList.append($(that.templates.tool(tool)));
                    }
                }
                that.element.append(toolList);
            },
            _createToolList: function () {
                return $('<ul class=\'k-reset\' />');
            },
            _attachEventHandlers: function () {
                var that = this;
                that.element.on(CLICK, TOOL_SELECTOR, proxy(that._onToolClick, that));
            },
            _detachEventHandlers: function () {
                this.element.off(NS).find('*').off(NS);
            },
            _onToolClick: function (e) {
                e.preventDefault();
                this._executeToolCommand($(e.currentTarget).data(COMMAND));
            },
            _executeToolCommand: function (command) {
                var that = this;
                var listBox = that.listBox;
                if (listBox) {
                    listBox._executeCommand(command);
                }
            },
            _updateToolStates: function () {
                var that = this;
                var tools = that.options.tools;
                var toolsLength = tools.length;
                var i;
                for (i = 0; i < toolsLength; i++) {
                    that._updateToolState(tools[i]);
                }
            },
            _updateToolState: function (toolName) {
                var that = this;
                var command = CommandFactory.current.create(toolName, { listBox: that.listBox });
                var toolElement = that.element.find('[data-command=\'' + toolName + '\']')[0];
                if (toolElement && command && command.canExecute) {
                    if (command.canExecute()) {
                        $(toolElement).removeClass(DISABLED_STATE_CLASS).removeAttr(TABINDEX);
                    } else {
                        $(toolElement).addClass(DISABLED_STATE_CLASS).attr(TABINDEX, '-1');
                    }
                }
            }
        });
        ToolBar.defaultTools = {
            remove: {
                command: REMOVE,
                iconClass: 'k-i-x'
            },
            moveUp: {
                command: MOVE_UP,
                iconClass: 'k-i-arrow-60-up'
            },
            moveDown: {
                command: MOVE_DOWN,
                iconClass: 'k-i-arrow-60-down'
            },
            transferTo: {
                command: TRANSFER_TO,
                iconClass: 'k-i-arrow-60-right'
            },
            transferFrom: {
                command: TRANSFER_FROM,
                iconClass: 'k-i-arrow-60-left'
            },
            transferAllTo: {
                command: TRANSFER_ALL_TO,
                iconClass: 'k-i-arrow-double-60-right'
            },
            transferAllFrom: {
                command: TRANSFER_ALL_FROM,
                iconClass: 'k-i-arrow-double-60-left'
            }
        };
        extend(ListBox, { ToolBar: ToolBar });
        function isInputElement(element) {
            return $(element).is(':button,a,:input,a>.k-icon,textarea,span.k-select,span.k-icon,span.k-link,label.k-checkbox-label,.k-input,.k-multiselect-wrap,.k-picker-wrap,.k-picker-wrap>.k-selected-color,.k-tool-icon,.k-dropdown');
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.upload', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'upload',
        name: 'Upload',
        category: 'web',
        description: 'The Upload widget uses progressive enhancement to deliver the best possible uploading experience to users.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, antiForgeryTokens = kendo.antiForgeryTokens, logToConsole = kendo.logToConsole, rFileExtension = /\.([^\.]+)$/, NS = '.kendoUpload', SELECT = 'select', UPLOAD = 'upload', SUCCESS = 'success', ERROR = 'error', COMPLETE = 'complete', CANCEL = 'cancel', CLEAR = 'clear', PAUSE = 'pause', RESUME = 'resume', PROGRESS = 'progress', REMOVE = 'remove', VALIDATIONERRORS = 'validationErrors', INVALIDMAXFILESIZE = 'invalidMaxFileSize', INVALIDMINFILESIZE = 'invalidMinFileSize', INVALIDFILEEXTENSION = 'invalidFileExtension', PROGRESSHIDEDELAY = 1000, PROGRESSHIDEDURATION = 2000;
        var headerStatusIcon = {
            loading: 'k-i-loading',
            warning: 'k-i-warning',
            success: 'k-i-check'
        };
        var Upload = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.name = element.name;
                that.multiple = that.options.multiple;
                that.directory = that.options.directory;
                that.localization = that.options.localization;
                var activeInput = that.element;
                that.wrapper = activeInput.closest('.k-upload');
                if (that.wrapper.length === 0) {
                    that.wrapper = that._wrapInput(activeInput);
                }
                that._activeInput(activeInput);
                that.toggle(that.options.enabled);
                var ns = that._ns = NS + '-' + kendo.guid();
                activeInput.closest('form').on('submit' + ns, $.proxy(that._onParentFormSubmit, that)).on('reset' + ns, $.proxy(that._onParentFormReset, that));
                if (that.options.async.saveUrl) {
                    that._module = that._supportsFormData() ? new formDataUploadModule(that) : new iframeUploadModule(that);
                    that._async = true;
                    var initialFiles = that.options.files;
                    if (initialFiles.length > 0) {
                        that._renderInitialFiles(initialFiles);
                    }
                } else {
                    that._module = new syncUploadModule(that);
                }
                if (that._supportsDrop()) {
                    if (that.options.dropZone !== '') {
                        that._setupCustomDropZone();
                    } else {
                        that._setupDropZone();
                    }
                }
                that.wrapper.on('click', '.k-upload-action', $.proxy(that._onFileAction, that)).on('click', '.k-clear-selected', $.proxy(that._onClearSelected, that)).on('click', '.k-upload-selected', $.proxy(that._onUploadSelected, that));
                if (that.element.val()) {
                    that._onInputChange({ target: that.element });
                }
            },
            events: [
                SELECT,
                UPLOAD,
                SUCCESS,
                ERROR,
                COMPLETE,
                CANCEL,
                CLEAR,
                PROGRESS,
                REMOVE,
                PAUSE,
                RESUME
            ],
            options: {
                name: 'Upload',
                enabled: true,
                multiple: true,
                directory: false,
                showFileList: true,
                template: '',
                files: [],
                async: {
                    autoRetryAfter: 0,
                    bufferChunkSize: 10000000,
                    maxAutoRetries: 1,
                    removeVerb: 'POST',
                    autoUpload: true,
                    withCredentials: true,
                    accept: '*/*; q=0.5, application/json',
                    useArrayBuffer: false
                },
                localization: {
                    'select': 'Select files...',
                    'cancel': 'Cancel',
                    'retry': 'Retry',
                    'remove': 'Remove',
                    'pause': 'Pause',
                    'resume': 'Resume',
                    'clearSelectedFiles': 'Clear',
                    'uploadSelectedFiles': 'Upload',
                    'dropFilesHere': 'Drop files here to upload',
                    'invalidFiles': 'Invalid file(s). Please check file upload requirements.',
                    'statusUploading': 'uploading',
                    'statusUploaded': 'uploaded',
                    'statusWarning': 'warning',
                    'statusFailed': 'failed',
                    'headerStatusUploading': 'Uploading...',
                    'headerStatusPaused': 'Paused',
                    'headerStatusUploaded': 'Done',
                    'invalidMaxFileSize': 'File size too large.',
                    'invalidMinFileSize': 'File size too small.',
                    'invalidFileExtension': 'File type not allowed.'
                },
                validation: {
                    allowedExtensions: [],
                    maxFileSize: 0,
                    minFileSize: 0
                },
                dropZone: ''
            },
            setOptions: function (options) {
                var that = this, activeInput = that.element;
                Widget.fn.setOptions.call(that, options);
                that.multiple = that.options.multiple;
                that.directory = that.options.directory;
                activeInput.attr('multiple', that._supportsMultiple() ? that.multiple : false);
                if (that.directory) {
                    activeInput.attr('webkitdirectory', that.directory);
                    activeInput.attr('directory', that.directory);
                }
                that.toggle(that.options.enabled);
            },
            enable: function (enable) {
                enable = typeof enable === 'undefined' ? true : enable;
                this.toggle(enable);
            },
            disable: function () {
                this.toggle(false);
            },
            toggle: function (enable) {
                enable = typeof enable === 'undefined' ? enable : !enable;
                this.wrapper.toggleClass('k-state-disabled', enable);
                this.element.prop('disabled', enable);
            },
            focus: function () {
                this.element.focus();
            },
            destroy: function () {
                var that = this;
                var customDropZone = $(that.options.dropZone);
                $(document).add($('.k-dropzone', that.wrapper)).add(that.wrapper.closest('form')).off(that._ns);
                if (customDropZone.length > 0) {
                    customDropZone.off(that._ns);
                }
                $(that.element).off(NS);
                Widget.fn.destroy.call(that);
            },
            pause: function (fileEntry) {
                this._module.onPause({ target: $(fileEntry, this.wrapper) });
                var pauseIcon = fileEntry.find('.k-i-pause-sm');
                pauseIcon.removeClass('k-i-pause-sm').addClass('k-i-play-sm').attr('title', this.localization.resume);
                $(pauseIcon).parent().attr('aria-label', this.localization.resume);
            },
            resume: function (fileEntry) {
                this._module.onResume({ target: $(fileEntry, this.wrapper) });
                var playIcon = fileEntry.find('.k-i-play-sm');
                playIcon.removeClass('k-i-play-sm').addClass('k-i-pause-sm').attr('title', this.localization.pause);
                $(playIcon).parent().attr('aria-label', this.localization.pause);
            },
            upload: function () {
                var that = this;
                that._module.onSaveSelected();
            },
            getFiles: function () {
                var that = this;
                var filesData;
                var allFiles = [];
                var listItems = that.wrapper.find('.k-file');
                for (var i = 0; i < listItems.length; i++) {
                    filesData = $(listItems[i]).data('fileNames');
                    if (filesData) {
                        for (var j = 0; j < filesData.length; j++) {
                            allFiles.push(filesData[j]);
                        }
                    }
                }
                return allFiles;
            },
            clearAllFiles: function () {
                var that = this;
                var files = that.wrapper.find('.k-file');
                files.each(function (index, file) {
                    that._removeFileByDomElement(file, false);
                });
            },
            removeAllFiles: function () {
                var that = this;
                var files = that.wrapper.find('.k-file');
                files.each(function (index, file) {
                    that._removeFileByDomElement(file, true);
                });
            },
            removeFileByUid: function (uid) {
                this._removeFileByUid(uid, true);
            },
            clearFileByUid: function (uid) {
                this._removeFileByUid(uid, false);
            },
            _removeFileByUid: function (uid, shouldSendRemoveRequest) {
                var that = this;
                var fileEntry;
                if (typeof uid !== 'string') {
                    return;
                }
                fileEntry = $('.k-file[' + kendo.attr('uid') + '="' + uid + '"]', that.wrapper);
                if (fileEntry.length > 0) {
                    that._removeFileByDomElement(fileEntry, shouldSendRemoveRequest);
                }
            },
            clearFile: function (callback) {
                this._removeFile(callback, false);
            },
            removeFile: function (callback) {
                this._removeFile(callback, true);
            },
            _removeFile: function (callback, shouldSendRemoveRequest) {
                var that = this;
                var files = that.wrapper.find('.k-file');
                var fileData;
                if (typeof callback === 'function') {
                    files.each(function (index, file) {
                        fileData = $(file).data('fileNames');
                        if (callback(fileData)) {
                            that._removeFileByDomElement(file, shouldSendRemoveRequest);
                        }
                    });
                }
            },
            _removeFileByDomElement: function (fileEntry, shouldSendRemoveRequest) {
                var that = this;
                var fileData = { target: $(fileEntry, that.wrapper) };
                var allFiles;
                if (that.options.async.saveUrl) {
                    if ($(fileEntry).hasClass('k-file-progress')) {
                        that._module.onCancel(fileData);
                    } else {
                        that._module.onRemove(fileData, {}, shouldSendRemoveRequest);
                    }
                    allFiles = $('.k-file', that.wrapper);
                    if (allFiles.length === 0) {
                        that._hideHeaderUploadstatus();
                    } else {
                        that._updateHeaderUploadStatus();
                    }
                } else {
                    that._module.onRemove(fileData, {}, shouldSendRemoveRequest);
                }
            },
            _addInput: function (sourceInput) {
                if (!sourceInput[0].nodeType) {
                    return;
                }
                var that = this, input = sourceInput.clone().val('');
                input.insertAfter(that.element).data('kendo' + that.options.prefix + that.options.name, that);
                $(that.element).hide().attr('tabindex', '-1').removeAttr('id').off(NS);
                that._activeInput(input);
                that.element.focus();
            },
            _activeInput: function (input) {
                var that = this, wrapper = that.wrapper;
                that.element = input;
                if (that.directory) {
                    input.attr('webkitdirectory', that.directory);
                    input.attr('directory', that.directory);
                }
                input.attr('multiple', that._supportsMultiple() ? that.multiple : false).attr('autocomplete', 'off').on('click' + NS, function (e) {
                    if (wrapper.hasClass('k-state-disabled')) {
                        e.preventDefault();
                    }
                }).on('focus' + NS, function () {
                    $(this).parent().addClass('k-state-focused');
                }).on('blur' + NS, function () {
                    $(this).parent().removeClass('k-state-focused');
                }).on('change' + NS, $.proxy(that._onInputChange, that)).on('keydown' + NS, $.proxy(that._onInputKeyDown, that));
            },
            _onInputKeyDown: function (e) {
                var that = this;
                var firstButton = that.wrapper.find('.k-upload-action:visible:first');
                if (e.keyCode === kendo.keys.TAB && firstButton.length > 0 && !e.shiftKey) {
                    e.preventDefault();
                    firstButton.focus();
                }
            },
            _onInputChange: function (e) {
                var that = this;
                var input = $(e.target);
                var files = assignGuidToFiles(that._inputFiles(input), that._isAsyncNonBatch());
                validateFiles(files, that.options.validation);
                var prevented = that.trigger(SELECT, { files: files });
                if (prevented) {
                    that._addInput(input);
                    input.remove();
                } else {
                    that._module.onSelect({ target: input }, files);
                }
            },
            _readDirectory: function (item) {
                var deferred = new $.Deferred();
                var dirReader = item.createReader();
                var allFolderFiles = [];
                var readEntries = function () {
                    dirReader.readEntries(function (entries) {
                        if (!entries.length) {
                            deferred.resolve(allFolderFiles);
                        } else {
                            allFolderFiles = allFolderFiles.concat(entries);
                            readEntries();
                        }
                    }, deferred.reject);
                };
                readEntries();
                return deferred.promise();
            },
            _readFile: function (item) {
                var that = this;
                var fullpath = item.fullPath;
                item.file(function (file) {
                    file.relativePath = fullpath.slice(1);
                    that.droppedFolderFiles.push(file);
                    that.droppedFolderCounter--;
                    if (that.droppedFolderCounter === 0) {
                        setTimeout(function () {
                            if (that.droppedFolderCounter === 0) {
                                if (that.droppedFolderFiles.length) {
                                    that._proceedDroppedItems(that.droppedFolderFiles);
                                    that.droppedFolderFiles = [];
                                }
                            }
                        }, 0);
                    }
                }, function () {
                    logToConsole('File error.');
                });
            },
            _traverseFileTree: function (item, skipCounter) {
                var that = this;
                if (!skipCounter) {
                    that.droppedFolderCounter--;
                }
                this._readDirectory(item).then(function (items) {
                    that.droppedFolderCounter += items.length;
                    for (var i = 0; i < items.length; i++) {
                        if (items[i].isFile) {
                            that._readFile(items[i]);
                        } else if (items[i].isDirectory) {
                            that._traverseFileTree(items[i]);
                        }
                    }
                });
            },
            _onDrop: function (e) {
                var dt = e.originalEvent.dataTransfer;
                var that = this;
                var droppedFiles = dt.files;
                var length;
                stopEvent(e);
                if (that.options.directoryDrop && dt.items) {
                    length = dt.items.length;
                    that.droppedFolderCounter = 0;
                    that.droppedFolderFiles = [];
                    for (var i = 0; i < length; i++) {
                        if (dt.items[i].webkitGetAsEntry) {
                            var entry = dt.items[i].webkitGetAsEntry();
                            if (entry.isDirectory) {
                                that._traverseFileTree(entry, true);
                            } else if (entry.isFile) {
                                that.droppedFolderFiles.push(dt.files[i]);
                            }
                        } else {
                            that._proceedDroppedItems(droppedFiles);
                        }
                    }
                } else {
                    that._proceedDroppedItems(droppedFiles);
                }
            },
            _proceedDroppedItems: function (droppedFiles) {
                var that = this;
                var files = assignGuidToFiles(getAllFileInfo(droppedFiles), that._isAsyncNonBatch());
                if (droppedFiles.length > 0 && !that.wrapper.hasClass('k-state-disabled')) {
                    if (!that.multiple && files.length > 1) {
                        files.splice(1, files.length - 1);
                    }
                    validateFiles(files, that.options.validation);
                    var prevented = that.trigger(SELECT, { files: files });
                    if (!prevented) {
                        that._module.onSelect({ target: $('.k-dropzone', that.wrapper) }, files);
                    }
                }
            },
            _filesContainValidationErrors: function (files) {
                var hasErrors = false;
                $(files).each(function (index, file) {
                    if (file[VALIDATIONERRORS] && file[VALIDATIONERRORS].length > 0) {
                        hasErrors = true;
                        return false;
                    }
                });
                return hasErrors;
            },
            _isAsyncNonBatch: function () {
                return this._async && !this.options.async.batch || false;
            },
            _renderInitialFiles: function (files) {
                var that = this;
                var idx = 0;
                files = assignGuidToFiles(files, true);
                for (idx = 0; idx < files.length; idx++) {
                    var currentFile = files[idx];
                    var fileEntry = that._enqueueFile(currentFile.name, { fileNames: [currentFile] });
                    fileEntry.addClass('k-file-success').data('files', [files[idx]]);
                    if (that._supportsRemove()) {
                        that._fileAction(fileEntry, REMOVE);
                    }
                }
            },
            _prepareTemplateData: function (name, data) {
                var filesData = data.fileNames, templateData = {}, totalSize = 0, idx = 0;
                for (idx = 0; idx < filesData.length; idx++) {
                    totalSize += filesData[idx].size;
                }
                templateData.name = name;
                templateData.size = totalSize;
                templateData.files = data.fileNames;
                return templateData;
            },
            _prepareDefaultSingleFileEntryTemplate: function (data) {
                var that = this;
                var file = data.fileNames[0];
                var fileSize = getTotalFilesSizeMessage(data.fileNames);
                var errors = file[VALIDATIONERRORS];
                var template = '';
                if (errors && errors.length > 0) {
                    template += '<li class=\'k-file k-file-invalid\'><span class=\'k-progress\'></span>' + '<span class=\'k-file-invalid-extension-wrapper\'>' + '<span class=\'k-file-invalid-icon\'>!</span>' + '<span class=\'k-file-state\'></span>' + '</span>' + '<span class=\'k-file-name-size-wrapper\'>' + '<span class=\'k-file-name k-file-name-invalid\' title=\'' + file.name + '\'>' + file.name + '</span>' + '<span class=\'k-file-validation-message\'>' + that.localization[errors[0]] + '</span>' + '</span>';
                } else {
                    template += '<li class=\'k-file\'><span class=\'k-progress\'></span>' + '<span class=\'k-file-extension-wrapper\'>' + '<span class=\'k-file-extension\'>' + file.extension.substring(1) + '</span>' + '<span class=\'k-file-state\'></span>' + '</span>' + '<span class=\'k-file-name-size-wrapper\'><span class=\'k-file-name\' title=\'' + file.name + '\'>' + file.name + '</span>' + '<span class=\'k-file-size\'>' + fileSize + '</span></span>';
                }
                template += '<strong class=\'k-upload-status\'></strong>';
                return $(template);
            },
            _prepareDefaultMultipleFileEntriesTemplate: function (data) {
                var that = this;
                var files = data.fileNames;
                var filesHaveValidationErrors = that._filesContainValidationErrors(files);
                var totalFileSize = getTotalFilesSizeMessage(files);
                var template = '';
                var i, currentFile;
                if (filesHaveValidationErrors) {
                    template += '<li class=\'k-file k-file-invalid\'><span class=\'k-progress\'></span>' + '<span class=\'k-multiple-files-invalid-extension-wrapper\'>' + '<span class=\'k-file-invalid-icon\'>!</span>';
                } else {
                    template += '<li class=\'k-file\'><span class=\'k-progress\'></span>' + '<span class=\'k-multiple-files-extension-wrapper\'>';
                }
                template += '<span class=\'k-file-state\'></span></span>';
                files.sort(function (a, b) {
                    if (a[VALIDATIONERRORS]) {
                        return -1;
                    }
                    if (b[VALIDATIONERRORS]) {
                        return 1;
                    }
                    return 0;
                });
                template += '<span class=\'k-file-name-size-wrapper\'>';
                for (i = 0; i < files.length; i++) {
                    currentFile = files[i];
                    if (currentFile[VALIDATIONERRORS] && currentFile[VALIDATIONERRORS].length > 0) {
                        template += '<span class=\'k-file-name k-file-name-invalid\' title=\'' + currentFile.name + '\'>' + currentFile.name + '</span>';
                    } else {
                        template += '<span class=\'k-file-name\' title=\'' + currentFile.name + '\'>' + currentFile.name + '</span>';
                    }
                }
                if (filesHaveValidationErrors) {
                    template += '<span class=\'k-file-validation-message\'>' + that.localization.invalidFiles + '</span>';
                } else {
                    template += '<span class=\'k-file-information\'>Total: ' + files.length + ' files, ' + totalFileSize + '</span>';
                }
                template += '</span><strong class=\'k-upload-status\'></strong>';
                return $(template);
            },
            _enqueueFile: function (name, data) {
                var that = this;
                var existingFileEntries;
                var fileEntry;
                var fileUid = data.fileNames[0].uid;
                var fileList = $('.k-upload-files', that.wrapper);
                var options = that.options;
                var template = options.template;
                var templateData;
                var removeEventArgs;
                if (fileList.length === 0) {
                    fileList = $('<ul class=\'k-upload-files k-reset\'></ul>').appendTo(that.wrapper);
                    if (!that.options.showFileList) {
                        fileList.hide();
                    }
                    that.wrapper.removeClass('k-upload-empty');
                }
                existingFileEntries = $('.k-file', fileList);
                if (!template) {
                    if (data.fileNames.length === 1) {
                        fileEntry = that._prepareDefaultSingleFileEntryTemplate(data);
                    } else {
                        fileEntry = that._prepareDefaultMultipleFileEntriesTemplate(data);
                    }
                } else {
                    templateData = that._prepareTemplateData(name, data);
                    template = kendo.template(template);
                    fileEntry = $('<li class=\'k-file\'>' + template(templateData) + '</li>');
                    fileEntry.find('.k-upload-action').addClass('k-button');
                    that.angular('compile', function () {
                        return {
                            elements: fileEntry,
                            data: [templateData]
                        };
                    });
                }
                fileEntry.attr(kendo.attr('uid'), fileUid).appendTo(fileList).data(data);
                if (!that._async) {
                    $('.k-progress', fileEntry).width('100%');
                }
                if (!that.multiple && existingFileEntries.length > 0) {
                    removeEventArgs = {
                        files: existingFileEntries.data('fileNames'),
                        headers: {}
                    };
                    if (!that.trigger(REMOVE, removeEventArgs)) {
                        that._module.onRemove({ target: $(existingFileEntries, that.wrapper) }, removeEventArgs);
                    }
                }
                return fileEntry;
            },
            _removeFileEntry: function (fileEntry) {
                var that = this;
                var fileList = fileEntry.closest('.k-upload-files');
                var allFiles, allCompletedFiles, allInvalidFiles;
                fileEntry.remove();
                allFiles = $('.k-file', fileList);
                allCompletedFiles = $('.k-file-success, .k-file-error', fileList);
                allInvalidFiles = $('.k-file-invalid', fileList);
                if (allCompletedFiles.length === allFiles.length || allInvalidFiles.length === allFiles.length) {
                    this._hideUploadButton();
                }
                if (allFiles.length === 0) {
                    fileList.remove();
                    that.wrapper.addClass('k-upload-empty');
                    that._hideHeaderUploadstatus();
                } else {
                    that._updateHeaderUploadStatus();
                }
            },
            _fileAction: function (fileElement, actionKey, skipClear) {
                var classDictionary = {
                    remove: 'k-i-x',
                    cancel: 'k-i-cancel',
                    retry: 'k-i-retry',
                    pause: 'k-i-pause-sm'
                };
                var iconsClassDictionary = {
                    remove: 'k-i-close',
                    cancel: 'k-i-close',
                    retry: 'k-i-reload-sm',
                    pause: 'k-i-pause-sm'
                };
                var firstActionButton;
                if (!classDictionary.hasOwnProperty(actionKey)) {
                    return;
                }
                if (!skipClear) {
                    this._clearFileAction(fileElement);
                }
                if (!this.options.template) {
                    if (!skipClear) {
                        fileElement.find('.k-upload-status .k-upload-action').remove();
                    }
                    fileElement.find('.k-upload-status').append(this._renderAction(classDictionary[actionKey], this.localization[actionKey], iconsClassDictionary[actionKey]));
                } else {
                    firstActionButton = fileElement.find('.k-upload-action').first();
                    if (!firstActionButton.find('.k-icon').length) {
                        firstActionButton.addClass('k-button').append('<span class=\'k-icon ' + iconsClassDictionary[actionKey] + ' ' + classDictionary[actionKey] + '\' title=\'' + this.localization[actionKey] + '\'' + 'aria-label=\'' + this.localization[actionKey] + '\'></span>').show();
                    } else if (firstActionButton.next('.k-upload-action').length) {
                        firstActionButton.next('.k-upload-action').addClass('k-button').append('<span class=\'k-icon ' + iconsClassDictionary[actionKey] + ' ' + classDictionary[actionKey] + '\' title=\'' + this.localization[actionKey] + '\'' + 'aria-label=\'' + this.localization[actionKey] + '\'></span>').show();
                    }
                }
            },
            _fileState: function (fileEntry, stateKey) {
                var localization = this.localization, states = {
                        uploading: { text: localization.statusUploading },
                        uploaded: { text: localization.statusUploaded },
                        failed: { text: localization.statusFailed }
                    }, currentState = states[stateKey];
                if (currentState) {
                    $('span.k-file-state', fileEntry).text(currentState.text);
                }
            },
            _renderAction: function (actionClass, actionText, iconClass) {
                if (actionClass !== '') {
                    return $('<button type=\'button\' class=\'k-button k-upload-action\' aria-label=\'' + actionText + '\'>' + '<span class=\'k-icon ' + iconClass + ' ' + actionClass + '\' title=\'' + actionText + '\'></span>' + '</button>').on('focus', function () {
                        $(this).addClass('k-state-focused');
                    }).on('blur', function () {
                        $(this).removeClass('k-state-focused');
                    });
                } else {
                    return $('<button type=\'button\' class=\'k-button\'>' + actionText + '</button>');
                }
            },
            _clearFileAction: function (fileElement) {
                $('.k-upload-action', fileElement).empty().hide();
            },
            _onFileAction: function (e) {
                var that = this;
                if (!that.wrapper.hasClass('k-state-disabled')) {
                    var button = $(e.target).closest('.k-upload-action');
                    var icon = button.find('.k-icon');
                    var fileEntry = button.closest('.k-file');
                    var files = fileEntry.data('fileNames');
                    var hasValidationErrors = that._filesContainValidationErrors(files);
                    var eventArgs = {
                        files: files,
                        headers: {}
                    };
                    that._retryClicked = false;
                    if (icon.hasClass('k-i-x')) {
                        if (!that.trigger(REMOVE, eventArgs)) {
                            that._module.onRemove({ target: $(fileEntry, that.wrapper) }, eventArgs, !hasValidationErrors);
                        }
                    } else if (icon.hasClass('k-i-cancel')) {
                        that.trigger(CANCEL, eventArgs);
                        that._module.onCancel({ target: $(fileEntry, that.wrapper) });
                        that._checkAllComplete();
                        that._updateHeaderUploadStatus();
                    } else if (icon.hasClass('k-i-pause-sm')) {
                        that.trigger(PAUSE, eventArgs);
                        that.pause(fileEntry);
                        that._updateHeaderUploadStatus();
                    } else if (icon.hasClass('k-i-play-sm')) {
                        that.trigger(RESUME, eventArgs);
                        that.resume(fileEntry);
                    } else if (icon.hasClass('k-i-retry')) {
                        $('.k-i-warning', fileEntry).remove();
                        $('.k-progress', fileEntry).finish().show();
                        that._module.onRetry({ target: $(fileEntry, that.wrapper) });
                        that._retryClicked = true;
                    }
                }
                return false;
            },
            _onUploadSelected: function () {
                var that = this;
                var wrapper = that.wrapper;
                if (!wrapper.hasClass('k-state-disabled')) {
                    this._module.onSaveSelected();
                }
                return false;
            },
            _onClearSelected: function () {
                var that = this;
                var wrapper = that.wrapper;
                var clearEventArgs = {};
                if (!wrapper.hasClass('k-state-disabled') && !that.trigger(CLEAR, clearEventArgs)) {
                    that.clearAllFiles();
                }
                return false;
            },
            _onFileProgress: function (e, percentComplete) {
                var progressPct;
                var warningPct;
                if (percentComplete > 100) {
                    percentComplete = 100;
                }
                if (!this.options.template) {
                    progressPct = $('.k-upload-pct', e.target);
                    warningPct = $('.k-i-warning', e.target);
                    if (warningPct.length) {
                        warningPct.removeClass('k-i-warning').removeClass('k-icon').addClass('k-upload-pct');
                    } else if (progressPct.length === 0) {
                        $('.k-upload-status', e.target).prepend('<span class=\'k-upload-pct\'></span>');
                    }
                    if (percentComplete !== 100) {
                        $('.k-upload-pct', e.target).text(percentComplete + '%');
                    } else {
                        $('.k-upload-pct', e.target).remove();
                    }
                    $('.k-progress', e.target).width(percentComplete + '%');
                } else {
                    $('.k-progress', e.target).width(percentComplete + '%');
                }
                this.trigger(PROGRESS, {
                    files: getFileEntry(e).data('fileNames'),
                    percentComplete: percentComplete
                });
            },
            _onUploadSuccess: function (e, response, xhr) {
                var that = this;
                var fileEntry = getFileEntry(e);
                var prevented = that.trigger(SUCCESS, {
                    files: fileEntry.data('fileNames'),
                    response: response,
                    operation: 'upload',
                    XMLHttpRequest: xhr
                });
                if (prevented) {
                    that._setUploadErrorState(fileEntry);
                } else {
                    that._fileState(fileEntry, 'uploaded');
                    fileEntry.removeClass('k-file-progress').addClass('k-file-success');
                    that._updateHeaderUploadStatus();
                    if (that._supportsRemove()) {
                        that._fileAction(fileEntry, REMOVE);
                    } else {
                        that._clearFileAction(fileEntry);
                    }
                }
                that._hideUploadProgress(fileEntry);
                that._checkAllComplete();
            },
            _onUploadError: function (e, xhr) {
                var that = this;
                var module = that._module;
                var fileEntry = getFileEntry(e);
                var fileUid = fileEntry.data('uid');
                that._setUploadErrorState(fileEntry);
                that.trigger(ERROR, {
                    operation: 'upload',
                    files: fileEntry.data('fileNames'),
                    XMLHttpRequest: xhr
                });
                logToConsole('Server response: ' + xhr.responseText);
                if (!that.options.async.chunkSize) {
                    that._hideUploadProgress(fileEntry);
                } else {
                    if (module._decreasePosition) {
                        module._decreasePosition(fileUid);
                    }
                }
                that._checkAllComplete();
                if (this.options.async.autoRetryAfter) {
                    this._autoRetryAfter(fileEntry);
                }
            },
            _autoRetryAfter: function (fileEntry) {
                var that = this;
                var retries = this._module.retries;
                if (!retries) {
                    return;
                }
                if (!retries[fileEntry.data('uid')]) {
                    retries[fileEntry.data('uid')] = 1;
                }
                if (retries[fileEntry.data('uid')] <= this.options.async.maxAutoRetries) {
                    retries[fileEntry.data('uid')]++;
                    setTimeout(function () {
                        that._module.performUpload(fileEntry);
                    }, this.options.async.autoRetryAfter);
                }
            },
            _setUploadErrorState: function (fileEntry) {
                var that = this;
                var uploadPercentage;
                that._fileState(fileEntry, 'failed');
                fileEntry.removeClass('k-file-progress').addClass('k-file-error');
                that._updateUploadProgress(fileEntry);
                uploadPercentage = $('.k-upload-pct', fileEntry);
                if (uploadPercentage.length > 0) {
                    if (!uploadPercentage.parent().find('.k-i-warning').length) {
                        uploadPercentage.removeClass('k-upload-pct').addClass('k-icon k-i-warning');
                    }
                    uploadPercentage.empty();
                } else {
                    $('.k-upload-status', fileEntry).prepend('<span class=\'k-icon k-i-warning\'></span>');
                }
                this._updateHeaderUploadStatus();
                this._fileAction(fileEntry, 'retry');
                this._fileAction(fileEntry, REMOVE, true);
                if (that._retryClicked) {
                    fileEntry.find('.k-i-retry').parent().focus();
                }
            },
            _updateUploadProgress: function (fileEntry) {
                var that = this;
                if (!that.options.async.chunkSize) {
                    $('.k-progress', fileEntry).width('100%');
                } else {
                    var fileUid = fileEntry.data('uid');
                    if (that._module.metaData) {
                        var fileMetaData = that._module.metaData[fileUid];
                        if (fileMetaData) {
                            var percentComplete = fileMetaData.totalChunks ? Math.round(fileMetaData.chunkIndex / fileMetaData.totalChunks * 100) : 100;
                            that._onFileProgress({ target: $(fileEntry, that.wrapper) }, percentComplete);
                        }
                    }
                }
            },
            _hideUploadProgress: function (fileEntry) {
                $('.k-progress', fileEntry).delay(PROGRESSHIDEDELAY).fadeOut(PROGRESSHIDEDURATION, function () {
                    $(this).css('width', '0%');
                });
            },
            _showUploadButton: function () {
                var that = this;
                var uploadButton = $('.k-upload-selected', that.wrapper);
                var clearButton = $('.k-clear-selected', that.wrapper);
                if (uploadButton.length === 0) {
                    uploadButton = that._renderAction('', this.localization.uploadSelectedFiles).addClass('k-upload-selected');
                    clearButton = that._renderAction('', this.localization.clearSelectedFiles).addClass('k-clear-selected');
                }
                this.wrapper.append(clearButton, uploadButton);
            },
            _hideUploadButton: function () {
                $('.k-upload-selected, .k-clear-selected', this.wrapper).remove();
            },
            _showHeaderUploadStatus: function (isUploading) {
                var that = this;
                var localization = that.localization;
                var dropZone = $('.k-dropzone', that.wrapper);
                var headerUploadStatus = $('.k-upload-status-total', that.wrapper);
                if (headerUploadStatus.length !== 0) {
                    headerUploadStatus.remove();
                }
                headerUploadStatus = '<strong class="k-upload-status k-upload-status-total"><span class="k-icon"></span></strong>';
                if (isUploading) {
                    headerUploadStatus = $(headerUploadStatus).append(localization.headerStatusUploading);
                    headerUploadStatus.find('.k-icon').addClass(headerStatusIcon.loading);
                } else {
                    headerUploadStatus = $(headerUploadStatus).append(localization.headerStatusUploaded);
                    headerUploadStatus.find('.k-icon').addClass(headerStatusIcon.warning);
                }
                if (dropZone.length > 0) {
                    dropZone.append(headerUploadStatus);
                } else {
                    $('.k-upload-button', that.wrapper).after(headerUploadStatus);
                }
            },
            _updateHeaderUploadStatus: function () {
                var that = this;
                var headerUploadStatus = $('.k-upload-status-total', this.wrapper);
                var currentlyUploading = $('.k-file', that.wrapper).not('.k-file-success, .k-file-error, .k-file-invalid');
                var currentlyInvalid = $('.k-file-invalid', that.wrapper);
                var currentlyFailed = $('.k-file-error', that.wrapper);
                var currentlyPaused = $('.k-file', that.wrapper).find('.k-i-play-sm');
                var failedUploads, headerUploadStatusIcon;
                if (currentlyPaused.length && (currentlyPaused.length === currentlyUploading.length || !that.options.async.concurrent)) {
                    headerUploadStatusIcon = $('.k-icon', headerUploadStatus).removeClass().addClass('k-icon').addClass('k-i-pause-sm');
                    headerUploadStatus.html(headerUploadStatusIcon).append(that.localization.headerStatusPaused);
                } else if (currentlyUploading.length === 0 || currentlyInvalid.length > 0 || currentlyFailed.length > 0) {
                    failedUploads = $('.k-file.k-file-error, .k-file.k-file-invalid', that.wrapper);
                    headerUploadStatus = $('.k-upload-status-total', that.wrapper);
                    headerUploadStatusIcon = $('.k-icon', headerUploadStatus).removeClass().addClass('k-icon').addClass(failedUploads.length !== 0 ? headerStatusIcon.warning : headerStatusIcon.success);
                    headerUploadStatus.html(headerUploadStatusIcon).append(that.localization.headerStatusUploaded);
                }
            },
            _hideHeaderUploadstatus: function () {
                $('.k-upload-status-total', this.wrapper).remove();
            },
            _onParentFormSubmit: function () {
                var upload = this, element = upload.element;
                if (typeof this._module.onAbort !== 'undefined') {
                    this._module.onAbort();
                }
                if (!element.value) {
                    var input = $(element);
                    input.attr('disabled', 'disabled');
                    window.setTimeout(function () {
                        input.removeAttr('disabled');
                    }, 0);
                }
            },
            _onParentFormReset: function () {
                $('.k-upload-files', this.wrapper).remove();
            },
            _supportsFormData: function () {
                return typeof FormData != 'undefined';
            },
            _supportsMultiple: function () {
                var windows = this._userAgent().indexOf('Windows') > -1;
                return !kendo.support.browser.opera && !(kendo.support.browser.safari && windows);
            },
            _supportsDrop: function () {
                var userAgent = this._userAgent().toLowerCase();
                var isChrome = /chrome/.test(userAgent);
                var isSafari = !isChrome && /safari/.test(userAgent);
                var isWindowsSafari = isSafari && /windows/.test(userAgent);
                return !isWindowsSafari && this._supportsFormData() && this.options.async.saveUrl;
            },
            _userAgent: function () {
                return navigator.userAgent;
            },
            _setupDropZone: function () {
                var that = this;
                $('.k-upload-button', that.wrapper).wrap('<div class=\'k-dropzone\'></div>');
                var ns = that._ns;
                var dropZone = $('.k-dropzone', that.wrapper).append($('<em>' + that.localization.dropFilesHere + '</em>')).on('dragenter' + ns, stopEvent).on('dragover' + ns, function (e) {
                    e.preventDefault();
                }).on('drop' + ns, $.proxy(that._onDrop, that));
                bindDragEventWrappers(dropZone, ns, function () {
                    if (!dropZone.closest('.k-upload').hasClass('k-state-disabled')) {
                        dropZone.addClass('k-dropzone-hovered');
                    }
                }, function () {
                    dropZone.removeClass('k-dropzone-hovered');
                });
                that._bindDocumentDragEventWrappers(dropZone);
            },
            _setupCustomDropZone: function () {
                var that = this;
                var dropZone = $(that.options.dropZone);
                $('.k-upload-button', that.wrapper).wrap('<div class=\'k-dropzone\'></div>').after($('<em>' + that.localization.dropFilesHere + '</em>'));
                var ns = that._ns;
                dropZone.on('dragenter' + ns, stopEvent).on('dragover' + ns, function (e) {
                    e.preventDefault();
                }).on('drop' + ns, $.proxy(that._onDrop, that));
                bindDragEventWrappers(dropZone, ns, function (e) {
                    if (!that.wrapper.hasClass('k-state-disabled')) {
                        dropZone.removeClass('k-dropzone-hovered');
                        $(e.target).addClass('k-dropzone-hovered');
                    }
                }, function () {
                    dropZone.removeClass('k-dropzone-hovered');
                    dropZone.find('.k-dropzone-hovered').removeClass('k-dropzone-hovered');
                });
                that._bindDocumentDragEventWrappers(dropZone);
            },
            _bindDocumentDragEventWrappers: function (dropZone) {
                var that = this;
                var ns = that._ns;
                bindDragEventWrappers($(document), ns, function () {
                    if (!that.wrapper.hasClass('k-state-disabled')) {
                        dropZone.addClass('k-dropzone-active');
                        dropZone.closest('.k-upload').removeClass('k-upload-empty');
                    }
                }, function () {
                    dropZone.removeClass('k-dropzone-active');
                    if ($('li.k-file', dropZone.closest('.k-upload')).length === 0) {
                        dropZone.closest('.k-upload').addClass('k-upload-empty');
                    }
                });
            },
            _supportsRemove: function () {
                return !!this.options.async.removeUrl;
            },
            _submitRemove: function (fileNames, eventArgs, onSuccess, onError) {
                var upload = this, removeField = upload.options.async.removeField || 'fileNames', params = $.extend(eventArgs.data, antiForgeryTokens());
                params[removeField] = fileNames;
                jQuery.ajax({
                    type: this.options.async.removeVerb,
                    dataType: 'json',
                    dataFilter: normalizeJSON,
                    url: this.options.async.removeUrl,
                    traditional: true,
                    data: params,
                    headers: eventArgs.headers,
                    success: onSuccess,
                    error: onError,
                    xhrFields: { withCredentials: this.options.async.withCredentials }
                });
            },
            _wrapInput: function (input) {
                var that = this;
                var options = that.options;
                input.wrap('<div class=\'k-widget k-upload k-header\'><div class=\'k-button k-upload-button\' aria-label=\'' + this.localization.select + '\'></div></div>');
                if (!options.async.saveUrl) {
                    input.closest('.k-upload').addClass('k-upload-sync');
                }
                input.closest('.k-upload').addClass('k-upload-empty');
                input.closest('.k-button').append('<span>' + this.localization.select + '</span>');
                return input.closest('.k-upload');
            },
            _checkAllComplete: function () {
                if ($('.k-file.k-file-progress', this.wrapper).length === 0) {
                    this.trigger(COMPLETE);
                }
            },
            _inputFiles: function (sourceInput) {
                return inputFiles(sourceInput);
            }
        });
        var syncUploadModule = function (upload) {
            this.name = 'syncUploadModule';
            this.element = upload.wrapper;
            this.upload = upload;
            this.element.closest('form').attr('enctype', 'multipart/form-data').attr('encoding', 'multipart/form-data');
        };
        syncUploadModule.prototype = {
            onSelect: function (e, files) {
                var upload = this.upload;
                var sourceInput = $(e.target);
                var filesContainErrors = upload._filesContainValidationErrors(files);
                upload._addInput(sourceInput);
                var fileData = { 'fileNames': files };
                if (filesContainErrors) {
                    sourceInput.remove();
                } else {
                    fileData.relatedInput = sourceInput;
                }
                var file = upload._enqueueFile(getFileName(sourceInput), fileData);
                if (filesContainErrors) {
                    upload._hideUploadProgress(file);
                }
                upload._fileAction(file, REMOVE);
            },
            onRemove: function (e) {
                var fileEntry = getFileEntry(e);
                var relatedInput = fileEntry.data('relatedInput');
                if (relatedInput) {
                    relatedInput.remove();
                }
                this.upload._removeFileEntry(fileEntry);
            }
        };
        var iframeUploadModule = function (upload) {
            this.name = 'iframeUploadModule';
            this.element = upload.wrapper;
            this.upload = upload;
            this.iframes = [];
        };
        Upload._frameId = 0;
        iframeUploadModule.prototype = {
            onSelect: function (e, files) {
                var upload = this.upload;
                var sourceInput = $(e.target);
                var hasValidationErrors = upload._filesContainValidationErrors(files);
                var fileEntry = this.prepareUpload(sourceInput, files, hasValidationErrors);
                if (upload.options.async.autoUpload) {
                    if (!hasValidationErrors) {
                        this.performUpload(fileEntry);
                    } else {
                        upload._fileAction(fileEntry, REMOVE);
                        upload._showHeaderUploadStatus(false);
                    }
                } else {
                    upload._fileAction(fileEntry, REMOVE);
                    if (!hasValidationErrors) {
                        upload._showUploadButton();
                    } else {
                        upload._updateHeaderUploadStatus();
                    }
                }
                if (hasValidationErrors) {
                    upload._hideUploadProgress(fileEntry);
                }
            },
            prepareUpload: function (sourceInput, files, hasValidationErrors) {
                var upload = this.upload;
                var activeInput = $(upload.element);
                var name = upload.options.async.saveField || sourceInput.attr('name');
                var fileEntry, fileData, iframe, form;
                upload._addInput(sourceInput);
                sourceInput.attr('name', name);
                if (!hasValidationErrors) {
                    iframe = this.createFrame(upload.name + '_' + Upload._frameId++);
                    this.registerFrame(iframe);
                    form = this.createForm(upload.options.async.saveUrl, iframe.attr('name')).append(activeInput);
                    fileData = {
                        'frame': iframe,
                        'relatedInput': activeInput,
                        'fileNames': files
                    };
                } else {
                    sourceInput.remove();
                    fileData = { 'fileNames': files };
                }
                fileEntry = upload._enqueueFile(getFileName(sourceInput), fileData);
                if (iframe) {
                    iframe.data({
                        'form': form,
                        'file': fileEntry
                    });
                }
                return fileEntry;
            },
            performUpload: function (fileEntry) {
                var e = { files: fileEntry.data('fileNames') };
                var iframe = fileEntry.data('frame');
                var upload = this.upload;
                if (!upload.trigger(UPLOAD, e)) {
                    upload._hideUploadButton();
                    upload._showHeaderUploadStatus(true);
                    iframe.appendTo(document.body);
                    var form = iframe.data('form').attr('action', upload.options.async.saveUrl).appendTo(document.body);
                    e.data = $.extend({}, e.data, antiForgeryTokens());
                    for (var key in e.data) {
                        var dataInput = form.find('input[name=\'' + key + '\']');
                        if (dataInput.length === 0) {
                            dataInput = $('<input>', {
                                type: 'hidden',
                                name: key
                            }).prependTo(form);
                        }
                        dataInput.val(e.data[key]);
                    }
                    upload._fileAction(fileEntry, CANCEL);
                    upload._fileState(fileEntry, 'uploading');
                    $(fileEntry).removeClass('k-file-error').addClass('k-file-progress');
                    iframe.one('load', $.proxy(this.onIframeLoad, this));
                    form[0].submit();
                } else {
                    upload._removeFileEntry(iframe.data('file'));
                    this.cleanupFrame(iframe);
                    this.unregisterFrame(iframe);
                }
            },
            onSaveSelected: function () {
                var module = this;
                var upload = module.upload;
                $('.k-file', this.element).each(function () {
                    var fileEntry = $(this);
                    var started = isFileUploadStarted(fileEntry);
                    var hasValidationErrors = upload._filesContainValidationErrors(fileEntry.data('fileNames'));
                    if (!started && !hasValidationErrors) {
                        module.performUpload(fileEntry);
                    }
                });
            },
            onIframeLoad: function (e) {
                var iframe = $(e.target), responseText;
                try {
                    responseText = iframe.contents().text();
                } catch (ex) {
                    responseText = 'Error trying to get server response: ' + ex;
                }
                this.processResponse(iframe, responseText);
            },
            processResponse: function (iframe, responseText) {
                var fileEntry = iframe.data('file'), module = this, fakeXHR = { responseText: responseText };
                tryParseJSON(responseText, function (jsonResult) {
                    $.extend(fakeXHR, {
                        statusText: 'OK',
                        status: '200'
                    });
                    module.upload._onFileProgress({ target: $(fileEntry, module.upload.wrapper) }, 100);
                    module.upload._onUploadSuccess({ target: $(fileEntry, module.upload.wrapper) }, jsonResult, fakeXHR);
                    module.cleanupFrame(iframe);
                    module.unregisterFrame(iframe);
                }, function () {
                    $.extend(fakeXHR, {
                        statusText: 'error',
                        status: '500'
                    });
                    module.upload._onUploadError({ target: $(fileEntry, module.upload.wrapper) }, fakeXHR);
                });
            },
            onCancel: function (e) {
                var iframe = $(e.target).data('frame');
                this.stopFrameSubmit(iframe);
                this.cleanupFrame(iframe);
                this.unregisterFrame(iframe);
                this.upload._removeFileEntry(iframe.data('file'));
            },
            onRetry: function (e) {
                var fileEntry = getFileEntry(e);
                this.performUpload(fileEntry);
            },
            onRemove: function (e, eventArgs, shouldSendRemoveRequest) {
                var module = this;
                var upload = module.upload;
                var fileEntry = getFileEntry(e);
                var iframe = fileEntry.data('frame');
                if (iframe) {
                    module.unregisterFrame(iframe);
                    upload._removeFileEntry(fileEntry);
                    module.cleanupFrame(iframe);
                } else {
                    if (fileEntry.hasClass('k-file-success')) {
                        removeUploadedFile(fileEntry, upload, eventArgs, shouldSendRemoveRequest);
                    } else {
                        upload._removeFileEntry(fileEntry);
                    }
                }
            },
            onAbort: function () {
                var element = this.element, module = this;
                $.each(this.iframes, function () {
                    $('input', this.data('form')).appendTo(element);
                    module.stopFrameSubmit(this[0]);
                    this.data('form').remove();
                    this.remove();
                });
                this.iframes = [];
            },
            createFrame: function (id) {
                return $('<iframe' + ' name=\'' + id + '\'' + ' id=\'' + id + '\'' + ' style=\'display:none;\' />');
            },
            createForm: function (action, target) {
                return $('<form enctype=\'multipart/form-data\' method=\'POST\'' + ' action=\'' + action + '\'' + ' target=\'' + target + '\'' + '/>');
            },
            stopFrameSubmit: function (frame) {
                if (typeof frame.stop != 'undefined') {
                    frame.stop();
                } else if (frame.document) {
                    frame.document.execCommand('Stop');
                }
            },
            registerFrame: function (frame) {
                this.iframes.push(frame);
            },
            unregisterFrame: function (frame) {
                this.iframes = $.grep(this.iframes, function (value) {
                    return value.attr('name') != frame.attr('name');
                });
            },
            cleanupFrame: function (frame) {
                var form = frame.data('form');
                frame.data('file').data('frame', null);
                setTimeout(function () {
                    form.remove();
                    frame.remove();
                }, 1);
            }
        };
        var formDataUploadModule = function (upload) {
            this.name = 'formDataUploadModule';
            this.element = upload.wrapper;
            this.upload = upload;
            this.position = {};
            this.metaData = {};
            this.cancelled = {};
            this.resume = {};
            this.paused = {};
            this.retries = {};
        };
        formDataUploadModule.prototype = {
            onSelect: function (e, files) {
                var upload = this.upload;
                var module = this;
                var sourceElement = $(e.target);
                var fileEntries = this.prepareUpload(sourceElement, files);
                var hasValidationErrors;
                var prev;
                $.each(fileEntries, function (index) {
                    hasValidationErrors = upload._filesContainValidationErrors($(this.data('fileNames')));
                    if (upload.options.async.autoUpload) {
                        if (!hasValidationErrors) {
                            if (upload.options.async.chunkSize) {
                                module.prepareChunk(this);
                                prev = this.prev();
                                if (upload.options.async.concurrent || index === 0 && !prev.length || index === 0 && prev.hasClass('k-file-success')) {
                                    module.performUpload(this);
                                }
                            } else {
                                module.performUpload(this);
                            }
                        } else {
                            upload._fileAction(this, REMOVE);
                            upload._showHeaderUploadStatus(false);
                        }
                    } else {
                        upload._fileAction(this, REMOVE);
                        if (!hasValidationErrors) {
                            upload._showUploadButton();
                            this.addClass('k-toupload');
                        } else {
                            upload._updateHeaderUploadStatus();
                        }
                    }
                    if (hasValidationErrors) {
                        upload._hideUploadProgress(this);
                    }
                });
            },
            prepareUpload: function (sourceElement, files) {
                var fileEntries = this.enqueueFiles(files);
                if (sourceElement.is('input')) {
                    $.each(fileEntries, function () {
                        $(this).data('relatedInput', sourceElement);
                    });
                    sourceElement.data('relatedFileEntries', fileEntries);
                    this.upload._addInput(sourceElement);
                }
                return fileEntries;
            },
            enqueueFiles: function (files) {
                var upload = this.upload;
                var name;
                var i;
                var filesLength = files.length;
                var currentFile;
                var fileEntry;
                var fileEntries = [];
                if (upload.options.async.batch === true) {
                    name = $.map(files, function (file) {
                        return file.name;
                    }).join(', ');
                    if (upload.directory || upload.options.directoryDrop) {
                        $(files).each(function () {
                            if (this.rawFile.webkitRelativePath || this.rawFile.relativePath) {
                                this.name = this.rawFile.webkitRelativePath || this.rawFile.relativePath;
                            }
                        });
                    }
                    fileEntry = upload._enqueueFile(name, { fileNames: files });
                    fileEntry.data('files', files);
                    fileEntries.push(fileEntry);
                } else {
                    for (i = 0; i < filesLength; i++) {
                        currentFile = files[i];
                        name = currentFile.name;
                        if (upload.directory || upload.options.directoryDrop) {
                            if (currentFile.rawFile.webkitRelativePath || currentFile.rawFile.relativePath) {
                                currentFile.name = currentFile.rawFile.webkitRelativePath || currentFile.rawFile.relativePath;
                            }
                        }
                        fileEntry = upload._enqueueFile(name, { fileNames: [currentFile] });
                        fileEntry.data('files', [currentFile]);
                        fileEntries.push(fileEntry);
                    }
                }
                return fileEntries;
            },
            performUpload: function (fileEntry) {
                var upload = this.upload, formData = this.createFormData(), xhr = this.createXHR(), e = {
                        files: fileEntry.data('fileNames'),
                        XMLHttpRequest: xhr
                    }, files;
                if (!upload.trigger(UPLOAD, e)) {
                    if (fileEntry.find('.k-i-cancel').length === 0) {
                        if (upload.options.async.chunkSize) {
                            upload._fileAction(fileEntry, PAUSE);
                        }
                        upload._fileAction(fileEntry, CANCEL, upload.options.async.chunkSize);
                    }
                    if (!upload.wrapper.find('.k-toupload').length) {
                        upload._hideUploadButton();
                    }
                    upload._showHeaderUploadStatus(true);
                    if (e.formData) {
                        formData = e.formData;
                    } else {
                        e.data = $.extend({}, e.data, antiForgeryTokens());
                        for (var key in e.data) {
                            formData.append(key, e.data[key]);
                        }
                        files = fileEntry.data('files');
                        if (files) {
                            this.populateFormData(formData, files);
                        }
                    }
                    upload._fileState(fileEntry, 'uploading');
                    $(fileEntry).removeClass('k-file-error').addClass('k-file-progress');
                    if (upload.options.async.useArrayBuffer && window.FileReader) {
                        this._readFile(upload.options.async.saveUrl, formData, fileEntry, xhr);
                    } else {
                        this.postFormData(upload.options.async.saveUrl, formData, fileEntry, xhr);
                    }
                } else {
                    this.removeFileEntry(fileEntry);
                }
            },
            _readFile: function (saveUrl, formData, fileEntry, xhr) {
                var that = this;
                var upload = that.upload;
                var file = fileEntry.data('files')[0];
                var reader = new FileReader();
                reader.onload = function (e) {
                    try {
                        if (!that.fileArrayBuffer) {
                            that.fileArrayBuffer = e.target.result;
                        } else {
                            that.fileArrayBuffer = that._appendBuffer(that.fileArrayBuffer, e.target.result);
                        }
                    } catch (err) {
                        upload._onUploadError({ target: $(fileEntry, upload.wrapper) }, xhr);
                        return;
                    }
                    if (that.position[file.uid] > file.size) {
                        that.postFormData(upload.options.async.saveUrl, that.fileArrayBuffer, fileEntry, xhr);
                        that.fileArrayBuffer = null;
                    } else {
                        that._readFile(saveUrl, formData, fileEntry, xhr);
                    }
                };
                reader.onerror = function () {
                    upload._onUploadError({ target: $(fileEntry, upload.wrapper) }, xhr);
                };
                reader.readAsArrayBuffer(that._getCurrentChunk(file.rawFile, file.uid));
            },
            _appendBuffer: function (buffer1, buffer2) {
                var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
                tmp.set(new Uint8Array(buffer1), 0);
                tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
                return tmp.buffer;
            },
            onSaveSelected: function () {
                var module = this;
                var upload = module.upload;
                $('.k-toupload', this.element).filter(function () {
                    var fileEntry = $(this);
                    var started = isFileUploadStarted(fileEntry);
                    var hasValidationErrors = upload._filesContainValidationErrors(fileEntry.data('fileNames'));
                    return !started && !hasValidationErrors;
                }).each(function (index) {
                    var fileEntry = $(this);
                    var prevEntry = fileEntry.prev();
                    fileEntry.removeClass('k-toupload');
                    if (upload.options.async.chunkSize) {
                        module.prepareChunk(fileEntry);
                        if (upload.options.async.concurrent || index === 0 && !prevEntry.length || (index === 0 && prevEntry.hasClass('k-file-success') || prevEntry.hasClass('k-file-error'))) {
                            module.performUpload(fileEntry);
                        }
                    } else {
                        module.performUpload(fileEntry);
                    }
                });
            },
            onCancel: function (e) {
                var fileEntry = getFileEntry(e);
                if (this.upload.options.async.chunkSize) {
                    this.cancelled[fileEntry.data('uid')] = true;
                }
                this.stopUploadRequest(fileEntry);
                this.removeFileEntry(fileEntry);
            },
            onPause: function (e) {
                var fileEntry = getFileEntry(e);
                var fileUid = fileEntry.data('uid');
                var async = this.upload.options.async;
                if (async.chunkSize) {
                    this.retries[fileUid] = async.maxAutoRetries + 1;
                    this.paused[fileUid] = true;
                    this.resume[fileUid] = false;
                }
            },
            onResume: function (e) {
                var fileEntry = getFileEntry(e);
                var fileUid = fileEntry.data('uid');
                if (this.upload.options.async.chunkSize) {
                    delete this.paused[fileUid];
                    this.resume[fileUid] = true;
                    this.retries[fileEntry.data('uid')] = 1;
                    this._increaseChunkIndex(fileUid);
                    this.performUpload(fileEntry);
                }
            },
            onRetry: function (e) {
                var fileEntry = getFileEntry(e);
                var async = this.upload.options.async;
                if (async.chunkSize) {
                    this.retries[fileEntry.data('uid')] = async.maxAutoRetries + 1;
                    delete this.paused[fileEntry.data('uid')];
                }
                this.performUpload(fileEntry);
            },
            onRemove: function (e, eventArgs, shouldSendRemoveRequest) {
                var module = this;
                var upload = module.upload;
                var fileEntry = getFileEntry(e);
                var async = this.upload.options.async;
                if (async.chunkSize) {
                    this.retries[fileEntry.data('uid')] = async.maxAutoRetries + 1;
                }
                if (fileEntry.hasClass('k-file-success')) {
                    removeUploadedFile(fileEntry, upload, eventArgs, shouldSendRemoveRequest);
                } else {
                    module.removeFileEntry(fileEntry);
                }
            },
            createXHR: function () {
                return new XMLHttpRequest();
            },
            postFormData: function (url, data, fileEntry, xhr) {
                var module = this;
                fileEntry.data('request', xhr);
                xhr.addEventListener('load', function (e) {
                    module.onRequestSuccess.call(module, e, fileEntry);
                }, false);
                xhr.addEventListener(ERROR, function (e) {
                    module.onRequestError.call(module, e, fileEntry);
                }, false);
                xhr.upload.addEventListener('progress', function (e) {
                    module.onRequestProgress.call(module, e, fileEntry);
                }, false);
                xhr.open('POST', url, true);
                xhr.withCredentials = this.upload.options.async.withCredentials;
                var accept = this.upload.options.async.accept;
                if (accept) {
                    xhr.setRequestHeader('Accept', accept);
                }
                xhr.send(data);
            },
            createFormData: function () {
                return new FormData();
            },
            populateFormData: function (data, files) {
                var chunk;
                var i;
                var length = files.length;
                var uid;
                var upload = this.upload;
                if (upload.options.async.chunkSize) {
                    uid = files[0].uid;
                    chunk = this._getCurrentChunk(files[0].rawFile, uid);
                    data.append(upload.options.async.saveField || upload.name, chunk);
                    var serializedMetaData = JSON.stringify(this.metaData[uid]);
                    data.append('metadata', serializedMetaData);
                } else {
                    for (i = 0; i < length; i++) {
                        data.append(upload.options.async.saveField || upload.name, files[i].rawFile);
                    }
                }
                return data;
            },
            onRequestSuccess: function (e, fileEntry) {
                var xhr = e.target, module = this;
                function raiseError() {
                    module.upload._onUploadError({ target: $(fileEntry, module.upload.wrapper) }, xhr);
                }
                function parseSuccess(jsonResult) {
                    var batch = module.upload.options.async.batch;
                    var chunkSize = module.upload.options.async.chunkSize;
                    var concurrent = module.upload.options.async.concurrent;
                    var fileUid = jsonResult.fileUid;
                    if (module.paused[fileUid] || module.cancelled[fileUid]) {
                        return;
                    }
                    delete module.retries[fileUid];
                    if (chunkSize && !batch && !jsonResult.uploaded) {
                        module._increaseChunkIndex(fileUid);
                        module.performUpload(fileEntry);
                    } else if (chunkSize && !batch && !concurrent && fileEntry.next().length && !fileEntry.next().hasClass('k-toupload')) {
                        module.upload._onFileProgress({ target: $(fileEntry, module.upload.wrapper) }, 100);
                        module._resetChunkIndex(fileUid);
                        module.upload._onUploadSuccess({ target: $(fileEntry, module.upload.wrapper) }, jsonResult, xhr);
                        module.performUpload(fileEntry.next());
                    } else {
                        module.upload._onFileProgress({ target: $(fileEntry, module.upload.wrapper) }, 100);
                        module.upload._onUploadSuccess({ target: $(fileEntry, module.upload.wrapper) }, jsonResult, xhr);
                        module.cleanupFileEntry(fileEntry);
                    }
                }
                if (xhr.status >= 200 && xhr.status <= 299) {
                    tryParseJSON(xhr.responseText, parseSuccess, raiseError);
                } else {
                    raiseError();
                }
            },
            onRequestError: function (e, fileEntry) {
                var xhr = e.target;
                this.upload._onUploadError({ target: $(fileEntry, this.upload.wrapper) }, xhr);
            },
            cleanupFileEntry: function (fileEntry) {
                var relatedInput = fileEntry.data('relatedInput'), uploadComplete = true;
                if (relatedInput) {
                    $.each(relatedInput.data('relatedFileEntries') || [], function () {
                        if (this.parent().length > 0 && this[0] != fileEntry[0]) {
                            uploadComplete = uploadComplete && this.hasClass('k-file-success');
                        }
                    });
                    if (uploadComplete) {
                        relatedInput.remove();
                    }
                }
            },
            removeFileEntry: function (fileEntry) {
                var chunkSize = this.upload.options.async.chunkSize;
                var concurrent = this.upload.options.async.concurrent;
                var isUploadButtonVisible = this.upload.wrapper.find('.k-upload-selected').length > 0;
                this.cleanupFileEntry(fileEntry);
                if (chunkSize && !concurrent && !isUploadButtonVisible) {
                    if (fileEntry.next().length) {
                        this.performUpload(fileEntry.next());
                    }
                }
                this.upload._removeFileEntry(fileEntry);
            },
            onRequestProgress: function (e, fileEntry) {
                var percentComplete = Math.round(e.loaded * 100 / e.total);
                var fileUid = fileEntry.data('uid');
                var fileMetaData;
                if (this.upload.options.async.chunkSize) {
                    fileMetaData = this.metaData[fileUid];
                    percentComplete = fileMetaData && fileMetaData.totalChunks ? Math.round(fileMetaData.chunkIndex / fileMetaData.totalChunks * 100) : 100;
                }
                this.upload._onFileProgress({ target: $(fileEntry, this.upload.wrapper) }, percentComplete);
            },
            stopUploadRequest: function (fileEntry) {
                fileEntry.data('request').abort();
            },
            prepareChunk: function (fileEntry) {
                var file = fileEntry.data('files')[0];
                var rawFile = file.rawFile;
                var uid = file.uid;
                var chunkSize = this.upload.options.async.chunkSize;
                this.position[uid] = 0;
                this.metaData[uid] = {
                    chunkIndex: 0,
                    contentType: rawFile.type,
                    fileName: rawFile.name,
                    relativePath: file.name,
                    totalFileSize: rawFile.size,
                    totalChunks: Math.ceil(rawFile.size / chunkSize),
                    uploadUid: uid
                };
            },
            _decreaseChunkIndex: function (uid) {
                this.metaData[uid].chunkIndex--;
            },
            _increaseChunkIndex: function (uid) {
                this.metaData[uid].chunkIndex++;
            },
            _resetChunkIndex: function (uid) {
                this.metaData[uid].chunkIndex = 0;
            },
            _decreasePosition: function (uid) {
                this.position[uid] -= this.upload.options.async.chunkSize;
            },
            _getCurrentChunk: function (file, uid) {
                var oldPosition = this.position[uid];
                var methodToInvoke;
                var async = this.upload.options.async;
                var chunkSize = async.chunkSize || async.bufferChunkSize;
                if (!this.position[uid]) {
                    this.position[uid] = 0;
                }
                this.position[uid] += chunkSize;
                if (!!(methodToInvoke = this._getChunker(file))) {
                    return file[methodToInvoke](oldPosition, this.position[uid]);
                } else {
                    return file;
                }
            },
            _getChunker: function (file) {
                if (file.slice) {
                    return 'slice';
                } else if (file.mozSlice) {
                    return 'mozSlice';
                } else if (file.webkitSlice) {
                    return 'webkitSlice';
                } else {
                    return null;
                }
            }
        };
        function getFileName(input) {
            return $.map(inputFiles(input), function (file) {
                return file.name;
            }).join(', ');
        }
        function inputFiles($input) {
            var input = $input[0];
            if (input.files) {
                return getAllFileInfo(input.files);
            } else {
                return [{
                        name: stripPath(input.value),
                        extension: getFileExtension(input.value),
                        size: null
                    }];
            }
        }
        function getAllFileInfo(rawFiles) {
            return $.map(rawFiles, function (file) {
                return getFileInfo(file);
            });
        }
        function getFileInfo(rawFile) {
            var fileName = rawFile.name || rawFile.fileName;
            return {
                name: kendo.htmlEncode(fileName),
                extension: getFileExtension(fileName),
                size: typeof rawFile.size == 'number' ? rawFile.size : rawFile.fileSize,
                rawFile: rawFile
            };
        }
        function getFileExtension(fileName) {
            var matches = fileName.match(rFileExtension);
            return matches ? matches[0] : '';
        }
        function stripPath(name) {
            var slashIndex = name.lastIndexOf('\\');
            return slashIndex != -1 ? name.substr(slashIndex + 1) : name;
        }
        function assignGuidToFiles(files, unique) {
            var uid = kendo.guid();
            return $.map(files, function (file) {
                file.uid = unique ? kendo.guid() : uid;
                return file;
            });
        }
        function validateFiles(files, validationInfo) {
            var allowedExtensions = parseAllowedExtensions(validationInfo.allowedExtensions);
            var maxFileSize = validationInfo.maxFileSize;
            var minFileSize = validationInfo.minFileSize;
            for (var i = 0; i < files.length; i++) {
                validateFileExtension(files[i], allowedExtensions);
                validateFileSize(files[i], minFileSize, maxFileSize);
            }
        }
        function parseAllowedExtensions(extensions) {
            var allowedExtensions = $.map(extensions, function (ext) {
                var parsedExt = ext.substring(0, 1) === '.' ? ext : '.' + ext;
                return parsedExt.toLowerCase();
            });
            return allowedExtensions;
        }
        function validateFileExtension(file, allowedExtensions) {
            if (allowedExtensions.length > 0) {
                if (allowedExtensions.indexOf(file.extension.toLowerCase()) < 0) {
                    file.validationErrors = file.validationErrors || [];
                    if ($.inArray(INVALIDFILEEXTENSION, file.validationErrors) === -1) {
                        file.validationErrors.push(INVALIDFILEEXTENSION);
                    }
                }
            }
        }
        function validateFileSize(file, minFileSize, maxFileSize) {
            if (minFileSize !== 0 && file.size < minFileSize) {
                file.validationErrors = file.validationErrors || [];
                if ($.inArray(INVALIDMINFILESIZE, file.validationErrors) === -1) {
                    file.validationErrors.push(INVALIDMINFILESIZE);
                }
            }
            if (maxFileSize !== 0 && file.size > maxFileSize) {
                file.validationErrors = file.validationErrors || [];
                if ($.inArray(INVALIDMAXFILESIZE, file.validationErrors) === -1) {
                    file.validationErrors.push(INVALIDMAXFILESIZE);
                }
            }
        }
        function getTotalFilesSizeMessage(files) {
            var totalSize = 0;
            if (typeof files[0].size == 'number') {
                for (var i = 0; i < files.length; i++) {
                    if (files[i].size) {
                        totalSize += files[i].size;
                    }
                }
            } else {
                return '';
            }
            totalSize /= 1024;
            if (totalSize < 1024) {
                return totalSize.toFixed(2) + ' KB';
            } else {
                return (totalSize / 1024).toFixed(2) + ' MB';
            }
        }
        function shouldRemoveFileEntry(upload) {
            return !upload.multiple && $('.k-file', upload.wrapper).length > 1;
        }
        function removeUploadedFile(fileEntry, upload, eventArgs, shouldSendRemoveRequest) {
            if (!upload._supportsRemove()) {
                if (shouldRemoveFileEntry(upload) || !shouldSendRemoveRequest) {
                    upload._removeFileEntry(fileEntry);
                }
                return;
            }
            var files = fileEntry.data('fileNames');
            var fileNames = $.map(files, function (file) {
                return file.name;
            });
            if (shouldSendRemoveRequest === false) {
                upload._removeFileEntry(fileEntry);
                return;
            }
            upload._submitRemove(fileNames, eventArgs, function onSuccess(data, textStatus, xhr) {
                var prevented = upload.trigger(SUCCESS, {
                    operation: 'remove',
                    files: files,
                    response: data,
                    XMLHttpRequest: xhr
                });
                if (!prevented) {
                    upload._removeFileEntry(fileEntry);
                }
            }, function onError(xhr) {
                if (shouldRemoveFileEntry(upload)) {
                    upload._removeFileEntry(fileEntry);
                }
                upload.trigger(ERROR, {
                    operation: 'remove',
                    files: files,
                    XMLHttpRequest: xhr
                });
                logToConsole('Server response: ' + xhr.responseText);
            });
        }
        function tryParseJSON(input, onSuccess, onError) {
            var success = false, json = '';
            try {
                json = $.parseJSON(normalizeJSON(input));
                success = true;
            } catch (e) {
                onError();
            }
            if (success) {
                onSuccess(json);
            }
        }
        function normalizeJSON(input) {
            if (typeof input === 'undefined' || input === '') {
                input = '{}';
            }
            return input;
        }
        function stopEvent(e) {
            e.stopPropagation();
            e.preventDefault();
        }
        function bindDragEventWrappers(element, namespace, onDragEnter, onDragLeave) {
            var hideInterval, lastDrag;
            element.on('dragenter' + namespace, function (e) {
                onDragEnter(e);
                lastDrag = new Date();
                if (!hideInterval) {
                    hideInterval = setInterval(function () {
                        var sinceLastDrag = new Date() - lastDrag;
                        if (sinceLastDrag > 100) {
                            onDragLeave();
                            clearInterval(hideInterval);
                            hideInterval = null;
                        }
                    }, 100);
                }
            }).on('dragover' + namespace, function () {
                lastDrag = new Date();
            });
        }
        function isFileUploadStarted(fileEntry) {
            return fileEntry.is('.k-file-progress, .k-file-success, .k-file-error');
        }
        function getFileEntry(e) {
            return $(e.target).closest('.k-file');
        }
        kendo.ui.plugin(Upload);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.filebrowser', [
        'kendo.listview',
        'kendo.dropdownlist',
        'kendo.upload'
    ], f);
}(function () {
    var __meta__ = {
        id: 'filebrowser',
        name: 'FileBrowser',
        category: 'web',
        description: '',
        hidden: true,
        depends: [
            'selectable',
            'listview',
            'dropdownlist',
            'upload'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, isPlainObject = $.isPlainObject, proxy = $.proxy, extend = $.extend, placeholderSupported = kendo.support.placeholder, browser = kendo.support.browser, isFunction = kendo.isFunction, trimSlashesRegExp = /(^\/|\/$)/g, CHANGE = 'change', APPLY = 'apply', ERROR = 'error', CLICK = 'click', NS = '.kendoFileBrowser', BREADCRUBMSNS = '.kendoBreadcrumbs', SEARCHBOXNS = '.kendoSearchBox', NAMEFIELD = 'name', SIZEFIELD = 'size', TYPEFIELD = 'type', DEFAULTSORTORDER = {
                field: TYPEFIELD,
                dir: 'asc'
            }, EMPTYTILE = kendo.template('<li class="k-tile-empty"><strong>${text}</strong></li>'), TOOLBARTMPL = '<div class="k-widget k-filebrowser-toolbar k-header k-floatwrap">' + '<div class="k-toolbar-wrap">' + '# if (showUpload) { # ' + '<div class="k-widget k-upload"><div class="k-button k-button-icontext k-upload-button">' + '<span class="k-icon k-i-plus"></span>#=messages.uploadFile#<input type="file" name="file" /></div></div>' + '# } #' + '# if (showCreate) { #' + '<button type="button" class="k-button k-button-icon"><span class="k-icon k-i-folder-add" /></button>' + '# } #' + '# if (showDelete) { #' + '<button type="button" class="k-button k-button-icon k-state-disabled"><span class="k-icon k-i-close" /></button>&nbsp;' + '# } #' + '</div>' + '<div class="k-tiles-arrange">' + '<label>#=messages.orderBy#: <select /></label>' + '</div>' + '</div>';
        extend(true, kendo.data, {
            schemas: {
                'filebrowser': {
                    data: function (data) {
                        return data.items || data || [];
                    },
                    model: {
                        id: 'name',
                        fields: {
                            name: 'name',
                            size: 'size',
                            type: 'type'
                        }
                    }
                }
            }
        });
        extend(true, kendo.data, {
            transports: {
                'filebrowser': kendo.data.RemoteTransport.extend({
                    init: function (options) {
                        kendo.data.RemoteTransport.fn.init.call(this, $.extend(true, {}, this.options, options));
                    },
                    _call: function (type, options) {
                        options.data = $.extend({}, options.data, { path: this.options.path() });
                        if (isFunction(this.options[type])) {
                            this.options[type].call(this, options);
                        } else {
                            kendo.data.RemoteTransport.fn[type].call(this, options);
                        }
                    },
                    read: function (options) {
                        this._call('read', options);
                    },
                    create: function (options) {
                        this._call('create', options);
                    },
                    destroy: function (options) {
                        this._call('destroy', options);
                    },
                    update: function () {
                    },
                    options: {
                        read: { type: 'POST' },
                        update: { type: 'POST' },
                        create: { type: 'POST' },
                        destroy: { type: 'POST' }
                    }
                })
            }
        });
        function bindDragEventWrappers(element, onDragEnter, onDragLeave) {
            var hideInterval, lastDrag;
            element.on('dragenter' + NS, function () {
                onDragEnter();
                lastDrag = new Date();
                if (!hideInterval) {
                    hideInterval = setInterval(function () {
                        var sinceLastDrag = new Date() - lastDrag;
                        if (sinceLastDrag > 100) {
                            onDragLeave();
                            clearInterval(hideInterval);
                            hideInterval = null;
                        }
                    }, 100);
                }
            }).on('dragover' + NS, function () {
                lastDrag = new Date();
            });
        }
        var offsetTop;
        if (browser.msie && browser.version < 8) {
            offsetTop = function (element) {
                return element.offsetTop;
            };
        } else {
            offsetTop = function (element) {
                return element.offsetTop - $(element).height();
            };
        }
        function concatPaths(path, name) {
            if (path === undefined || !path.match(/\/$/)) {
                path = (path || '') + '/';
            }
            return path + name;
        }
        function sizeFormatter(value) {
            if (!value) {
                return '';
            }
            var suffix = ' bytes';
            if (value >= 1073741824) {
                suffix = ' GB';
                value /= 1073741824;
            } else if (value >= 1048576) {
                suffix = ' MB';
                value /= 1048576;
            } else if (value >= 1024) {
                suffix = ' KB';
                value /= 1024;
            }
            return Math.round(value * 100) / 100 + suffix;
        }
        function fieldName(fields, name) {
            var descriptor = fields[name];
            if (isPlainObject(descriptor)) {
                return descriptor.from || descriptor.field || name;
            }
            return descriptor;
        }
        var FileBrowser = Widget.extend({
            init: function (element, options) {
                var that = this;
                options = options || {};
                Widget.fn.init.call(that, element, options);
                that.element.addClass('k-filebrowser');
                that.element.on(CLICK + NS, '.k-filebrowser-toolbar button:not(.k-state-disabled):has(.k-i-close)', proxy(that._deleteClick, that)).on(CLICK + NS, '.k-filebrowser-toolbar button:not(.k-state-disabled):has(.k-i-folder-add)', proxy(that._addClick, that)).on('keydown' + NS, 'li.k-state-selected input', proxy(that._directoryKeyDown, that)).on('blur' + NS, 'li.k-state-selected input', proxy(that._directoryBlur, that));
                that._dataSource();
                that.refresh();
                that.path(that.options.path);
            },
            options: {
                name: 'FileBrowser',
                messages: {
                    uploadFile: 'Upload',
                    orderBy: 'Arrange by',
                    orderByName: 'Name',
                    orderBySize: 'Size',
                    directoryNotFound: 'A directory with this name was not found.',
                    emptyFolder: 'Empty Folder',
                    deleteFile: 'Are you sure you want to delete "{0}"?',
                    invalidFileType: 'The selected file "{0}" is not valid. Supported file types are {1}.',
                    overwriteFile: 'A file with name "{0}" already exists in the current directory. Do you want to overwrite it?',
                    dropFilesHere: 'drop file here to upload',
                    search: 'Search'
                },
                transport: {},
                path: '/',
                fileTypes: '*.*'
            },
            events: [
                ERROR,
                CHANGE,
                APPLY
            ],
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.dataSource.unbind(ERROR, that._errorHandler);
                that.element.add(that.list).add(that.toolbar).off(NS);
                kendo.destroy(that.element);
            },
            value: function () {
                var that = this, selected = that._selectedItem(), path, fileUrl = that.options.transport.fileUrl;
                if (selected && selected.get(TYPEFIELD) === 'f') {
                    path = concatPaths(that.path(), selected.get(NAMEFIELD)).replace(trimSlashesRegExp, '');
                    if (fileUrl) {
                        path = isFunction(fileUrl) ? fileUrl(path) : kendo.format(fileUrl, encodeURIComponent(path));
                    }
                    return path;
                }
            },
            _selectedItem: function () {
                var listView = this.listView, selected = listView.select();
                if (selected.length) {
                    return this.dataSource.getByUid(selected.attr(kendo.attr('uid')));
                }
            },
            _toolbar: function () {
                var that = this, template = kendo.template(TOOLBARTMPL), messages = that.options.messages, arrangeBy = [
                        {
                            text: messages.orderByName,
                            value: 'name'
                        },
                        {
                            text: messages.orderBySize,
                            value: 'size'
                        }
                    ];
                that.toolbar = $(template({
                    messages: messages,
                    showUpload: that.options.transport.uploadUrl,
                    showCreate: that.options.transport.create,
                    showDelete: that.options.transport.destroy
                })).appendTo(that.element).find('.k-upload input').kendoUpload({
                    multiple: false,
                    localization: { dropFilesHere: messages.dropFilesHere },
                    async: {
                        saveUrl: that.options.transport.uploadUrl,
                        autoUpload: true
                    },
                    upload: proxy(that._fileUpload, that),
                    error: function (e) {
                        that._error({
                            xhr: e.XMLHttpRequest,
                            status: 'error'
                        });
                    }
                }).end();
                that.upload = that.toolbar.find('.k-upload input').data('kendoUpload');
                that.arrangeBy = that.toolbar.find('.k-tiles-arrange select').kendoDropDownList({
                    dataSource: arrangeBy,
                    dataTextField: 'text',
                    dataValueField: 'value',
                    change: function () {
                        that.orderBy(this.value());
                    }
                }).data('kendoDropDownList');
                that._attachDropzoneEvents();
            },
            _attachDropzoneEvents: function () {
                var that = this;
                if (that.options.transport.uploadUrl) {
                    bindDragEventWrappers($(document.documentElement), $.proxy(that._dropEnter, that), $.proxy(that._dropLeave, that));
                    that._scrollHandler = proxy(that._positionDropzone, that);
                }
            },
            _dropEnter: function () {
                this._positionDropzone();
                $(document).on('scroll' + NS, this._scrollHandler);
            },
            _dropLeave: function () {
                this._removeDropzone();
                $(document).off('scroll' + NS, this._scrollHandler);
            },
            _positionDropzone: function () {
                var that = this, element = that.element, offset = element.offset();
                that.toolbar.find('.k-dropzone').addClass('k-filebrowser-dropzone').offset(offset).css({
                    width: element[0].clientWidth,
                    height: element[0].clientHeight,
                    lineHeight: element[0].clientHeight + 'px'
                });
            },
            _removeDropzone: function () {
                this.toolbar.find('.k-dropzone').removeClass('k-filebrowser-dropzone').css({
                    width: '',
                    height: '',
                    lineHeight: '',
                    top: '',
                    left: ''
                });
            },
            _deleteClick: function () {
                var that = this, item = that.listView.select(), message = kendo.format(that.options.messages.deleteFile, item.find('strong').text());
                if (item.length && that._showMessage(message, 'confirm')) {
                    that.listView.remove(item);
                }
            },
            _addClick: function () {
                this.createDirectory();
            },
            _getFieldName: function (name) {
                return fieldName(this.dataSource.reader.model.fields, name);
            },
            _fileUpload: function (e) {
                var that = this, options = that.options, fileTypes = options.fileTypes, filterRegExp = new RegExp(('(' + fileTypes.split(',').join(')|(') + ')').replace(/\*\./g, '.*.'), 'i'), fileName = e.files[0].name, fileSize = e.files[0].size, fileNameField = NAMEFIELD, sizeField = SIZEFIELD, file;
                if (filterRegExp.test(fileName)) {
                    e.data = { path: that.path() };
                    file = that._createFile(fileName, fileSize);
                    if (!file) {
                        e.preventDefault();
                    } else {
                        that.upload.one('success', function (e) {
                            var model = that._insertFileToList(file);
                            if (model._override) {
                                model.set(fileNameField, e.response[that._getFieldName(fileNameField)]);
                                model.set(sizeField, e.response[that._getFieldName(sizeField)]);
                                that.listView.dataSource.pushUpdate(model);
                            }
                            that._tiles = that.listView.items().filter('[' + kendo.attr('type') + '=f]');
                        });
                    }
                } else {
                    e.preventDefault();
                    that._showMessage(kendo.format(options.messages.invalidFileType, fileName, fileTypes));
                }
            },
            _findFile: function (name) {
                var data = this.dataSource.data(), idx, result, typeField = TYPEFIELD, nameField = NAMEFIELD, length;
                name = name.toLowerCase();
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].get(typeField) === 'f' && data[idx].get(nameField).toLowerCase() === name) {
                        result = data[idx];
                        break;
                    }
                }
                return result;
            },
            _createFile: function (fileName, fileSize) {
                var that = this, model = {}, typeField = TYPEFIELD, file = that._findFile(fileName);
                if (file) {
                    if (!that._showMessage(kendo.format(that.options.messages.overwriteFile, fileName), 'confirm')) {
                        return null;
                    } else {
                        file._override = true;
                        return file;
                    }
                }
                model[typeField] = 'f';
                model[NAMEFIELD] = fileName;
                model[SIZEFIELD] = fileSize;
                return model;
            },
            _insertFileToList: function (model) {
                var index;
                if (model._override) {
                    return model;
                }
                var dataSource = this.dataSource;
                var view = dataSource.view();
                for (var i = 0, length = view.length; i < length; i++) {
                    if (view[i].get(TYPEFIELD) === 'f') {
                        index = i;
                        break;
                    }
                }
                return dataSource.insert(++index, model);
            },
            createDirectory: function () {
                var that = this, idx, length, lastDirectoryIdx = 0, typeField = TYPEFIELD, nameField = NAMEFIELD, view = that.dataSource.data(), name = that._nameDirectory(), model = new that.dataSource.reader.model();
                for (idx = 0, length = view.length; idx < length; idx++) {
                    if (view[idx].get(typeField) === 'd') {
                        lastDirectoryIdx = idx;
                    }
                }
                model.set(typeField, 'd');
                model.set(nameField, name);
                that.listView.one('dataBound', function () {
                    var selected = that.listView.items().filter('[' + kendo.attr('uid') + '=' + model.uid + ']');
                    if (selected.length) {
                        this.edit(selected);
                    }
                    this.element.scrollTop(selected.attr('offsetTop') - this.element[0].offsetHeight);
                    setTimeout(function () {
                        that.listView.element.find('.k-edit-item input').select();
                    });
                }).one('save', function (e) {
                    var value = e.model.get(nameField);
                    if (!value) {
                        e.model.set(nameField, name);
                    } else {
                        e.model.set(nameField, that._nameExists(value, model.uid) ? that._nameDirectory() : value);
                    }
                });
                that.dataSource.insert(++lastDirectoryIdx, model);
            },
            _directoryKeyDown: function (e) {
                if (e.keyCode == 13) {
                    e.currentTarget.blur();
                }
            },
            _directoryBlur: function () {
                this.listView.save();
            },
            _nameExists: function (name, uid) {
                var data = this.dataSource.data(), typeField = TYPEFIELD, nameField = NAMEFIELD, idx, length;
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].get(typeField) === 'd' && data[idx].get(nameField).toLowerCase() === name.toLowerCase() && data[idx].uid !== uid) {
                        return true;
                    }
                }
                return false;
            },
            _nameDirectory: function () {
                var name = 'New folder', data = this.dataSource.data(), directoryNames = [], typeField = TYPEFIELD, nameField = NAMEFIELD, candidate, idx, length;
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].get(typeField) === 'd' && data[idx].get(nameField).toLowerCase().indexOf(name.toLowerCase()) > -1) {
                        directoryNames.push(data[idx].get(nameField));
                    }
                }
                if ($.inArray(name, directoryNames) > -1) {
                    idx = 2;
                    do {
                        candidate = name + ' (' + idx + ')';
                        idx++;
                    } while ($.inArray(candidate, directoryNames) > -1);
                    name = candidate;
                }
                return name;
            },
            orderBy: function (field) {
                this.dataSource.sort([
                    {
                        field: TYPEFIELD,
                        dir: 'asc'
                    },
                    {
                        field: field,
                        dir: 'asc'
                    }
                ]);
            },
            search: function (name) {
                this.dataSource.filter({
                    field: NAMEFIELD,
                    operator: 'contains',
                    value: name
                });
            },
            _content: function () {
                var that = this;
                that.list = $('<ul class="k-reset k-floats k-tiles" />').appendTo(that.element).on('dblclick' + NS, 'li', proxy(that._dblClick, that));
                that.listView = new kendo.ui.ListView(that.list, {
                    dataSource: that.dataSource,
                    template: that._itemTmpl(),
                    editTemplate: that._editTmpl(),
                    selectable: true,
                    autoBind: false,
                    dataBinding: function (e) {
                        that.toolbar.find('.k-i-close').parent().addClass('k-state-disabled');
                        if (e.action === 'remove' || e.action === 'sync') {
                            e.preventDefault();
                            kendo.ui.progress(that.listView.element, false);
                        }
                    },
                    dataBound: function () {
                        if (that.dataSource.view().length) {
                            that._tiles = this.items().filter('[' + kendo.attr('type') + '=f]');
                        } else {
                            this.wrapper.append(EMPTYTILE({ text: that.options.messages.emptyFolder }));
                        }
                    },
                    change: proxy(that._listViewChange, that)
                });
            },
            _dblClick: function (e) {
                var that = this, li = $(e.currentTarget);
                if (li.hasClass('k-edit-item')) {
                    that._directoryBlur();
                }
                if (li.filter('[' + kendo.attr('type') + '=d]').length) {
                    var folder = that.dataSource.getByUid(li.attr(kendo.attr('uid')));
                    if (folder) {
                        that.path(concatPaths(that.path(), folder.get(NAMEFIELD)));
                        that.breadcrumbs.value(that.path());
                    }
                } else if (li.filter('[' + kendo.attr('type') + '=f]').length) {
                    that.trigger(APPLY);
                }
            },
            _listViewChange: function () {
                var selected = this._selectedItem();
                if (selected) {
                    this.toolbar.find('.k-i-close').parent().removeClass('k-state-disabled');
                    this.trigger(CHANGE, { selected: selected });
                }
            },
            _dataSource: function () {
                var that = this, options = that.options, transport = options.transport, typeSortOrder = extend({}, DEFAULTSORTORDER), nameSortOrder = {
                        field: NAMEFIELD,
                        dir: 'asc'
                    }, schema, dataSource = {
                        type: transport.type || 'filebrowser',
                        sort: [
                            typeSortOrder,
                            nameSortOrder
                        ]
                    };
                if (isPlainObject(transport)) {
                    transport.path = proxy(that.path, that);
                    dataSource.transport = transport;
                }
                if (isPlainObject(options.schema)) {
                    dataSource.schema = options.schema;
                } else if (transport.type && isPlainObject(kendo.data.schemas[transport.type])) {
                    schema = kendo.data.schemas[transport.type];
                }
                if (that.dataSource && that._errorHandler) {
                    that.dataSource.unbind(ERROR, that._errorHandler);
                } else {
                    that._errorHandler = proxy(that._error, that);
                }
                that.dataSource = kendo.data.DataSource.create(dataSource).bind(ERROR, that._errorHandler);
            },
            _navigation: function () {
                var that = this, navigation = $('<div class="k-floatwrap"><input/><input/></div>').appendTo(this.element);
                that.breadcrumbs = navigation.find('input:first').kendoBreadcrumbs({
                    value: that.options.path,
                    change: function () {
                        that.path(this.value());
                    }
                }).data('kendoBreadcrumbs');
                that.searchBox = navigation.parent().find('input:last').kendoSearchBox({
                    label: that.options.messages.search,
                    change: function () {
                        that.search(this.value());
                    }
                }).data('kendoSearchBox');
            },
            _error: function (e) {
                var that = this, status;
                if (!that.trigger(ERROR, e)) {
                    status = e.xhr.status;
                    if (e.status == 'error') {
                        if (status == '404') {
                            that._showMessage(that.options.messages.directoryNotFound);
                        } else if (status != '0') {
                            that._showMessage('Error! The requested URL returned ' + status + ' - ' + e.xhr.statusText);
                        }
                    } else if (status == 'timeout') {
                        that._showMessage('Error! Server timeout.');
                    }
                    var dataSource = that.dataSource;
                    if (dataSource.hasChanges()) {
                        dataSource.cancelChanges();
                    }
                }
            },
            _showMessage: function (message, type) {
                return window[type || 'alert'](message);
            },
            refresh: function () {
                var that = this;
                that._navigation();
                that._toolbar();
                that._content();
            },
            _editTmpl: function () {
                var html = '<li class="k-tile k-state-selected" ' + kendo.attr('uid') + '="#=uid#" ';
                html += kendo.attr('type') + '="${' + TYPEFIELD + '}">';
                html += '#if(' + TYPEFIELD + ' == "d") { #';
                html += '<div class="k-thumb"><span class="k-icon k-i-folder"></span></div>';
                html += '#}else{#';
                html += '<div class="k-thumb"><span class="k-icon k-i-loading"></span></div>';
                html += '#}#';
                html += '#if(' + TYPEFIELD + ' == "d") { #';
                html += '<input class="k-input" ' + kendo.attr('bind') + '="value:' + NAMEFIELD + '"/>';
                html += '#}#';
                html += '</li>';
                return proxy(kendo.template(html), { sizeFormatter: sizeFormatter });
            },
            _itemTmpl: function () {
                var html = '<li class="k-tile" ' + kendo.attr('uid') + '="#=uid#" ';
                html += kendo.attr('type') + '="${' + TYPEFIELD + '}">';
                html += '#if(' + TYPEFIELD + ' == "d") { #';
                html += '<div class="k-thumb"><span class="k-icon k-i-folder"></span></div>';
                html += '#}else{#';
                html += '<div class="k-thumb"><span class="k-icon k-i-file"></span></div>';
                html += '#}#';
                html += '<strong>${' + NAMEFIELD + '}</strong>';
                html += '#if(' + TYPEFIELD + ' == "f") { # <span class="k-filesize">${this.sizeFormatter(' + SIZEFIELD + ')}</span> #}#';
                html += '</li>';
                return proxy(kendo.template(html), { sizeFormatter: sizeFormatter });
            },
            path: function (value) {
                var that = this, path = that._path || '';
                if (value !== undefined) {
                    that._path = value.replace(trimSlashesRegExp, '') + '/';
                    that.dataSource.read({ path: that._path });
                    return;
                }
                if (path) {
                    path = path.replace(trimSlashesRegExp, '');
                }
                return path === '/' || path === '' ? '' : path + '/';
            }
        });
        var SearchBox = Widget.extend({
            init: function (element, options) {
                var that = this;
                options = options || {};
                Widget.fn.init.call(that, element, options);
                if (placeholderSupported) {
                    that.element.attr('placeholder', that.options.label);
                }
                that._wrapper();
                that.element.on('keydown' + SEARCHBOXNS, proxy(that._keydown, that)).on('change' + SEARCHBOXNS, proxy(that._updateValue, that));
                that.wrapper.on(CLICK + SEARCHBOXNS, 'a', proxy(that._click, that));
                if (!placeholderSupported) {
                    that.element.on('focus' + SEARCHBOXNS, proxy(that._focus, that)).on('blur' + SEARCHBOXNS, proxy(that._blur, that));
                }
            },
            options: {
                name: 'SearchBox',
                label: 'Search',
                value: ''
            },
            events: [CHANGE],
            destroy: function () {
                var that = this;
                that.wrapper.add(that.element).add(that.label).off(SEARCHBOXNS);
                Widget.fn.destroy.call(that);
            },
            _keydown: function (e) {
                if (e.keyCode === 13) {
                    this._updateValue();
                }
            },
            _click: function (e) {
                e.preventDefault();
                this._updateValue();
            },
            _updateValue: function () {
                var that = this, value = that.element.val();
                if (value !== that.value()) {
                    that.value(value);
                    that.trigger(CHANGE);
                }
            },
            _blur: function () {
                this._updateValue();
                this._toggleLabel();
            },
            _toggleLabel: function () {
                if (!placeholderSupported) {
                    this.label.toggle(!this.element.val());
                }
            },
            _focus: function () {
                this.label.hide();
            },
            _wrapper: function () {
                var element = this.element, wrapper = element.parents('.k-search-wrap');
                element[0].style.width = '';
                element.addClass('k-input');
                if (!wrapper.length) {
                    wrapper = element.wrap($('<div class="k-widget k-search-wrap k-textbox"/>')).parent();
                    if (!placeholderSupported) {
                        $('<label style="display:block">' + this.options.label + '</label>').insertBefore(element);
                    }
                    $('<a href="#" class="k-icon k-i-zoom k-search"/>').appendTo(wrapper);
                }
                this.wrapper = wrapper;
                this.label = wrapper.find('>label');
            },
            value: function (value) {
                var that = this;
                if (value !== undefined) {
                    that.options.value = value;
                    that.element.val(value);
                    that._toggleLabel();
                    return;
                }
                return that.options.value;
            }
        });
        var Breadcrumbs = Widget.extend({
            init: function (element, options) {
                var that = this;
                options = options || {};
                Widget.fn.init.call(that, element, options);
                that._wrapper();
                that.wrapper.on('focus' + BREADCRUBMSNS, 'input', proxy(that._focus, that)).on('blur' + BREADCRUBMSNS, 'input', proxy(that._blur, that)).on('keydown' + BREADCRUBMSNS, 'input', proxy(that._keydown, that)).on(CLICK + BREADCRUBMSNS, 'a.k-i-arrow-60-up:first', proxy(that._rootClick, that)).on(CLICK + BREADCRUBMSNS, 'a:not(.k-i-arrow-60-up)', proxy(that._click, that));
                that.value(that.options.value);
            },
            options: {
                name: 'Breadcrumbs',
                gap: 50
            },
            events: [CHANGE],
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.wrapper.add(that.wrapper.find('input')).add(that.wrapper.find('a')).off(BREADCRUBMSNS);
            },
            _update: function (val) {
                val = (val || '').charAt(0) === '/' ? val : '/' + (val || '');
                if (val !== this.value()) {
                    this.value(val);
                    this.trigger(CHANGE);
                }
            },
            _click: function (e) {
                e.preventDefault();
                this._update(this._path($(e.target).prevAll('a:not(.k-i-arrow-60-up)').addBack()));
            },
            _rootClick: function (e) {
                e.preventDefault();
                this._update('');
            },
            _focus: function () {
                var that = this, element = that.element;
                that.overlay.hide();
                that.element.val(that.value());
                setTimeout(function () {
                    element.select();
                });
            },
            _blur: function () {
                if (this.overlay.is(':visible')) {
                    return;
                }
                var that = this, element = that.element, val = element.val().replace(/\/{2,}/g, '/');
                that.overlay.show();
                element.val('');
                that._update(val);
            },
            _keydown: function (e) {
                var that = this;
                if (e.keyCode === 13) {
                    that._blur();
                    setTimeout(function () {
                        that.overlay.find('a:first').focus();
                    });
                }
            },
            _wrapper: function () {
                var element = this.element, wrapper = element.parents('.k-breadcrumbs'), overlay;
                element[0].style.width = '';
                element.addClass('k-input');
                if (!wrapper.length) {
                    wrapper = element.wrap($('<div class="k-widget k-breadcrumbs k-textbox"/>')).parent();
                }
                overlay = wrapper.find('.k-breadcrumbs-wrap');
                if (!overlay.length) {
                    overlay = $('<div class="k-breadcrumbs-wrap"/>').appendTo(wrapper);
                }
                this.wrapper = wrapper;
                this.overlay = overlay;
            },
            refresh: function () {
                var html = '', value = this.value(), segments, segment, idx, length;
                if (value === undefined || !value.match(/^\//)) {
                    value = '/' + (value || '');
                }
                segments = value.split('/');
                for (idx = 0, length = segments.length; idx < length; idx++) {
                    segment = segments[idx];
                    if (segment) {
                        if (!html) {
                            html += '<a href="#" class="k-icon k-i-arrow-60-up" title="Go to parent folder"></a>';
                        }
                        html += '<a class="k-link" href="#">' + segments[idx] + '</a>';
                        html += '<span class="k-icon k-i-arrow-60-right" title="Go to child folder"></span>';
                    }
                }
                this.overlay.empty().append($(html));
                this._adjustSectionWidth();
            },
            _adjustSectionWidth: function () {
                var that = this, wrapper = that.wrapper, width = wrapper.width() - that.options.gap, links = that.overlay.find('a'), a;
                links.each(function (index) {
                    a = $(this);
                    if (a.parent().width() > width) {
                        if (index == links.length - 1) {
                            a.width(width);
                        } else {
                            a.prev().addBack().hide();
                        }
                    }
                });
            },
            value: function (val) {
                if (val !== undefined) {
                    this._value = val.replace(/\/{2,}/g, '/');
                    this.refresh();
                    return;
                }
                return this._value;
            },
            _path: function (trail) {
                return '/' + $.map(trail, function (b) {
                    return $(b).text();
                }).join('/');
            }
        });
        kendo.ui.plugin(FileBrowser);
        kendo.ui.plugin(Breadcrumbs);
        kendo.ui.plugin(SearchBox);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.imagebrowser', ['kendo.filebrowser'], f);
}(function () {
    var __meta__ = {
        id: 'imagebrowser',
        name: 'ImageBrowser',
        category: 'web',
        description: '',
        hidden: true,
        depends: ['filebrowser']
    };
    (function ($, undefined) {
        var kendo = window.kendo, FileBrowser = kendo.ui.FileBrowser, isPlainObject = $.isPlainObject, proxy = $.proxy, extend = $.extend, browser = kendo.support.browser, isFunction = kendo.isFunction, trimSlashesRegExp = /(^\/|\/$)/g, ERROR = 'error', NS = '.kendoImageBrowser', NAMEFIELD = 'name', SIZEFIELD = 'size', TYPEFIELD = 'type', DEFAULTSORTORDER = {
                field: TYPEFIELD,
                dir: 'asc'
            }, EMPTYTILE = kendo.template('<li class="k-tile-empty"><strong>${text}</strong></li>');
        extend(true, kendo.data, {
            schemas: {
                'imagebrowser': {
                    data: function (data) {
                        return data.items || data || [];
                    },
                    model: {
                        id: 'name',
                        fields: {
                            name: 'name',
                            size: 'size',
                            type: 'type'
                        }
                    }
                }
            }
        });
        extend(true, kendo.data, {
            transports: {
                'imagebrowser': kendo.data.RemoteTransport.extend({
                    init: function (options) {
                        kendo.data.RemoteTransport.fn.init.call(this, $.extend(true, {}, this.options, options));
                    },
                    _call: function (type, options) {
                        options.data = $.extend({}, options.data, { path: this.options.path() });
                        if (isFunction(this.options[type])) {
                            this.options[type].call(this, options);
                        } else {
                            kendo.data.RemoteTransport.fn[type].call(this, options);
                        }
                    },
                    read: function (options) {
                        this._call('read', options);
                    },
                    create: function (options) {
                        this._call('create', options);
                    },
                    destroy: function (options) {
                        this._call('destroy', options);
                    },
                    update: function () {
                    },
                    options: {
                        read: { type: 'POST' },
                        update: { type: 'POST' },
                        create: { type: 'POST' },
                        destroy: { type: 'POST' }
                    }
                })
            }
        });
        var offsetTop;
        if (browser.msie && browser.version < 8) {
            offsetTop = function (element) {
                return element.offsetTop;
            };
        } else {
            offsetTop = function (element) {
                return element.offsetTop - $(element).height();
            };
        }
        function concatPaths(path, name) {
            if (path === undefined || !path.match(/\/$/)) {
                path = (path || '') + '/';
            }
            return path + name;
        }
        function sizeFormatter(value) {
            if (!value) {
                return '';
            }
            var suffix = ' bytes';
            if (value >= 1073741824) {
                suffix = ' GB';
                value /= 1073741824;
            } else if (value >= 1048576) {
                suffix = ' MB';
                value /= 1048576;
            } else if (value >= 1024) {
                suffix = ' KB';
                value /= 1024;
            }
            return Math.round(value * 100) / 100 + suffix;
        }
        var ImageBrowser = FileBrowser.extend({
            init: function (element, options) {
                var that = this;
                options = options || {};
                FileBrowser.fn.init.call(that, element, options);
                that.element.addClass('k-imagebrowser');
            },
            options: {
                name: 'ImageBrowser',
                fileTypes: '*.png,*.gif,*.jpg,*.jpeg'
            },
            value: function () {
                var that = this, selected = that._selectedItem(), path, imageUrl = that.options.transport.imageUrl;
                if (selected && selected.get(TYPEFIELD) === 'f') {
                    path = concatPaths(that.path(), selected.get(NAMEFIELD)).replace(trimSlashesRegExp, '');
                    if (imageUrl) {
                        path = isFunction(imageUrl) ? imageUrl(path) : kendo.format(imageUrl, encodeURIComponent(path));
                    }
                    return path;
                }
            },
            _fileUpload: function (e) {
                var that = this, options = that.options, fileTypes = options.fileTypes, filterRegExp = new RegExp(('(' + fileTypes.split(',').join(')|(') + ')').replace(/\*\./g, '.*.'), 'i'), fileName = e.files[0].name, fileSize = e.files[0].size, fileNameField = NAMEFIELD, sizeField = SIZEFIELD, file;
                if (filterRegExp.test(fileName)) {
                    e.data = { path: that.path() };
                    file = that._createFile(fileName, fileSize);
                    if (!file) {
                        e.preventDefault();
                    } else {
                        file._uploading = true;
                        that.upload.one('error', function () {
                            file = undefined;
                        });
                        that.upload.one('success', function (e) {
                            if (file) {
                                delete file._uploading;
                                var model = that._insertFileToList(file);
                                if (model._override) {
                                    model.set(fileNameField, e.response[that._getFieldName(fileNameField)]);
                                    model.set(sizeField, e.response[that._getFieldName(sizeField)]);
                                    that.listView.dataSource.pushUpdate(model);
                                }
                                that._tiles = that.listView.items().filter('[' + kendo.attr('type') + '=f]');
                                that._scroll();
                            }
                        });
                    }
                } else {
                    e.preventDefault();
                    that._showMessage(kendo.format(options.messages.invalidFileType, fileName, fileTypes));
                }
            },
            _content: function () {
                var that = this;
                that.list = $('<ul class="k-reset k-floats k-tiles" />').appendTo(that.element).on('scroll' + NS, proxy(that._scroll, that)).on('dblclick' + NS, 'li', proxy(that._dblClick, that));
                that.listView = new kendo.ui.ListView(that.list, {
                    dataSource: that.dataSource,
                    template: that._itemTmpl(),
                    editTemplate: that._editTmpl(),
                    selectable: true,
                    autoBind: false,
                    dataBinding: function (e) {
                        that.toolbar.find('.k-i-close').parent().addClass('k-state-disabled');
                        if (e.action === 'remove' || e.action === 'sync') {
                            e.preventDefault();
                            kendo.ui.progress(that.listView.element, false);
                        }
                    },
                    dataBound: function () {
                        if (that.dataSource.view().length) {
                            that._tiles = this.items().filter('[' + kendo.attr('type') + '=f]');
                            that._scroll();
                        } else {
                            this.wrapper.append(EMPTYTILE({ text: that.options.messages.emptyFolder }));
                        }
                    },
                    change: proxy(that._listViewChange, that)
                });
            },
            _dataSource: function () {
                var that = this, options = that.options, transport = options.transport, typeSortOrder = extend({}, DEFAULTSORTORDER), nameSortOrder = {
                        field: NAMEFIELD,
                        dir: 'asc'
                    }, schema, dataSource = {
                        type: transport.type || 'imagebrowser',
                        sort: [
                            typeSortOrder,
                            nameSortOrder
                        ]
                    };
                if (isPlainObject(transport)) {
                    transport.path = proxy(that.path, that);
                    dataSource.transport = transport;
                }
                if (isPlainObject(options.schema)) {
                    dataSource.schema = options.schema;
                } else if (transport.type && isPlainObject(kendo.data.schemas[transport.type])) {
                    schema = kendo.data.schemas[transport.type];
                }
                if (that.dataSource && that._errorHandler) {
                    that.dataSource.unbind(ERROR, that._errorHandler);
                } else {
                    that._errorHandler = proxy(that._error, that);
                }
                that.dataSource = kendo.data.DataSource.create(dataSource).bind(ERROR, that._errorHandler);
            },
            _loadImage: function (li) {
                var that = this, element = $(li), dataItem = that.dataSource.getByUid(element.attr(kendo.attr('uid'))), name = dataItem.get(NAMEFIELD), thumbnailUrl = that.options.transport.thumbnailUrl, img = $('<img />', { alt: name }), urlJoin = '?';
                if (dataItem._uploading) {
                    return;
                }
                img.hide().on('load' + NS, function () {
                    $(this).prev().remove().end().addClass('k-image').fadeIn();
                });
                element.find('.k-i-loading').after(img);
                if (isFunction(thumbnailUrl)) {
                    thumbnailUrl = thumbnailUrl(that.path(), encodeURIComponent(name));
                } else {
                    if (thumbnailUrl.indexOf('?') >= 0) {
                        urlJoin = '&';
                    }
                    thumbnailUrl = thumbnailUrl + urlJoin + 'path=' + encodeURIComponent(that.path() + name);
                    if (dataItem._override) {
                        thumbnailUrl += '&_=' + new Date().getTime();
                        delete dataItem._override;
                    }
                }
                img.attr('src', thumbnailUrl);
                li.loaded = true;
            },
            _scroll: function () {
                var that = this;
                if (that.options.transport && that.options.transport.thumbnailUrl) {
                    clearTimeout(that._timeout);
                    that._timeout = setTimeout(function () {
                        var height = kendo._outerHeight(that.list), viewTop = that.list.scrollTop(), viewBottom = viewTop + height;
                        that._tiles.each(function () {
                            var top = offsetTop(this), bottom = top + this.offsetHeight;
                            if (top >= viewTop && top < viewBottom || bottom >= viewTop && bottom < viewBottom) {
                                that._loadImage(this);
                            }
                            if (top > viewBottom) {
                                return false;
                            }
                        });
                        that._tiles = that._tiles.filter(function () {
                            return !this.loaded;
                        });
                    }, 250);
                }
            },
            _itemTmpl: function () {
                var that = this, html = '<li class="k-tile" ' + kendo.attr('uid') + '="#=uid#" ';
                html += kendo.attr('type') + '="${' + TYPEFIELD + '}">';
                html += '#if(' + TYPEFIELD + ' == "d") { #';
                html += '<div class="k-thumb"><span class="k-icon k-i-folder"></span></div>';
                html += '#}else{#';
                if (that.options.transport && that.options.transport.thumbnailUrl) {
                    html += '<div class="k-thumb"><span class="k-icon k-i-loading"></span></div>';
                } else {
                    html += '<div class="k-thumb"><span class="k-icon k-i-file"></span></div>';
                }
                html += '#}#';
                html += '<strong>${' + NAMEFIELD + '}</strong>';
                html += '#if(' + TYPEFIELD + ' == "f") { # <span class="k-filesize">${this.sizeFormatter(' + SIZEFIELD + ')}</span> #}#';
                html += '</li>';
                return proxy(kendo.template(html), { sizeFormatter: sizeFormatter });
            }
        });
        kendo.ui.plugin(ImageBrowser);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/undoredostack', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        var UndoRedoStack = kendo.Observable.extend({
            init: function (options) {
                kendo.Observable.fn.init.call(this, options);
                this.clear();
            },
            events: [
                'undo',
                'redo'
            ],
            push: function (command) {
                this.stack = this.stack.slice(0, this.currentCommandIndex + 1);
                this.currentCommandIndex = this.stack.push(command) - 1;
            },
            undo: function () {
                if (this.canUndo()) {
                    var command = this.stack[this.currentCommandIndex--];
                    command.undo();
                    this.trigger('undo', { command: command });
                }
            },
            redo: function () {
                if (this.canRedo()) {
                    var command = this.stack[++this.currentCommandIndex];
                    command.redo();
                    this.trigger('redo', { command: command });
                }
            },
            clear: function () {
                this.stack = [];
                this.currentCommandIndex = -1;
            },
            canUndo: function () {
                return this.currentCommandIndex >= 0;
            },
            canRedo: function () {
                return this.currentCommandIndex != this.stack.length - 1;
            }
        });
        kendo.deepExtend(kendo, { util: { UndoRedoStack: UndoRedoStack } });
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/main', [
        'util/undoredostack',
        'kendo.combobox',
        'kendo.dropdownlist',
        'kendo.window',
        'kendo.colorpicker'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, Class = kendo.Class, Widget = kendo.ui.Widget, os = kendo.support.mobileOS, browser = kendo.support.browser, extend = $.extend, proxy = $.proxy, deepExtend = kendo.deepExtend, keys = kendo.keys;
        var SELECT = 'select';
        var SELECT_OVERLAY_SELECTOR = 'select.k-select-overlay';
        var PLACEHOLDER_CLASS = 'k-placeholder';
        var PLACEHOLDER_TAG_ID = 'placeholder';
        var REFRESH_INTERVAL = 200;
        var ToolTemplate = Class.extend({
            init: function (options) {
                this.options = options;
            },
            getHtml: function () {
                var options = this.options;
                return kendo.template(options.template, { useWithBlock: false })(options);
            }
        });
        var EditorUtils = {
            editorWrapperTemplate: '<table cellspacing="4" cellpadding="0" class="k-widget k-editor k-header" role="presentation"><tbody>' + '<tr role="presentation"><td class="k-editor-toolbar-wrap" role="presentation"><ul class="k-editor-toolbar" role="toolbar" /></td></tr>' + '<tr><td class="k-editable-area" /></tr>' + '</tbody></table>',
            buttonTemplate: '# var iconCssClass= "k-icon k-i-" + kendo.toHyphens(data.cssClass.replace("k-", ""));#' + '<a tabindex="0" role="button" class="k-tool"' + '#= data.popup ? " data-popup" : "" #' + ' unselectable="on" title="#= data.title #"><span unselectable="on" class="k-tool-icon #= iconCssClass #"></span><span class="k-tool-text">#= data.title #</span></a>',
            colorPickerTemplate: '<div class="k-colorpicker k-icon k-i-#= data.cssClass.replace("k-", "") #" />',
            comboBoxTemplate: '<select title="#= data.title #" class="#= data.cssClass #" />',
            dropDownListTemplate: '<span class="k-editor-dropdown"><select title="#= data.title #" class="#= data.cssClass #" /></span>',
            separatorTemplate: '<span class="k-separator" />',
            overflowAnchorTemplate: '<a tabindex="0" role="button" class="k-tool k-overflow-anchor" data-popup' + ' unselectable="on" title="#= data.title #" aria-haspopup="true" aria-expanded="false">' + '<span unselectable="on" class="k-icon k-i-more-vertical"></span><span class="k-tool-text">#= data.title #</span></a>',
            formatByName: function (name, format) {
                for (var i = 0; i < format.length; i++) {
                    if ($.inArray(name, format[i].tags) >= 0) {
                        return format[i];
                    }
                }
            },
            getToolCssClass: function (name) {
                var toolCssClassNames = {
                    superscript: 'sup-script',
                    subscript: 'sub-script',
                    justifyLeft: 'align-left',
                    justifyCenter: 'align-center',
                    justifyRight: 'align-right',
                    justifyFull: 'align-justify',
                    insertUnorderedList: 'list-unordered',
                    insertOrderedList: 'list-ordered',
                    'import': 'login',
                    indent: 'indent-increase',
                    outdent: 'indent-decrease',
                    createLink: 'link-horizontal',
                    unlink: 'unlink-horizontal',
                    insertImage: 'image',
                    insertFile: 'file-add',
                    viewHtml: 'html',
                    foreColor: 'foreground-color',
                    backColor: 'paint',
                    createTable: 'table-insert',
                    addColumnLeft: 'table-column-insert-left',
                    addColumnRight: 'table-column-insert-right',
                    addRowAbove: 'table-row-insert-above',
                    addRowBelow: 'table-row-insert-below',
                    deleteRow: 'table-row-delete',
                    deleteColumn: 'table-column-delete',
                    tableWizard: 'table-properties',
                    tableWizardInsert: 'table-wizard',
                    cleanFormatting: 'clear-css'
                };
                var cssClass = toolCssClassNames[name];
                if (cssClass) {
                    return cssClass;
                }
                return name;
            },
            registerTool: function (toolName, tool) {
                var toolOptions = tool.options;
                if (toolOptions && toolOptions.template) {
                    toolOptions.template.options.cssClass = 'k-' + EditorUtils.getToolCssClass(toolName);
                }
                if (!tool.name) {
                    tool.options.name = toolName;
                    tool.name = toolName.toLowerCase();
                }
                Editor.defaultTools[toolName] = tool;
            },
            registerFormat: function (formatName, format) {
                Editor.fn.options.formats[formatName] = format;
            },
            cacheComments: function (content, comments) {
                for (var index in comments) {
                    content = content.replace(comments[index], '{' + index + '}');
                }
                return content;
            },
            retrieveComments: function (content, comments) {
                for (var index in comments) {
                    content = content.replace('{' + index + '}', comments[index]);
                }
                return content;
            }
        };
        var messages = {
            bold: 'Bold',
            italic: 'Italic',
            underline: 'Underline',
            strikethrough: 'Strikethrough',
            superscript: 'Superscript',
            subscript: 'Subscript',
            justifyCenter: 'Center text',
            justifyLeft: 'Align text left',
            justifyRight: 'Align text right',
            justifyFull: 'Justify',
            insertUnorderedList: 'Insert unordered list',
            insertOrderedList: 'Insert ordered list',
            indent: 'Indent',
            outdent: 'Outdent',
            createLink: 'Insert hyperlink',
            unlink: 'Remove hyperlink',
            insertImage: 'Insert image',
            insertFile: 'Insert file',
            insertHtml: 'Insert HTML',
            viewHtml: 'View HTML',
            fontName: 'Select font family',
            fontNameInherit: '(inherited font)',
            fontSize: 'Select font size',
            fontSizeInherit: '(inherited size)',
            formatBlock: 'Format',
            formatting: 'Format',
            foreColor: 'Color',
            backColor: 'Background color',
            style: 'Styles',
            emptyFolder: 'Empty Folder',
            editAreaTitle: 'Editable area. Press F10 for toolbar.',
            uploadFile: 'Upload',
            overflowAnchor: 'More tools',
            orderBy: 'Arrange by:',
            orderBySize: 'Size',
            orderByName: 'Name',
            invalidFileType: 'The selected file "{0}" is not valid. Supported file types are {1}.',
            deleteFile: 'Are you sure you want to delete "{0}"?',
            overwriteFile: 'A file with name "{0}" already exists in the current directory. Do you want to overwrite it?',
            directoryNotFound: 'A directory with this name was not found.',
            imageWebAddress: 'Web address',
            imageAltText: 'Alternate text',
            imageWidth: 'Width (px)',
            imageHeight: 'Height (px)',
            fileWebAddress: 'Web address',
            fileTitle: 'Title',
            fileText: 'Text',
            linkWebAddress: 'Web address',
            linkText: 'Text',
            linkToolTip: 'ToolTip',
            linkOpenInNewWindow: 'Open link in new window',
            dialogUpdate: 'Update',
            dialogInsert: 'Insert',
            dialogOk: 'Ok',
            dialogCancel: 'Cancel',
            cleanFormatting: 'Clean formatting',
            createTable: 'Create a table',
            createTableHint: 'Create a {0} x {1} table',
            addColumnLeft: 'Add column on the left',
            addColumnRight: 'Add column on the right',
            addRowAbove: 'Add row above',
            addRowBelow: 'Add row below',
            deleteRow: 'Delete row',
            deleteColumn: 'Delete column',
            tableWizard: 'Table Wizard',
            tableTab: 'Table',
            cellTab: 'Cell',
            accessibilityTab: 'Accessibility',
            caption: 'Caption',
            summary: 'Summary',
            width: 'Width',
            height: 'Height',
            units: 'Units',
            cellSpacing: 'Cell Spacing',
            cellPadding: 'Cell Padding',
            cellMargin: 'Cell Margin',
            alignment: 'Alignment',
            background: 'Background',
            cssClass: 'CSS Class',
            id: 'ID',
            border: 'Border',
            borderStyle: 'Border Style',
            collapseBorders: 'Collapse borders',
            wrapText: 'Wrap text',
            associateCellsWithHeaders: 'Associate cells with headers',
            alignLeft: 'Align Left',
            alignCenter: 'Align Center',
            alignRight: 'Align Right',
            alignLeftTop: 'Align Left Top',
            alignCenterTop: 'Align Center Top',
            alignRightTop: 'Align Right Top',
            alignLeftMiddle: 'Align Left Middle',
            alignCenterMiddle: 'Align Center Middle',
            alignRightMiddle: 'Align Right Middle',
            alignLeftBottom: 'Align Left Bottom',
            alignCenterBottom: 'Align Center Bottom',
            alignRightBottom: 'Align Right Bottom',
            alignRemove: 'Remove Alignment',
            columns: 'Columns',
            rows: 'Rows',
            selectAllCells: 'Select All Cells',
            exportAs: 'Export As',
            'import': 'Import'
        };
        var supportedBrowser = !os || os.ios && os.flatVersion >= 500 || !os.ios && typeof document.documentElement.contentEditable != 'undefined';
        var toolGroups = {
            basic: [
                'bold',
                'italic',
                'underline'
            ],
            alignment: [
                'justifyLeft',
                'justifyCenter',
                'justifyRight'
            ],
            lists: [
                'insertUnorderedList',
                'insertOrderedList'
            ],
            indenting: [
                'indent',
                'outdent'
            ],
            links: [
                'createLink',
                'unlink'
            ],
            tables: [
                'tableWizard',
                'createTable',
                'addColumnLeft',
                'addColumnRight',
                'addRowAbove',
                'addRowBelow',
                'deleteRow',
                'deleteColumn'
            ]
        };
        var Editor = Widget.extend({
            init: function (element, options) {
                var that = this, value, editorNS = kendo.ui.editor, toolbarContainer, toolbarOptions, type, comments;
                var domElement;
                var dom = editorNS.Dom;
                if (!supportedBrowser) {
                    return;
                }
                Widget.fn.init.call(that, element, options);
                that.options = deepExtend({}, that.options, options);
                that.options.tools = that.options.tools.slice();
                element = that.element;
                domElement = element[0];
                type = dom.name(domElement);
                this._registerHandler(element.closest('form'), 'submit', proxy(that.update, that, undefined));
                toolbarOptions = extend({}, that.options);
                toolbarOptions.editor = that;
                if (type == 'textarea') {
                    that._wrapTextarea();
                    toolbarContainer = that.wrapper.find('.k-editor-toolbar');
                    if (domElement.id) {
                        toolbarContainer.attr('aria-controls', domElement.id);
                    }
                } else {
                    that.element.attr('contenteditable', true).addClass('k-widget k-editor k-editor-inline');
                    toolbarOptions.popup = true;
                    toolbarContainer = $('<ul class="k-editor-toolbar" role="toolbar" />').insertBefore(element);
                }
                that.toolbar = new editorNS.Toolbar(toolbarContainer[0], toolbarOptions);
                that.toolbar.bindTo(that);
                if (type == 'textarea') {
                    setTimeout(function () {
                        var heightStyle = that.wrapper[0].style.height;
                        var expectedHeight = parseInt(heightStyle, 10);
                        var actualHeight = that.wrapper.height();
                        if (heightStyle.indexOf('px') > 0 && !isNaN(expectedHeight) && actualHeight > expectedHeight) {
                            that.wrapper.height(expectedHeight - (actualHeight - expectedHeight));
                        }
                    });
                }
                that._resizable();
                that._initializeContentElement(that);
                that.keyboard = new editorNS.Keyboard([
                    new editorNS.BackspaceHandler(that),
                    new editorNS.TypingHandler(that),
                    new editorNS.SystemHandler(that),
                    new editorNS.SelectAllHandler(that)
                ]);
                that.clipboard = new editorNS.Clipboard(this);
                that.undoRedoStack = new kendo.util.UndoRedoStack();
                if (options && options.value) {
                    value = options.value;
                } else if (that.textarea) {
                    value = domElement.value;
                    if (that.options.encoded && $.trim(domElement.defaultValue).length) {
                        value = domElement.defaultValue;
                    }
                    comments = dom.getAllComments($('<div></div>').html(value)[0]);
                    value = EditorUtils.cacheComments(value, comments);
                    value = value.replace(/[\r\n\v\f\t ]+/gi, ' ');
                    value = EditorUtils.retrieveComments(value, comments);
                } else {
                    value = domElement.innerHTML;
                }
                that.value(value || '\uFEFF');
                this._registerHandler(document, {
                    'mousedown': function () {
                        that._endTyping();
                    },
                    'mouseup': function (e) {
                        that._mouseup(e);
                    }
                });
                that._initializeImmutables();
                that.toolbar.resize();
                kendo.notify(that);
            },
            setOptions: function (options) {
                var editor = this;
                Widget.fn.setOptions.call(editor, options);
                if (options.tools) {
                    editor.toolbar.bindTo(editor);
                }
                this._initializePlaceholder();
            },
            _togglePlaceholder: function (show) {
                var that = this, body = that.body, $body = $(body), placeholder = that.options.placeholder;
                if (!that.textarea || !placeholder) {
                    return;
                }
                $body.attr('aria-label', function () {
                    return show ? placeholder : '';
                });
                $body.toggleClass(PLACEHOLDER_CLASS, show);
            },
            _endTyping: function () {
                var keyboard = this.keyboard;
                try {
                    if (keyboard.isTypingInProgress()) {
                        keyboard.endTyping(true);
                        this.saveSelection();
                    }
                } catch (e) {
                }
            },
            _selectionChange: function () {
                this._selectionStarted = false;
                this.saveSelection();
                this.trigger('select', {});
            },
            _resizable: function () {
                var resizable = this.options.resizable;
                var isResizable = $.isPlainObject(resizable) ? resizable.content === undefined || resizable.content === true : resizable;
                if (isResizable && this.textarea) {
                    var draggableElement = $('<div class=\'k-resize-handle\'><span class=\'k-icon k-i-arrow-45-down-right\' /></div>').insertAfter(this.textarea);
                    this.wrapper.addClass('k-resizable');
                    this.wrapper.kendoResizable(extend({}, this.options.resizable, {
                        draggableElement: draggableElement,
                        start: function (e) {
                            var editor = this.editor = $(e.currentTarget).closest('.k-editor');
                            this.initialSize = editor.height();
                            editor.find('td:last').append('<div class=\'k-overlay\' />');
                        },
                        resize: function (e) {
                            var delta = e.y.initialDelta;
                            var newSize = this.initialSize + delta;
                            var min = this.options.min || 0;
                            var max = this.options.max || Infinity;
                            newSize = Math.min(max, Math.max(min, newSize));
                            this.editor.height(newSize);
                        },
                        resizeend: function () {
                            this.editor.find('.k-overlay').remove();
                            this.editor = null;
                        }
                    }));
                    if (kendo.support.mobileOS.ios) {
                        var resizableWidget = this.wrapper.getKendoResizable();
                        resizableWidget.draggable.options.ignore = SELECT_OVERLAY_SELECTOR;
                    }
                }
            },
            _initializeTableResizing: function () {
                var editor = this;
                kendo.ui.editor.TableResizing.create(editor);
                editor._showTableResizeHandlesProxy = proxy(editor._showTableResizeHandles, editor);
                editor.bind(SELECT, editor._showTableResizeHandlesProxy);
            },
            _destroyTableResizing: function () {
                var editor = this;
                var tableResizing = editor.tableResizing;
                if (tableResizing) {
                    tableResizing.destroy();
                    editor.tableResizing = null;
                }
                if (editor._showTableResizeHandlesProxy) {
                    editor.unbind(SELECT, editor._showTableResizeHandlesProxy);
                }
            },
            _showTableResizeHandles: function () {
                var editor = this;
                var tableResizing = editor.tableResizing;
                if (tableResizing) {
                    tableResizing.showResizeHandles();
                }
            },
            _initializeColumnResizing: function () {
                kendo.ui.editor.ColumnResizing.create(this);
            },
            _destroyColumnResizing: function () {
                var editor = this;
                if (editor.columnResizing) {
                    editor.columnResizing.destroy();
                    editor.columnResizing = null;
                }
            },
            _initializeRowResizing: function () {
                kendo.ui.editor.RowResizing.create(this);
            },
            _destroyRowResizing: function () {
                var editor = this;
                if (editor.rowResizing) {
                    editor.rowResizing.destroy();
                    editor.rowResizing = null;
                }
            },
            _wrapTextarea: function () {
                var that = this, textarea = that.element, w = textarea[0].style.width, h = textarea[0].style.height, template = EditorUtils.editorWrapperTemplate, editorWrap = $(template).insertBefore(textarea).width(w).height(h), editArea = editorWrap.find('.k-editable-area');
                textarea.attr('autocomplete', 'off').appendTo(editArea).addClass('k-content k-raw-content').css('display', 'none');
                that.textarea = textarea;
                that.wrapper = editorWrap;
            },
            _createContentElement: function (stylesheets) {
                var editor = this;
                var iframe, wnd, doc;
                var textarea = editor.textarea;
                var specifiedDomain = editor.options.domain;
                var domain = specifiedDomain || document.domain;
                var domainScript = '';
                var src = 'javascript:""';
                textarea.hide();
                iframe = $('<iframe />', {
                    title: editor.options.messages.editAreaTitle,
                    frameBorder: '0'
                })[0];
                $(iframe).css('display', '').addClass('k-content').attr('tabindex', textarea[0].tabIndex).insertBefore(textarea);
                if (specifiedDomain || domain != location.hostname) {
                    domainScript = '<script>document.domain="' + domain + '"</script>';
                    src = 'javascript:document.write(\'' + domainScript + '\')';
                    iframe.src = src;
                }
                wnd = iframe.contentWindow || iframe;
                doc = wnd.document || iframe.contentDocument;
                $(iframe).one('load', function () {
                    editor.toolbar.decorateFrom(doc.body);
                });
                doc.open();
                doc.write('<!DOCTYPE html><html><head>' + '<meta charset=\'utf-8\' />' + '<style>' + 'html{padding:0;margin:0;height:100%;min-height:100%;cursor:text;}' + 'body{box-sizing:border-box;font-size:12px;font-family:Verdana,Geneva,sans-serif;margin-top:-1px;padding:5px .4em 0;' + 'word-wrap: break-word;-webkit-nbsp-mode: space;-webkit-line-break: after-white-space;' + (kendo.support.isRtl(textarea) ? 'direction:rtl;' : '') + (os.ios ? 'word-break:keep-all;' : '') + '}' + 'h1{font-size:2em;margin:.67em 0}h2{font-size:1.5em}h3{font-size:1.16em}h4{font-size:1em}h5{font-size:.83em}h6{font-size:.7em}' + 'p{margin:0 0 1em;}.k-marker{display:none;}.k-paste-container,.Apple-style-span{position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden}' + 'ul,ol{padding-left:2.5em}' + 'span{-ms-high-contrast-adjust:none;}' + 'a{color:#00a}' + 'code{font-size:1.23em}' + 'telerik\\3Ascript{display: none;}' + '.k-table{width:100%;border-spacing:0;margin: 0 0 1em;}' + '.k-table td{min-width:1px;padding:.2em .3em;}' + '.k-table,.k-table td{outline:0;border: 1px dotted #ccc;}' + '.k-table p{margin:0;padding:0;}' + '.k-column-resize-handle-wrapper {position: absolute; height: 10px; width:10px; cursor: col-resize; z-index: 2;}' + '.k-column-resize-handle {width: 100%; height: 100%;}' + '.k-column-resize-handle > .k-column-resize-marker {width:2px; height:100%; margin:0 auto; background-color:#00b0ff; display:none; opacity:0.8;}' + '.k-row-resize-handle-wrapper {position: absolute; cursor: row-resize; z-index:2; width: 10px; height: 10px;}' + '.k-row-resize-handle {display: table; width: 100%; height: 100%;}' + '.k-row-resize-marker-wrapper{display: table-cell; height:100%; width:100%; margin:0; padding:0; vertical-align: middle;}' + '.k-row-resize-marker{margin: 0; padding:0; width:100%; height:2px; background-color: #00b0ff; opacity:0.8; display:none;}' + '.k-table-resize-handle-wrapper {position: absolute; background-color: #fff; border: 1px solid #000; z-index: 100; width: 5px; height: 5px;}' + '.k-table-resize-handle {width: 100%; height: 100%;}' + '.k-table-resize-handle.k-resize-east{cursor:e-resize;}' + '.k-table-resize-handle.k-resize-north{cursor:n-resize;}' + '.k-table-resize-handle.k-resize-northeast{cursor:ne-resize;}' + '.k-table-resize-handle.k-resize-northwest{cursor:nw-resize;}' + '.k-table-resize-handle.k-resize-south{cursor:s-resize;}' + '.k-table-resize-handle.k-resize-southeast{cursor:se-resize;}' + '.k-table-resize-handle.k-resize-southwest{cursor:sw-resize;}' + '.k-table-resize-handle.k-resize-west{cursor:w-resize;}' + '.k-table.k-table-resizing{opacity:0.6;}' + '.k-placeholder{color:grey}' + 'k\\:script{display:none;}' + '</style>' + domainScript + $.map(stylesheets, function (href) {
                    return '<link rel=\'stylesheet\' href=\'' + href + '\'>';
                }).join('') + '</head><body autocorrect=\'off\' contenteditable=\'true\'></body></html>');
                doc.close();
                return wnd;
            },
            _blur: function () {
                var textarea = this.textarea;
                var old = textarea ? textarea.val() : this._oldValue;
                var value = this.options.encoded ? this.encodedValue() : this.value();
                this.update();
                if (textarea) {
                    textarea.trigger('blur');
                }
                if (value != old) {
                    this.trigger('change');
                    if (textarea) {
                        textarea.trigger('change');
                    }
                }
            },
            _spellCorrect: function (editor) {
                var beforeCorrection;
                var falseTrigger = false;
                this._registerHandler(editor.body, {
                    'contextmenu': function () {
                        editor.one('select', function () {
                            beforeCorrection = null;
                        });
                        editor._spellCorrectTimeout = setTimeout(function () {
                            beforeCorrection = new kendo.ui.editor.RestorePoint(editor.getRange(), editor.body);
                            falseTrigger = false;
                        }, 10);
                    },
                    'input': function () {
                        if (!beforeCorrection) {
                            return;
                        }
                        if (kendo.support.browser.mozilla && !falseTrigger) {
                            falseTrigger = true;
                            return;
                        }
                        kendo.ui.editor._finishUpdate(editor, beforeCorrection);
                    }
                });
            },
            _registerHandler: function (element, type, handler) {
                var editor = this;
                var NS = '.kendoEditor';
                var eventNames;
                var i;
                element = $(element);
                if (!this._handlers) {
                    this._handlers = [];
                }
                if (element.length) {
                    if ($.isPlainObject(type)) {
                        for (var t in type) {
                            if (type.hasOwnProperty(t)) {
                                this._registerHandler(element, t, type[t]);
                            }
                        }
                    } else {
                        eventNames = kendo.applyEventMap(type).split(' ');
                        for (i = 0; i < eventNames.length; i++) {
                            editor._handlers.push({
                                element: element,
                                type: eventNames[i] + NS,
                                handler: handler
                            });
                            element.on(eventNames[i] + NS, handler);
                        }
                    }
                }
            },
            _deregisterHandlers: function () {
                var handlers = this._handlers;
                for (var i = 0; i < handlers.length; i++) {
                    var h = handlers[i];
                    h.element.off(h.type, h.handler);
                }
                this._handlers = [];
            },
            _initializeContentElement: function () {
                var editor = this;
                var doc;
                var blurTrigger;
                var mousedownTrigger;
                if (editor.textarea) {
                    editor.window = editor._createContentElement(editor.options.stylesheets);
                    doc = editor.document = editor.window.contentDocument || editor.window.document;
                    if (!doc.body) {
                        var body = doc.createElement('body');
                        body.setAttribute('contenteditable', 'true');
                        body.setAttribute('autocorrect', 'off');
                        doc.getElementsByTagName('html')[0].appendChild(body);
                        var interval = setInterval(function () {
                            if ($(editor.document).find('body').length > 1) {
                                $(editor.document).find('body:last').remove();
                                window.clearInterval(interval);
                            }
                        }, 10);
                    }
                    editor.body = doc.body;
                    blurTrigger = editor.window;
                    mousedownTrigger = doc;
                    this._registerHandler(doc, 'mouseup', proxy(this._mouseup, this));
                } else {
                    editor.window = window;
                    doc = editor.document = document;
                    editor.body = editor.element[0];
                    blurTrigger = editor.body;
                    mousedownTrigger = editor.body;
                    editor.toolbar.decorateFrom(editor.body);
                }
                this._registerHandler(blurTrigger, 'blur', proxy(this._blur, this));
                editor._registerHandler(mousedownTrigger, 'down', proxy(editor._mousedown, editor));
                try {
                    doc.execCommand('enableInlineTableEditing', null, false);
                } catch (e) {
                }
                if (kendo.support.touch) {
                    this._registerHandler(doc, {
                        'keydown': function () {
                            if (kendo._activeElement() != doc.body) {
                                editor.window.focus();
                            }
                        }
                    });
                }
                this._initializePlaceholder();
                this._spellCorrect(editor);
                this._registerHandler(editor.body, {
                    'keydown': function (e) {
                        var range;
                        if ((e.keyCode === keys.BACKSPACE || e.keyCode === keys.DELETE) && editor.body.getAttribute('contenteditable') !== 'true') {
                            return false;
                        }
                        if (e.keyCode === keys.F10) {
                            setTimeout(proxy(editor.toolbar.focus, editor.toolbar), 100);
                            editor.toolbar.preventPopupHide = true;
                            e.preventDefault();
                            return;
                        } else if (e.keyCode == keys.LEFT || e.keyCode == keys.RIGHT) {
                            range = editor.getRange();
                            var left = e.keyCode == keys.LEFT;
                            var container = range[left ? 'startContainer' : 'endContainer'];
                            var offset = range[left ? 'startOffset' : 'endOffset'];
                            var direction = left ? -1 : 1;
                            var next = offset + direction;
                            var nextChar = left ? next : offset;
                            if (container.nodeType == 3 && container.nodeValue[nextChar] == '\uFEFF') {
                                range.setStart(container, next);
                                range.collapse(true);
                                editor.selectRange(range);
                            }
                        }
                        var tools = editor.toolbar.tools;
                        var toolName = editor.keyboard.toolFromShortcut(tools, e);
                        var toolOptions = toolName ? tools[toolName].options : {};
                        if (toolName && !toolOptions.keyPressCommand) {
                            e.preventDefault();
                            if (!/^(undo|redo)$/.test(toolName)) {
                                editor.keyboard.endTyping(true);
                            }
                            editor.trigger('keydown', e);
                            editor.exec(toolName);
                            editor._runPostContentKeyCommands(e);
                            return false;
                        }
                        editor.keyboard.clearTimeout();
                        editor.keyboard.keydown(e);
                    },
                    'keypress': function (e) {
                        setTimeout(function () {
                            editor._runPostContentKeyCommands(e);
                            editor._showTableResizeHandles();
                        }, 0);
                    },
                    'keyup': function (e) {
                        var selectionCodes = [
                            keys.BACKSPACE,
                            keys.TAB,
                            keys.PAGEUP,
                            keys.PAGEDOWN,
                            keys.END,
                            keys.HOME,
                            keys.LEFT,
                            keys.UP,
                            keys.RIGHT,
                            keys.DOWN,
                            keys.INSERT,
                            keys.DELETE
                        ];
                        if ($.inArray(e.keyCode, selectionCodes) > -1 || e.keyCode == 65 && e.ctrlKey && !e.altKey && !e.shiftKey) {
                            window.clearTimeout(this._refreshInterval);
                            this._refreshInterval = window.setTimeout(function () {
                                editor._selectionChange();
                            }, REFRESH_INTERVAL);
                        }
                        editor.keyboard.keyup(e);
                    },
                    'click': function (e) {
                        var dom = kendo.ui.editor.Dom, range;
                        if (dom.name(e.target) === 'img') {
                            range = editor.createRange();
                            range.selectNode(e.target);
                            editor.selectRange(range);
                        }
                    },
                    'cut copy paste drop dragover': function (e) {
                        editor.clipboard['on' + e.type](e);
                    },
                    'focusin': function () {
                        if (editor.body.hasAttribute('contenteditable')) {
                            $(this).addClass('k-state-active');
                            editor.toolbar.show();
                            editor._togglePlaceholder(false);
                        }
                    },
                    'focusout': function () {
                        setTimeout(function () {
                            var active = kendo._activeElement();
                            var body = editor.body;
                            var toolbar = editor.toolbar;
                            if (toolbar.options.popup) {
                                var toolbarContainerElement = toolbar.window.element.get(0);
                                if (toolbarContainerElement && !($.contains(toolbarContainerElement, active) || toolbarContainerElement == active)) {
                                    toolbar.preventPopupHide = false;
                                }
                            }
                            if (active != body && !$.contains(body, active) && !$(active).is('.k-editortoolbar-dragHandle') && !toolbar.focused()) {
                                $(body).removeClass('k-state-active');
                                toolbar.hide();
                            }
                            editor._togglePlaceholder(!editor.value().trim());
                        }, 10);
                    }
                });
                editor._initializeColumnResizing();
                editor._initializeRowResizing();
                editor._initializeTableResizing();
            },
            _initializePlaceholder: function () {
                var that = this, placeholder = that.options.placeholder, style, $head;
                if (!that.textarea || !placeholder) {
                    return;
                }
                style = '<style id=\'' + PLACEHOLDER_TAG_ID + '\'>.' + PLACEHOLDER_CLASS + ':before { content: \'' + placeholder + '\'; }' + '</style>';
                $head = $(that.document.head);
                $head.find('#' + PLACEHOLDER_TAG_ID).remove();
                $head.append(style);
                that._togglePlaceholder(!that.value().trim());
            },
            _initializeImmutables: function () {
                var that = this, editorNS = kendo.ui.editor;
                if (that.options.immutables) {
                    that.immutables = new editorNS.Immutables(that);
                }
            },
            _mousedown: function (e) {
                var editor = this;
                editor._selectionStarted = true;
                if ($(editor.body).parents('.k-window').length) {
                    e.stopPropagation();
                }
                if (browser.gecko) {
                    return;
                }
                var target = $(e.target).closest('a[href]');
                if ((e.which == 2 || e.which == 1 && e.ctrlKey) && target && target.is('a[href]')) {
                    window.open(target.attr('href'), '_new');
                }
                if (browser.msie && e.target.tagName.toLowerCase() === 'html') {
                    setTimeout(function () {
                        editor.body.focus();
                    }, 0);
                }
            },
            _mouseup: function (e) {
                var that = this;
                if (kendo.support.mobileOS.ios && e && $(e.target).is(SELECT_OVERLAY_SELECTOR)) {
                    return;
                }
                if (that._selectionStarted) {
                    setTimeout(function () {
                        that._selectionChange();
                    }, 1);
                }
            },
            _runPostContentKeyCommands: function (e) {
                var range = this.getRange();
                var tools = this.keyboard.toolsFromShortcut(this.toolbar.tools, e);
                for (var i = 0; i < tools.length; i++) {
                    var tool = tools[i];
                    var o = tool.options;
                    if (!o.keyPressCommand) {
                        continue;
                    }
                    var cmd = new o.command({ range: range });
                    if (cmd.changesContent()) {
                        this.keyboard.endTyping(true);
                        this.exec(tool.name);
                    }
                }
            },
            refresh: function () {
                var that = this;
                if (that.textarea) {
                    that._destroyResizings();
                    var value = that.value();
                    that.textarea.val(value);
                    that.wrapper.find('iframe').remove();
                    that._initializeContentElement(that);
                    that.value(value);
                }
            },
            events: [
                'select',
                'change',
                'execute',
                'error',
                'paste',
                'keydown',
                'keyup'
            ],
            options: {
                name: 'Editor',
                messages: messages,
                placeholder: '',
                formats: {},
                encoded: true,
                domain: null,
                resizable: false,
                deserialization: { custom: null },
                serialization: {
                    entities: true,
                    semantic: true,
                    scripts: false
                },
                pasteCleanup: {
                    all: false,
                    css: false,
                    custom: null,
                    keepNewLines: false,
                    msAllFormatting: false,
                    msConvertLists: true,
                    msTags: true,
                    none: false,
                    span: false
                },
                stylesheets: [],
                dialogOptions: {
                    modal: true,
                    resizable: false,
                    draggable: true,
                    animation: false
                },
                imageBrowser: null,
                fileBrowser: null,
                fontName: [
                    {
                        text: 'Arial',
                        value: 'Arial, Helvetica, sans-serif'
                    },
                    {
                        text: 'Courier New',
                        value: '"Courier New", Courier, monospace'
                    },
                    {
                        text: 'Georgia',
                        value: 'Georgia, serif'
                    },
                    {
                        text: 'Impact',
                        value: 'Impact, Charcoal, sans-serif'
                    },
                    {
                        text: 'Lucida Console',
                        value: '"Lucida Console", Monaco, monospace'
                    },
                    {
                        text: 'Tahoma',
                        value: 'Tahoma, Geneva, sans-serif'
                    },
                    {
                        text: 'Times New Roman',
                        value: '"Times New Roman", Times, serif'
                    },
                    {
                        text: 'Trebuchet MS',
                        value: '"Trebuchet MS", Helvetica, sans-serif'
                    },
                    {
                        text: 'Verdana',
                        value: 'Verdana, Geneva, sans-serif'
                    }
                ],
                fontSize: [
                    {
                        text: '1 (8pt)',
                        value: 'xx-small'
                    },
                    {
                        text: '2 (10pt)',
                        value: 'x-small'
                    },
                    {
                        text: '3 (12pt)',
                        value: 'small'
                    },
                    {
                        text: '4 (14pt)',
                        value: 'medium'
                    },
                    {
                        text: '5 (18pt)',
                        value: 'large'
                    },
                    {
                        text: '6 (24pt)',
                        value: 'x-large'
                    },
                    {
                        text: '7 (36pt)',
                        value: 'xx-large'
                    }
                ],
                formatBlock: [
                    {
                        text: 'Paragraph',
                        value: 'p'
                    },
                    {
                        text: 'Quotation',
                        value: 'blockquote'
                    },
                    {
                        text: 'Heading 1',
                        value: 'h1'
                    },
                    {
                        text: 'Heading 2',
                        value: 'h2'
                    },
                    {
                        text: 'Heading 3',
                        value: 'h3'
                    },
                    {
                        text: 'Heading 4',
                        value: 'h4'
                    },
                    {
                        text: 'Heading 5',
                        value: 'h5'
                    },
                    {
                        text: 'Heading 6',
                        value: 'h6'
                    }
                ],
                tools: [].concat.call(['formatting'], toolGroups.basic, toolGroups.alignment, toolGroups.lists, toolGroups.indenting, toolGroups.links, ['insertImage'], toolGroups.tables)
            },
            destroy: function () {
                var editor = this;
                Widget.fn.destroy.call(this);
                this._endTyping(true);
                this._deregisterHandlers();
                clearTimeout(this._spellCorrectTimeout);
                this._focusOutside();
                this.toolbar.destroy();
                editor._destroyUploadWidget();
                editor._destroyResizings();
                kendo.destroy(this.wrapper);
            },
            _destroyResizings: function () {
                var editor = this;
                editor._destroyTableResizing();
                kendo.ui.editor.TableResizing.dispose(editor);
                editor._destroyRowResizing();
                kendo.ui.editor.RowResizing.dispose(editor);
                editor._destroyColumnResizing();
                kendo.ui.editor.ColumnResizing.dispose(editor);
            },
            _focusOutside: function () {
                if (kendo.support.browser.msie && this.textarea) {
                    var tempInput = $('<input style=\'position:fixed;left:1px;top:1px;width:1px;height:1px;font-size:0;border:0;opacity:0\' />').appendTo(document.body).focus();
                    tempInput.blur().remove();
                }
            },
            _destroyUploadWidget: function () {
                var editor = this;
                if (editor._uploadWidget) {
                    editor._uploadWidget.destroy();
                    editor._uploadWidget = null;
                }
            },
            state: function (toolName) {
                var tool = Editor.defaultTools[toolName];
                var finder = tool && (tool.options.finder || tool.finder);
                var RangeUtils = kendo.ui.editor.RangeUtils;
                var range, textNodes;
                if (finder) {
                    range = this.getRange();
                    textNodes = RangeUtils.textNodes(range);
                    if (!textNodes.length && range.collapsed) {
                        textNodes = [range.startContainer];
                    }
                    return finder.getFormat ? finder.getFormat(textNodes) : finder.isFormatted(textNodes);
                }
                return false;
            },
            value: function (html) {
                var body = this.body, editorNS = kendo.ui.editor, options = this.options, currentHtml = editorNS.Serializer.domToXhtml(body, options.serialization);
                if (html === undefined) {
                    return currentHtml;
                }
                if (html == currentHtml) {
                    return;
                }
                editorNS.Serializer.htmlToDom(html, body, options.deserialization);
                this.selectionRestorePoint = null;
                this.update();
                this.toolbar.refreshTools();
            },
            saveSelection: function (range) {
                range = range || this.getRange();
                var container = range.commonAncestorContainer, body = this.body;
                if (container == body || $.contains(body, container)) {
                    this.selectionRestorePoint = new kendo.ui.editor.RestorePoint(range, body);
                }
            },
            _focusBody: function () {
                var body = this.body;
                var iframe = this.wrapper && this.wrapper.find('iframe')[0];
                var documentElement = this.document.documentElement;
                var activeElement = kendo._activeElement();
                var scrollTop;
                if (!iframe && body.scrollHeight > body.clientHeight) {
                    scrollTop = body.scrollTop;
                    body.focus();
                    body.scrollTop = scrollTop;
                } else if (activeElement != body && activeElement != iframe) {
                    scrollTop = documentElement.scrollTop;
                    body.focus();
                    documentElement.scrollTop = scrollTop;
                }
            },
            restoreSelection: function () {
                this._focusBody();
                if (this.selectionRestorePoint) {
                    this.selectRange(this.selectionRestorePoint.toRange());
                }
            },
            focus: function () {
                this.restoreSelection();
            },
            update: function (value) {
                value = value || this.options.encoded ? this.encodedValue() : this.value();
                if (this.textarea) {
                    this.textarea.val(value);
                    this._togglePlaceholder(!value.trim());
                } else {
                    this._oldValue = value;
                }
            },
            encodedValue: function () {
                return kendo.ui.editor.Dom.encode(this.value());
            },
            createRange: function (document) {
                return kendo.ui.editor.RangeUtils.createRange(document || this.document);
            },
            getSelection: function () {
                return kendo.ui.editor.SelectionUtils.selectionFromDocument(this.document);
            },
            selectRange: function (range) {
                this._focusBody();
                var selection = this.getSelection();
                selection.removeAllRanges();
                selection.addRange(range);
                this.saveSelection(range);
            },
            getRange: function () {
                var selection = this.getSelection(), range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : this.createRange(), doc = this.document;
                if (range.startContainer == doc && range.endContainer == doc && !range.startOffset && !range.endOffset) {
                    range.setStart(this.body, 0);
                    range.collapse(true);
                }
                return range;
            },
            _containsRange: function (range) {
                var dom = kendo.ui.editor.Dom;
                var body = this.body;
                return range && dom.isAncestorOrSelf(body, range.startContainer) && dom.isAncestorOrSelf(body, range.endContainer);
            },
            _deleteSavedRange: function () {
                if ('_range' in this) {
                    delete this._range;
                }
            },
            selectedHtml: function () {
                return kendo.ui.editor.Serializer.domToXhtml(this.getRange().cloneContents());
            },
            paste: function (html, options) {
                this.focus();
                var command = new kendo.ui.editor.InsertHtmlCommand($.extend({
                    range: this.getRange(),
                    html: html
                }, options));
                command.editor = this;
                command.exec();
            },
            exec: function (name, params) {
                var that = this;
                var command = null;
                var range, tool, prevented;
                if (!name) {
                    throw new Error('kendoEditor.exec(): `name` parameter cannot be empty');
                }
                if (that.body.getAttribute('contenteditable') !== 'true' && name !== 'print' && name !== 'pdf' && name !== 'exportAs') {
                    return false;
                }
                name = name.toLowerCase();
                if (!that.keyboard.isTypingInProgress()) {
                    that._focusBody();
                    that.selectRange(that._range || that.getRange());
                }
                tool = that.toolbar.toolById(name);
                if (!tool) {
                    for (var id in Editor.defaultTools) {
                        if (id.toLowerCase() == name) {
                            tool = Editor.defaultTools[id];
                            break;
                        }
                    }
                }
                if (tool) {
                    range = that.getRange();
                    if (tool.command) {
                        command = tool.command(extend({
                            range: range,
                            body: that.body,
                            immutables: !!that.immutables
                        }, params));
                    }
                    prevented = that.trigger('execute', {
                        name: name,
                        command: command
                    });
                    if (prevented) {
                        return;
                    }
                    if (/^(undo|redo)$/i.test(name)) {
                        that.undoRedoStack[name]();
                    } else if (command) {
                        that.execCommand(command);
                        if (command.async) {
                            command.change = proxy(that._selectionChange, that);
                            return;
                        }
                    }
                    that._selectionChange();
                }
            },
            execCommand: function (command) {
                if (!command.managesUndoRedo) {
                    this.undoRedoStack.push(command);
                }
                command.editor = this;
                command.exec();
            }
        });
        Editor.defaultTools = {
            undo: {
                options: {
                    key: 'Z',
                    ctrl: true
                }
            },
            redo: {
                options: {
                    key: 'Y',
                    ctrl: true
                }
            }
        };
        kendo.ui.plugin(Editor);
        var Tool = Class.extend({
            init: function (options) {
                this.options = options;
            },
            initialize: function (ui, options) {
                ui.attr({
                    unselectable: 'on',
                    title: options.title
                });
                ui.children('.k-tool-text').html(options.title);
            },
            command: function (commandArguments) {
                return new this.options.command(commandArguments);
            },
            update: $.noop
        });
        Tool.exec = function (editor, name, value) {
            editor.exec(name, { value: value });
        };
        EditorUtils.registerTool('separator', new Tool({ template: new ToolTemplate({ template: EditorUtils.separatorTemplate }) }));
        var bomFill = browser.msie && browser.version < 9 ? '\uFEFF' : '';
        var emptyElementContent = '\uFEFF';
        var emptyTableCellContent = emptyElementContent;
        if (browser.msie || browser.edge) {
            emptyTableCellContent = emptyElementContent = '&nbsp;';
        }
        extend(kendo.ui, {
            editor: {
                ToolTemplate: ToolTemplate,
                EditorUtils: EditorUtils,
                Tool: Tool,
                _bomFill: bomFill,
                emptyElementContent: emptyElementContent,
                emptyTableCellContent: emptyTableCellContent
            }
        });
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(Editor.prototype);
            Editor.prototype._drawPDF = function () {
                return kendo.drawing.drawDOM(this.body, this.options.pdf);
            };
            Editor.prototype.saveAsPDF = function () {
                var progress = new $.Deferred();
                var promise = progress.promise();
                var args = { promise: promise };
                if (this.trigger('pdfExport', args)) {
                    return;
                }
                var options = this.options.pdf;
                this._drawPDF(progress).then(function (root) {
                    return kendo.drawing.exportPDF(root, options);
                }).done(function (dataURI) {
                    kendo.saveAs({
                        dataURI: dataURI,
                        fileName: options.fileName,
                        proxyURL: options.proxyURL,
                        proxyTarget: options.proxyTarget,
                        forceProxy: options.forceProxy
                    });
                    progress.resolve();
                }).fail(function (err) {
                    progress.reject(err);
                });
                return promise;
            };
        }
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/dom', ['editor/main'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, map = $.map, extend = $.extend, browser = kendo.support.browser, STYLE = 'style', FLOAT = 'float', CSSFLOAT = 'cssFloat', STYLEFLOAT = 'styleFloat', CLASS = 'class', KMARKER = 'k-marker';
        function makeMap(items) {
            var obj = {}, i, len;
            for (i = 0, len = items.length; i < len; i++) {
                obj[items[i]] = true;
            }
            return obj;
        }
        var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed'.split(',')), nonListBlockElements = 'p,div,h1,h2,h3,h4,h5,h6,address,applet,blockquote,button,center,dd,dir,dl,dt,fieldset,form,frameset,hr,iframe,isindex,map,menu,noframes,noscript,object,pre,script,table,tbody,td,tfoot,th,thead,tr,header,article,nav,footer,section,aside,main,figure,figcaption'.split(','), blockElements = nonListBlockElements.concat([
                'ul',
                'ol',
                'li'
            ]), block = makeMap(blockElements), selfClosing = makeMap('area,base,br,col,command,embed,hr,img,input,keygen,link,menuitem,meta,param,source,track,wbr'.split(',')), inlineElements = 'span,em,a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,strike,strong,sub,sup,textarea,tt,u,var,data,time,mark,ruby'.split(','), inline = makeMap(inlineElements), fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'.split(','));
        var normalize = function (node) {
            if (node.nodeType == 1) {
                node.normalize();
            }
        };
        if (browser.msie && browser.version >= 8) {
            normalize = function (parent) {
                if (parent.nodeType == 1 && parent.firstChild) {
                    var prev = parent.firstChild, node = prev;
                    while (true) {
                        node = node.nextSibling;
                        if (!node) {
                            break;
                        }
                        if (node.nodeType == 3 && prev.nodeType == 3) {
                            node.nodeValue = prev.nodeValue + node.nodeValue;
                            Dom.remove(prev);
                        }
                        prev = node;
                    }
                }
            };
        }
        var whitespace = /^\s+$/, emptyspace = /^[\n\r\t]+$/, rgb = /rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i, bom = /\ufeff/g, whitespaceOrBom = /^(\s+|\ufeff)$/, persistedScrollTop, cssAttributes = ('color,padding-left,padding-right,padding-top,padding-bottom,' + 'background-color,background-attachment,background-image,background-position,background-repeat,' + 'border-top-style,border-top-width,border-top-color,' + 'border-bottom-style,border-bottom-width,border-bottom-color,' + 'border-left-style,border-left-width,border-left-color,' + 'border-right-style,border-right-width,border-right-color,' + 'font-family,font-size,font-style,font-variant,font-weight,line-height').split(','), htmlRe = /[<>\&]/g, entityRe = /[\u00A0-\u2666<>\&]/g, entityTable = {
                34: 'quot',
                38: 'amp',
                39: 'apos',
                60: 'lt',
                62: 'gt',
                160: 'nbsp',
                161: 'iexcl',
                162: 'cent',
                163: 'pound',
                164: 'curren',
                165: 'yen',
                166: 'brvbar',
                167: 'sect',
                168: 'uml',
                169: 'copy',
                170: 'ordf',
                171: 'laquo',
                172: 'not',
                173: 'shy',
                174: 'reg',
                175: 'macr',
                176: 'deg',
                177: 'plusmn',
                178: 'sup2',
                179: 'sup3',
                180: 'acute',
                181: 'micro',
                182: 'para',
                183: 'middot',
                184: 'cedil',
                185: 'sup1',
                186: 'ordm',
                187: 'raquo',
                188: 'frac14',
                189: 'frac12',
                190: 'frac34',
                191: 'iquest',
                192: 'Agrave',
                193: 'Aacute',
                194: 'Acirc',
                195: 'Atilde',
                196: 'Auml',
                197: 'Aring',
                198: 'AElig',
                199: 'Ccedil',
                200: 'Egrave',
                201: 'Eacute',
                202: 'Ecirc',
                203: 'Euml',
                204: 'Igrave',
                205: 'Iacute',
                206: 'Icirc',
                207: 'Iuml',
                208: 'ETH',
                209: 'Ntilde',
                210: 'Ograve',
                211: 'Oacute',
                212: 'Ocirc',
                213: 'Otilde',
                214: 'Ouml',
                215: 'times',
                216: 'Oslash',
                217: 'Ugrave',
                218: 'Uacute',
                219: 'Ucirc',
                220: 'Uuml',
                221: 'Yacute',
                222: 'THORN',
                223: 'szlig',
                224: 'agrave',
                225: 'aacute',
                226: 'acirc',
                227: 'atilde',
                228: 'auml',
                229: 'aring',
                230: 'aelig',
                231: 'ccedil',
                232: 'egrave',
                233: 'eacute',
                234: 'ecirc',
                235: 'euml',
                236: 'igrave',
                237: 'iacute',
                238: 'icirc',
                239: 'iuml',
                240: 'eth',
                241: 'ntilde',
                242: 'ograve',
                243: 'oacute',
                244: 'ocirc',
                245: 'otilde',
                246: 'ouml',
                247: 'divide',
                248: 'oslash',
                249: 'ugrave',
                250: 'uacute',
                251: 'ucirc',
                252: 'uuml',
                253: 'yacute',
                254: 'thorn',
                255: 'yuml',
                402: 'fnof',
                913: 'Alpha',
                914: 'Beta',
                915: 'Gamma',
                916: 'Delta',
                917: 'Epsilon',
                918: 'Zeta',
                919: 'Eta',
                920: 'Theta',
                921: 'Iota',
                922: 'Kappa',
                923: 'Lambda',
                924: 'Mu',
                925: 'Nu',
                926: 'Xi',
                927: 'Omicron',
                928: 'Pi',
                929: 'Rho',
                931: 'Sigma',
                932: 'Tau',
                933: 'Upsilon',
                934: 'Phi',
                935: 'Chi',
                936: 'Psi',
                937: 'Omega',
                945: 'alpha',
                946: 'beta',
                947: 'gamma',
                948: 'delta',
                949: 'epsilon',
                950: 'zeta',
                951: 'eta',
                952: 'theta',
                953: 'iota',
                954: 'kappa',
                955: 'lambda',
                956: 'mu',
                957: 'nu',
                958: 'xi',
                959: 'omicron',
                960: 'pi',
                961: 'rho',
                962: 'sigmaf',
                963: 'sigma',
                964: 'tau',
                965: 'upsilon',
                966: 'phi',
                967: 'chi',
                968: 'psi',
                969: 'omega',
                977: 'thetasym',
                978: 'upsih',
                982: 'piv',
                8226: 'bull',
                8230: 'hellip',
                8242: 'prime',
                8243: 'Prime',
                8254: 'oline',
                8260: 'frasl',
                8472: 'weierp',
                8465: 'image',
                8476: 'real',
                8482: 'trade',
                8501: 'alefsym',
                8592: 'larr',
                8593: 'uarr',
                8594: 'rarr',
                8595: 'darr',
                8596: 'harr',
                8629: 'crarr',
                8656: 'lArr',
                8657: 'uArr',
                8658: 'rArr',
                8659: 'dArr',
                8660: 'hArr',
                8704: 'forall',
                8706: 'part',
                8707: 'exist',
                8709: 'empty',
                8711: 'nabla',
                8712: 'isin',
                8713: 'notin',
                8715: 'ni',
                8719: 'prod',
                8721: 'sum',
                8722: 'minus',
                8727: 'lowast',
                8730: 'radic',
                8733: 'prop',
                8734: 'infin',
                8736: 'ang',
                8743: 'and',
                8744: 'or',
                8745: 'cap',
                8746: 'cup',
                8747: 'int',
                8756: 'there4',
                8764: 'sim',
                8773: 'cong',
                8776: 'asymp',
                8800: 'ne',
                8801: 'equiv',
                8804: 'le',
                8805: 'ge',
                8834: 'sub',
                8835: 'sup',
                8836: 'nsub',
                8838: 'sube',
                8839: 'supe',
                8853: 'oplus',
                8855: 'otimes',
                8869: 'perp',
                8901: 'sdot',
                8968: 'lceil',
                8969: 'rceil',
                8970: 'lfloor',
                8971: 'rfloor',
                9001: 'lang',
                9002: 'rang',
                9674: 'loz',
                9824: 'spades',
                9827: 'clubs',
                9829: 'hearts',
                9830: 'diams',
                338: 'OElig',
                339: 'oelig',
                352: 'Scaron',
                353: 'scaron',
                376: 'Yuml',
                710: 'circ',
                732: 'tilde',
                8194: 'ensp',
                8195: 'emsp',
                8201: 'thinsp',
                8204: 'zwnj',
                8205: 'zwj',
                8206: 'lrm',
                8207: 'rlm',
                8211: 'ndash',
                8212: 'mdash',
                8216: 'lsquo',
                8217: 'rsquo',
                8218: 'sbquo',
                8220: 'ldquo',
                8221: 'rdquo',
                8222: 'bdquo',
                8224: 'dagger',
                8225: 'Dagger',
                8240: 'permil',
                8249: 'lsaquo',
                8250: 'rsaquo',
                8364: 'euro'
            };
        var Dom = {
            block: block,
            inline: inline,
            findNodeIndex: function (node, skipText) {
                var i = 0;
                if (!node) {
                    return -1;
                }
                while (true) {
                    node = node.previousSibling;
                    if (!node) {
                        break;
                    }
                    if (!(skipText && node.nodeType == 3)) {
                        i++;
                    }
                }
                return i;
            },
            isDataNode: function (node) {
                return node && node.nodeValue !== null && node.data !== null;
            },
            isAncestorOf: function (parent, node) {
                try {
                    return !Dom.isDataNode(parent) && ($.contains(parent, Dom.isDataNode(node) ? node.parentNode : node) || node.parentNode == parent);
                } catch (e) {
                    return false;
                }
            },
            isAncestorOrSelf: function (root, node) {
                return Dom.isAncestorOf(root, node) || root == node;
            },
            findClosestAncestor: function (root, node) {
                if (Dom.isAncestorOf(root, node)) {
                    while (node && node.parentNode != root) {
                        node = node.parentNode;
                    }
                }
                return node;
            },
            getAllComments: function (rootElem) {
                var comments = [];
                var iterator = document.createNodeIterator(rootElem, NodeFilter.SHOW_COMMENT, function () {
                    return NodeFilter.FILTER_ACCEPT;
                }, false);
                var curNode = iterator.nextNode();
                while (curNode) {
                    comments.push(curNode.nodeValue);
                    curNode = iterator.nextNode();
                }
                return comments;
            },
            getNodeLength: function (node) {
                return Dom.isDataNode(node) ? node.length : node.childNodes.length;
            },
            splitDataNode: function (node, offset) {
                var newNode = node.cloneNode(false);
                var denormalizedText = '';
                var iterator = node.nextSibling;
                var temp;
                while (iterator && iterator.nodeType == 3 && iterator.nodeValue) {
                    denormalizedText += iterator.nodeValue;
                    temp = iterator;
                    iterator = iterator.nextSibling;
                    Dom.remove(temp);
                }
                node.deleteData(offset, node.length);
                newNode.deleteData(0, offset);
                newNode.nodeValue += denormalizedText;
                Dom.insertAfter(newNode, node);
            },
            attrEquals: function (node, attributes) {
                for (var key in attributes) {
                    var value = node[key];
                    if (key == FLOAT) {
                        value = node[kendo.support.cssFloat ? CSSFLOAT : STYLEFLOAT];
                    }
                    if (typeof value == 'object') {
                        if (!Dom.attrEquals(value, attributes[key])) {
                            return false;
                        }
                    } else if (value != attributes[key]) {
                        return false;
                    }
                }
                return true;
            },
            blockParentOrBody: function (node) {
                return Dom.parentOfType(node, blockElements) || node.ownerDocument.body;
            },
            blockParents: function (nodes) {
                var blocks = [], i, len;
                for (i = 0, len = nodes.length; i < len; i++) {
                    var block = Dom.parentOfType(nodes[i], Dom.blockElements);
                    if (block && $.inArray(block, blocks) < 0) {
                        blocks.push(block);
                    }
                }
                return blocks;
            },
            windowFromDocument: function (document) {
                return document.defaultView || document.parentWindow;
            },
            normalize: normalize,
            blockElements: blockElements,
            nonListBlockElements: nonListBlockElements,
            inlineElements: inlineElements,
            empty: empty,
            fillAttrs: fillAttrs,
            nodeTypes: {
                ELEMENT_NODE: 1,
                ATTRIBUTE_NODE: 2,
                TEXT_NODE: 3,
                CDATA_SECTION_NODE: 4,
                ENTITY_REFERENCE_NODE: 5,
                ENTITY_NODE: 6,
                PROCESSING_INSTRUCTION_NODE: 7,
                COMMENT_NODE: 8,
                DOCUMENT_NODE: 9,
                DOCUMENT_TYPE_NODE: 10,
                DOCUMENT_FRAGMENT_NODE: 11,
                NOTATION_NODE: 12
            },
            toHex: function (color) {
                var matches = rgb.exec(color);
                if (!matches) {
                    return color;
                }
                return '#' + map(matches.slice(1), function (x) {
                    x = parseInt(x, 10).toString(16);
                    return x.length > 1 ? x : '0' + x;
                }).join('');
            },
            encode: function (value, options) {
                var encodableChars = !options || options.entities ? entityRe : htmlRe;
                return value.replace(encodableChars, function (c) {
                    var charCode = c.charCodeAt(0);
                    var entity = entityTable[charCode];
                    return entity ? '&' + entity + ';' : c;
                });
            },
            isBom: function (node) {
                return node && node.nodeType === 3 && /^[\ufeff]+$/.test(node.nodeValue);
            },
            stripBom: function (text) {
                return (text || '').replace(bom, '');
            },
            stripBomNode: function (node) {
                if (Dom.isBom(node)) {
                    node.parentNode.removeChild(node);
                }
            },
            insignificant: function (node) {
                var attr = node.attributes;
                return node.className == 'k-marker' || Dom.is(node, 'br') && (node.className == 'k-br' || attr._moz_dirty || attr._moz_editor_bogus_node);
            },
            tableCell: function (node) {
                return Dom.is(node, 'td') || Dom.is(node, 'th');
            },
            significantNodes: function (nodes) {
                return $.grep(nodes, function (child) {
                    var name = Dom.name(child);
                    if (name == 'br') {
                        return false;
                    } else if (Dom.insignificant(child)) {
                        return false;
                    } else if (Dom.emptyTextNode(child)) {
                        return false;
                    } else if (child.nodeType == 1 && !empty[name] && Dom.emptyNode(child)) {
                        return false;
                    }
                    return true;
                });
            },
            emptyTextNode: function (node) {
                return node && node.nodeType == 3 && whitespaceOrBom.test(node.nodeValue);
            },
            emptyNode: function (node) {
                return node.nodeType == 1 && !Dom.significantNodes(node.childNodes).length;
            },
            name: function (node) {
                return node.nodeName.toLowerCase();
            },
            significantChildNodes: function (node) {
                return $.grep(node.childNodes, function (child) {
                    return child.nodeType != 3 || !Dom.isWhitespace(child);
                });
            },
            lastTextNode: function (node) {
                var result = null;
                if (node.nodeType == 3) {
                    return node;
                }
                for (var child = node.lastChild; child; child = child.previousSibling) {
                    result = Dom.lastTextNode(child);
                    if (result) {
                        return result;
                    }
                }
                return result;
            },
            is: function (node, nodeName) {
                return node && Dom.name(node) == nodeName;
            },
            isMarker: function (node) {
                return node.className == KMARKER;
            },
            isWhitespace: function (node) {
                return whitespace.test(node.nodeValue);
            },
            allWhitespaceContent: function (node) {
                var child = node.firstChild;
                while (child && Dom.isWhitespace(child)) {
                    child = child.nextSibling;
                }
                return !child;
            },
            isEmptyspace: function (node) {
                return emptyspace.test(node.nodeValue);
            },
            htmlIndentSpace: function (node) {
                if (!(Dom.isDataNode(node) && Dom.isWhitespace(node))) {
                    return false;
                }
                if (emptyspace.test(node.nodeValue)) {
                    return true;
                }
                var sibling = function (el, direction) {
                    while (el[direction]) {
                        el = el[direction];
                        if (Dom.significantNodes([el]).length > 0) {
                            return el;
                        }
                    }
                };
                var parent = node.parentNode;
                var prev = sibling(node, 'previousSibling');
                var next = sibling(node, 'nextSibling');
                if (bom.test(node.nodeValue)) {
                    return !!(prev || next);
                }
                if ($(parent).is('tr,tbody,thead,tfoot,table,ol,ul')) {
                    return true;
                }
                if (Dom.isBlock(parent) || Dom.is(parent, 'body')) {
                    var isPrevBlock = prev && Dom.isBlock(prev);
                    var isNextBlock = next && Dom.isBlock(next);
                    if (!next && isPrevBlock || !prev && isNextBlock || isPrevBlock && isNextBlock) {
                        return true;
                    }
                }
                return false;
            },
            isBlock: function (node) {
                return block[Dom.name(node)];
            },
            isSelfClosing: function (node) {
                return selfClosing[Dom.name(node)];
            },
            isEmpty: function (node) {
                return empty[Dom.name(node)];
            },
            isInline: function (node) {
                return inline[Dom.name(node)];
            },
            isBr: function (node) {
                return Dom.name(node) == 'br';
            },
            list: function (node) {
                var name = node ? Dom.name(node) : '';
                return name == 'ul' || name == 'ol' || name == 'dl';
            },
            scrollContainer: function (doc) {
                var wnd = Dom.windowFromDocument(doc), scrollContainer = (wnd.contentWindow || wnd).document || wnd.ownerDocument || wnd;
                if (scrollContainer.compatMode == 'BackCompat') {
                    scrollContainer = scrollContainer.body;
                } else {
                    scrollContainer = scrollContainer.scrollingElement || scrollContainer.documentElement;
                }
                return scrollContainer;
            },
            scrollTo: function (node, toStart) {
                var doc = node.ownerDocument;
                var wnd = Dom.windowFromDocument(doc);
                var windowHeight = wnd.innerHeight;
                var scrollContainer = Dom.scrollContainer(doc);
                var element, elementTop, elementHeight, marker;
                if (Dom.isDataNode(node)) {
                    if (toStart) {
                        marker = Dom.create(doc, 'span', { 'innerHTML': '&#xfeff;' });
                        Dom.insertBefore(marker, node);
                        element = $(marker);
                    } else {
                        element = $(node.parentNode);
                    }
                } else {
                    element = $(node);
                }
                elementTop = element.offset().top;
                elementHeight = element[0].offsetHeight;
                if (toStart || !elementHeight) {
                    elementHeight = parseInt(element.css('line-height'), 10) || Math.ceil(1.2 * parseInt(element.css('font-size'), 10)) || 15;
                }
                if (marker) {
                    Dom.remove(marker);
                }
                if (elementHeight + elementTop > scrollContainer.scrollTop + windowHeight) {
                    scrollContainer.scrollTop = elementHeight + elementTop - windowHeight;
                }
            },
            persistScrollTop: function (doc) {
                persistedScrollTop = Dom.scrollContainer(doc).scrollTop;
            },
            offset: function (target, offsetParent) {
                var result = {
                    top: target.offsetTop,
                    left: target.offsetLeft
                };
                var parent = target.offsetParent;
                while (parent && (!offsetParent || Dom.isAncestorOf(offsetParent, parent))) {
                    result.top += parent.offsetTop;
                    result.left += parent.offsetLeft;
                    parent = parent.offsetParent;
                }
                return result;
            },
            restoreScrollTop: function (doc) {
                if (typeof persistedScrollTop == 'number') {
                    Dom.scrollContainer(doc).scrollTop = persistedScrollTop;
                    persistedScrollTop = undefined;
                }
            },
            insertAt: function (parent, newElement, position) {
                parent.insertBefore(newElement, parent.childNodes[position] || null);
            },
            insertBefore: function (newElement, referenceElement) {
                if (referenceElement.parentNode) {
                    return referenceElement.parentNode.insertBefore(newElement, referenceElement);
                } else {
                    return referenceElement;
                }
            },
            insertAfter: function (newElement, referenceElement) {
                return referenceElement.parentNode.insertBefore(newElement, referenceElement.nextSibling);
            },
            remove: function (node) {
                if (node.parentNode) {
                    node.parentNode.removeChild(node);
                }
            },
            removeChildren: function (node) {
                while (node.firstChild) {
                    node.removeChild(node.firstChild);
                }
            },
            removeTextSiblings: function (node) {
                var parentNode = node.parentNode;
                while (node.nextSibling && node.nextSibling.nodeType == 3) {
                    parentNode.removeChild(node.nextSibling);
                }
                while (node.previousSibling && node.previousSibling.nodeType == 3) {
                    parentNode.removeChild(node.previousSibling);
                }
            },
            trim: function (parent) {
                for (var i = parent.childNodes.length - 1; i >= 0; i--) {
                    var node = parent.childNodes[i];
                    if (Dom.isDataNode(node)) {
                        if (!Dom.stripBom(node.nodeValue).length) {
                            Dom.remove(node);
                        }
                    } else if (node.className != KMARKER) {
                        Dom.trim(node);
                        if (!Dom.isEmpty(node) && node.childNodes.length === 0 || Dom.isBlock(node) && Dom.allWhitespaceContent(node)) {
                            Dom.remove(node);
                        }
                    }
                }
                return parent;
            },
            closest: function (node, tag) {
                while (node && Dom.name(node) != tag) {
                    node = node.parentNode;
                }
                return node;
            },
            closestBy: function (node, condition, rootCondition) {
                while (node && !condition(node)) {
                    if (rootCondition && rootCondition(node)) {
                        return null;
                    }
                    node = node.parentNode;
                }
                return node;
            },
            sibling: function (node, direction) {
                do {
                    node = node[direction];
                } while (node && node.nodeType != 1);
                return node;
            },
            next: function (node) {
                return Dom.sibling(node, 'nextSibling');
            },
            prev: function (node) {
                return Dom.sibling(node, 'previousSibling');
            },
            parentOfType: function (node, tags) {
                do {
                    node = node.parentNode;
                } while (node && !Dom.ofType(node, tags));
                return node;
            },
            ofType: function (node, tags) {
                return $.inArray(Dom.name(node), tags) >= 0;
            },
            changeTag: function (referenceElement, tagName, skipAttributes) {
                var newElement = Dom.create(referenceElement.ownerDocument, tagName), attributes = referenceElement.attributes, i, len, name, value, attribute;
                if (!skipAttributes) {
                    for (i = 0, len = attributes.length; i < len; i++) {
                        attribute = attributes[i];
                        if (attribute.specified) {
                            name = attribute.nodeName;
                            value = attribute.nodeValue;
                            if (name == CLASS) {
                                newElement.className = value;
                            } else if (name == STYLE) {
                                newElement.style.cssText = referenceElement.style.cssText;
                            } else {
                                newElement.setAttribute(name, value);
                            }
                        }
                    }
                }
                while (referenceElement.firstChild) {
                    newElement.appendChild(referenceElement.firstChild);
                }
                Dom.insertBefore(newElement, referenceElement);
                Dom.remove(referenceElement);
                return newElement;
            },
            editableParent: function (node) {
                while (node && (node.nodeType == 3 || node.contentEditable !== 'true')) {
                    node = node.parentNode;
                }
                return node;
            },
            wrap: function (node, wrapper) {
                Dom.insertBefore(wrapper, node);
                wrapper.appendChild(node);
                return wrapper;
            },
            unwrap: function (node) {
                var parent = node.parentNode;
                while (node.firstChild) {
                    parent.insertBefore(node.firstChild, node);
                }
                parent.removeChild(node);
            },
            wrapper: function (node) {
                var wrapper = Dom.closestBy(node, function (el) {
                    return el.parentNode && Dom.significantNodes(el.parentNode.childNodes).length > 1;
                });
                return $(wrapper).is('body,.k-editor') ? undefined : wrapper;
            },
            create: function (document, tagName, attributes) {
                return Dom.attr(document.createElement(tagName), attributes);
            },
            createEmptyNode: function (document, tagName, attributes) {
                var node = Dom.attr(document.createElement(tagName), attributes);
                node.innerHTML = '\uFEFF';
                return node;
            },
            attr: function (element, attributes) {
                attributes = extend({}, attributes);
                if (attributes && STYLE in attributes) {
                    Dom.style(element, attributes.style);
                    delete attributes.style;
                }
                for (var attr in attributes) {
                    if (attributes[attr] === null) {
                        element.removeAttribute(attr);
                        delete attributes[attr];
                    } else if (attr == 'className') {
                        element[attr] = attributes[attr];
                    }
                }
                return extend(element, attributes);
            },
            mergeAttributes: function (origin, target) {
                if (!origin.attributes.length) {
                    return;
                }
                $.each(origin.attributes, function () {
                    if (this.name !== 'contenteditable') {
                        $(target).attr(this.name, this.value);
                    }
                });
            },
            style: function (node, value) {
                $(node).css(value || {});
            },
            unstyle: function (node, value) {
                for (var key in value) {
                    if (key == FLOAT) {
                        key = kendo.support.cssFloat ? CSSFLOAT : STYLEFLOAT;
                    }
                    node.style[key] = '';
                }
                if (node.style.cssText === '') {
                    node.removeAttribute(STYLE);
                }
            },
            inlineStyle: function (body, name, attributes) {
                var span = $(Dom.create(body.ownerDocument, name, attributes)), style;
                body.appendChild(span[0]);
                style = map(cssAttributes, function (value) {
                    if (browser.msie && value == 'line-height' && span.css(value) == '1px') {
                        return 'line-height:1.5';
                    } else {
                        return value + ':' + span.css(value);
                    }
                }).join(';');
                span.remove();
                return style;
            },
            getEffectiveBackground: function (element) {
                var backgroundStyle = element.css('background-color') || '';
                if (backgroundStyle.indexOf('rgba(0, 0, 0, 0') < 0 && backgroundStyle !== 'transparent') {
                    return backgroundStyle;
                } else if (element[0].tagName.toLowerCase() === 'html') {
                    return 'Window';
                } else {
                    return Dom.getEffectiveBackground(element.parent());
                }
            },
            innerText: function (node) {
                var text = node.innerHTML;
                text = text.replace(/<!--(.|\s)*?-->/gi, '');
                text = text.replace(/<\/?[^>]+?\/?>/gm, '');
                return text;
            },
            removeClass: function (node, classNames) {
                var className = ' ' + node.className + ' ', classes = classNames.split(' '), i, len;
                for (i = 0, len = classes.length; i < len; i++) {
                    className = className.replace(' ' + classes[i] + ' ', ' ');
                }
                className = $.trim(className);
                if (className.length) {
                    node.className = className;
                } else {
                    node.removeAttribute(CLASS);
                }
            },
            commonAncestor: function () {
                var count = arguments.length, paths = [], minPathLength = Infinity, output = null, i, ancestors, node, first, j;
                if (!count) {
                    return null;
                }
                if (count == 1) {
                    return arguments[0];
                }
                for (i = 0; i < count; i++) {
                    ancestors = [];
                    node = arguments[i];
                    while (node) {
                        ancestors.push(node);
                        node = node.parentNode;
                    }
                    paths.push(ancestors.reverse());
                    minPathLength = Math.min(minPathLength, ancestors.length);
                }
                if (count == 1) {
                    return paths[0][0];
                }
                for (i = 0; i < minPathLength; i++) {
                    first = paths[0][i];
                    for (j = 1; j < count; j++) {
                        if (first != paths[j][i]) {
                            return output;
                        }
                    }
                    output = first;
                }
                return output;
            },
            closestSplittableParent: function (nodes) {
                var result;
                if (nodes.length == 1) {
                    result = Dom.parentOfType(nodes[0], [
                        'ul',
                        'ol'
                    ]);
                } else {
                    result = Dom.commonAncestor.apply(null, nodes);
                }
                if (!result) {
                    result = Dom.parentOfType(nodes[0], [
                        'p',
                        'td'
                    ]) || nodes[0].ownerDocument.body;
                }
                if (Dom.isInline(result)) {
                    result = Dom.blockParentOrBody(result);
                }
                var editableParents = map(nodes, Dom.editableParent);
                var editableAncestor = Dom.commonAncestor(editableParents)[0];
                if ($.contains(result, editableAncestor)) {
                    result = editableAncestor;
                }
                return result;
            },
            closestEditable: function (node, types) {
                var closest;
                var editable = Dom.editableParent(node);
                if (Dom.ofType(node, types)) {
                    closest = node;
                } else {
                    closest = Dom.parentOfType(node, types);
                }
                if (closest && editable && $.contains(closest, editable)) {
                    closest = editable;
                } else if (!closest && editable) {
                    closest = editable;
                }
                return closest;
            },
            closestEditableOfType: function (node, types) {
                var editable = Dom.closestEditable(node, types);
                if (editable && Dom.ofType(editable, types) && !$(editable).is('.k-editor')) {
                    return editable;
                }
            },
            filter: function (tagName, nodes, invert) {
                var filterFn = function (node) {
                    return Dom.name(node) == tagName;
                };
                return Dom.filterBy(nodes, filterFn, invert);
            },
            filterBy: function (nodes, condition, invert) {
                var i = 0;
                var len = nodes.length;
                var result = [];
                var match;
                for (; i < len; i++) {
                    match = condition(nodes[i]);
                    if (match && !invert || !match && invert) {
                        result.push(nodes[i]);
                    }
                }
                return result;
            },
            ensureTrailingBreaks: function (node) {
                var elements = $(node).find('p,td,th');
                var length = elements.length;
                var i = 0;
                if (length) {
                    for (; i < length; i++) {
                        Dom.ensureTrailingBreak(elements[i]);
                    }
                } else {
                    Dom.ensureTrailingBreak(node);
                }
            },
            removeTrailingBreak: function (node) {
                $(node).find('br[type=_moz],.k-br').remove();
            },
            ensureTrailingBreak: function (node) {
                Dom.removeTrailingBreak(node);
                var lastChild = node.lastChild;
                var name = lastChild && Dom.name(lastChild);
                var br;
                if (!name || name != 'br' && name != 'img' || name == 'br' && lastChild.className != 'k-br') {
                    br = node.ownerDocument.createElement('br');
                    br.className = 'k-br';
                    node.appendChild(br);
                }
            }
        };
        kendo.ui.editor.Dom = Dom;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/serializer', ['editor/dom'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo;
        var Editor = kendo.ui.editor;
        var dom = Editor.Dom;
        var extend = $.extend;
        var fontSizeMappings = 'xx-small,x-small,small,medium,large,x-large,xx-large'.split(',');
        var quoteRe = /"/g;
        var brRe = /<br[^>]*>/i;
        var pixelRe = /^\d+(\.\d*)?(px)?$/i;
        var emptyPRe = /<p>(?:&nbsp;)?<\/p>/i;
        var cssDeclaration = /(\*?[-#\/\*\\\w]+(?:\[[0-9a-z_-]+\])?)\s*:\s*((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/g;
        var sizzleAttr = /^sizzle-\d+/i;
        var scriptAttr = /^k-script-/i;
        var onerrorRe = /\s*onerror\s*=\s*(?:'|")?([^'">\s]*)(?:'|")?/i;
        var br = '<br class="k-br">';
        var div = document.createElement('div');
        div.innerHTML = ' <hr>';
        var supportsLeadingWhitespace = div.firstChild.nodeType === 3;
        div = null;
        var isFunction = $.isFunction;
        var TD = 'td';
        var Serializer = {
            toEditableHtml: function (html) {
                return (html || '').replace(/<!\[CDATA\[(.*)?\]\]>/g, '<!--[CDATA[$1]]-->').replace(/<(\/?)script([^>]*)>/gi, '<$1k:script$2>').replace(/<img([^>]*)>/gi, function (match) {
                    return match.replace(onerrorRe, '');
                }).replace(/(<\/?img[^>]*>)[\r\n\v\f\t ]+/gi, '$1').replace(/^<(table|blockquote)/i, br + '<$1').replace(/^[\s]*(&nbsp;|\u00a0)/i, '$1').replace(/<\/(table|blockquote)>$/i, '</$1>' + br);
            },
            _toEditableImmutables: function (body) {
                var immutable = Editor.Immutables.immutable, emptyTextNode = dom.emptyTextNode, first = body.firstChild, last = body.lastChild;
                while (emptyTextNode(first)) {
                    first = first.nextSibling;
                }
                while (emptyTextNode(last)) {
                    last = last.previousSibling;
                }
                if (first && immutable(first)) {
                    $(br).prependTo(body);
                }
                if (last && immutable(last)) {
                    $(br).appendTo(body);
                }
            },
            _fillEmptyElements: function (body) {
                $(body).find('p,td').each(function () {
                    var p = $(this);
                    if (/^\s*$/g.test(p.text()) && !p.find('img,input').length) {
                        var node = this;
                        while (node.firstChild && node.firstChild.nodeType != 3) {
                            node = node.firstChild;
                        }
                        if (node.nodeType == 1 && !dom.empty[dom.name(node)]) {
                            if (dom.is(node, 'td')) {
                                node.innerHTML = kendo.ui.editor.emptyTableCellContent;
                            } else {
                                node.innerHTML = kendo.ui.editor.emptyElementContent;
                            }
                        }
                    }
                });
            },
            _removeSystemElements: function (body) {
                $('.k-paste-container', body).remove();
            },
            _resetOrderedLists: function (root) {
                var ols = root.getElementsByTagName('ol'), i, ol, originalStart;
                for (i = 0; i < ols.length; i++) {
                    ol = ols[i];
                    originalStart = ol.getAttribute('start');
                    ol.setAttribute('start', 1);
                    if (originalStart) {
                        ol.setAttribute('start', originalStart);
                    } else {
                        ol.removeAttribute(originalStart);
                    }
                }
            },
            _preventScriptExecution: function (root) {
                $(root).find('*').each(function () {
                    var attributes = this.attributes;
                    var attribute, i, l, name;
                    var attributesToRemove = [];
                    for (i = 0, l = attributes.length; i < l; i++) {
                        attribute = attributes[i];
                        name = attribute.nodeName;
                        if (attribute.specified && /^on/i.test(name)) {
                            this.setAttribute('k-script-' + name, attribute.value);
                            attributesToRemove.push(name);
                        }
                    }
                    for (i = 0, l = attributesToRemove.length; i < l; i++) {
                        this.removeAttribute(attributesToRemove[i]);
                    }
                });
            },
            htmlToDom: function (html, root, options) {
                var browser = kendo.support.browser;
                var msie = browser.msie;
                var legacyIE = msie && browser.version < 9;
                var originalSrc = 'originalsrc';
                var originalHref = 'originalhref';
                var o = options || {};
                var immutables = o.immutables;
                html = Serializer.toEditableHtml(html);
                if (legacyIE) {
                    html = '<br/>' + html;
                    html = html.replace(/href\s*=\s*(?:'|")?([^'">\s]*)(?:'|")?/, originalHref + '="$1"');
                    html = html.replace(/src\s*=\s*(?:'|")?([^'">\s]*)(?:'|")?/, originalSrc + '="$1"');
                }
                if (isFunction(o.custom)) {
                    html = o.custom(html) || html;
                }
                root.innerHTML = html;
                if (immutables) {
                    immutables.deserialize(root);
                }
                if (legacyIE) {
                    dom.remove(root.firstChild);
                    $(root).find('k\\:script,script,link,img,a').each(function () {
                        var node = this;
                        if (node[originalHref]) {
                            node.setAttribute('href', node[originalHref]);
                            node.removeAttribute(originalHref);
                        }
                        if (node[originalSrc]) {
                            node.setAttribute('src', node[originalSrc]);
                            node.removeAttribute(originalSrc);
                        }
                    });
                } else if (msie) {
                    dom.normalize(root);
                    Serializer._resetOrderedLists(root);
                }
                Serializer._preventScriptExecution(root);
                Serializer._fillEmptyElements(root);
                Serializer._removeSystemElements(root);
                Serializer._toEditableImmutables(root);
                $('table', root).addClass('k-table');
                return root;
            },
            domToXhtml: function (root, options) {
                var result = [];
                var immutables = options && options.immutables;
                function semanticFilter(attributes) {
                    return $.grep(attributes, function (attr) {
                        return attr.name != 'style';
                    });
                }
                function mapStart(node, tag) {
                    result.push('<' + tag);
                    attr(node);
                    result.push('>');
                }
                var tagMap = {
                    iframe: {
                        start: function (node) {
                            mapStart(node, 'iframe');
                        },
                        end: function () {
                            result.push('</iframe>');
                        }
                    },
                    'k:script': {
                        start: function (node) {
                            mapStart(node, 'script');
                        },
                        end: function () {
                            result.push('</script>');
                        },
                        skipEncoding: true
                    },
                    span: {
                        semantic: true,
                        start: function (node) {
                            var style = node.style;
                            var attributes = specifiedAttributes(node);
                            var semanticAttributes = semanticFilter(attributes);
                            if (semanticAttributes.length) {
                                result.push('<span');
                                attr(node, semanticAttributes);
                                result.push('>');
                            }
                            if (style.textDecoration == 'underline') {
                                result.push('<u>');
                            }
                            var font = [];
                            if (style.color) {
                                font.push('color="' + dom.toHex(style.color) + '"');
                            }
                            if (style.fontFamily) {
                                font.push('face="' + style.fontFamily + '"');
                            }
                            if (style.fontSize) {
                                var size = $.inArray(style.fontSize, fontSizeMappings);
                                font.push('size="' + size + '"');
                            }
                            if (font.length) {
                                result.push('<font ' + font.join(' ') + '>');
                            }
                        },
                        end: function (node) {
                            var style = node.style;
                            if (style.color || style.fontFamily || style.fontSize) {
                                result.push('</font>');
                            }
                            if (style.textDecoration == 'underline') {
                                result.push('</u>');
                            }
                            if (semanticFilter(specifiedAttributes(node)).length) {
                                result.push('</span>');
                            }
                        }
                    },
                    strong: {
                        semantic: true,
                        start: function (node) {
                            mapStart(node, 'b');
                        },
                        end: function () {
                            result.push('</b>');
                        }
                    },
                    em: {
                        semantic: true,
                        start: function (node) {
                            mapStart(node, 'i');
                        },
                        end: function () {
                            result.push('</i>');
                        }
                    },
                    b: {
                        semantic: false,
                        start: function (node) {
                            mapStart(node, 'strong');
                        },
                        end: function () {
                            result.push('</strong>');
                        }
                    },
                    i: {
                        semantic: false,
                        start: function (node) {
                            mapStart(node, 'em');
                        },
                        end: function () {
                            result.push('</em>');
                        }
                    },
                    u: {
                        semantic: false,
                        start: function (node) {
                            result.push('<span');
                            var attributes = specifiedAttributes(node);
                            var style = $(attributes).filter(function (i, item) {
                                return item.name == 'style';
                            })[0];
                            var styleObj = {
                                nodeName: 'style',
                                value: 'text-decoration:underline;'
                            };
                            if (style) {
                                styleObj.value = style.value;
                                if (!/text-decoration/i.test(styleObj.value)) {
                                    styleObj.value = 'text-decoration:underline;' + styleObj.value;
                                }
                                attributes.splice($.inArray(style, attributes), 1);
                            }
                            attributes.push(styleObj);
                            attr(node, attributes);
                            result.push('>');
                        },
                        end: function () {
                            result.push('</span>');
                        }
                    },
                    font: {
                        semantic: false,
                        start: function (node) {
                            result.push('<span style="');
                            var color = node.getAttribute('color');
                            var size = fontSizeMappings[node.getAttribute('size')];
                            var face = node.getAttribute('face');
                            if (color) {
                                result.push('color:');
                                result.push(dom.toHex(color));
                                result.push(';');
                            }
                            if (face) {
                                result.push('font-family:');
                                result.push(face);
                                result.push(';');
                            }
                            if (size) {
                                result.push('font-size:');
                                result.push(size);
                                result.push(';');
                            }
                            result.push('">');
                        },
                        end: function () {
                            result.push('</span>');
                        }
                    }
                };
                tagMap.script = tagMap['k:script'];
                options = options || {};
                if (typeof options.semantic == 'undefined') {
                    options.semantic = true;
                }
                function cssProperties(cssText) {
                    var trim = $.trim;
                    var css = trim(cssText);
                    var match;
                    var property, value;
                    var properties = [];
                    cssDeclaration.lastIndex = 0;
                    while (true) {
                        match = cssDeclaration.exec(css);
                        if (!match) {
                            break;
                        }
                        property = trim(match[1].toLowerCase());
                        value = trim(match[2]);
                        if (property == 'font-size-adjust' || property == 'font-stretch') {
                            continue;
                        }
                        if (property.indexOf('color') >= 0) {
                            value = dom.toHex(value);
                        } else if (property.indexOf('font') >= 0) {
                            value = value.replace(quoteRe, '\'');
                        } else if (/\burl\(/g.test(value)) {
                            value = value.replace(quoteRe, '');
                        }
                        properties.push({
                            property: property,
                            value: value
                        });
                    }
                    return properties;
                }
                function styleAttr(cssText) {
                    var properties = cssProperties(cssText);
                    var i;
                    for (i = 0; i < properties.length; i++) {
                        result.push(properties[i].property);
                        result.push(':');
                        result.push(properties[i].value);
                        result.push(';');
                    }
                }
                function specifiedAttributes(node) {
                    var result = [];
                    var attributes = node.attributes;
                    var attribute, i, l;
                    var name, value, specified;
                    for (i = 0, l = attributes.length; i < l; i++) {
                        attribute = attributes[i];
                        name = attribute.nodeName;
                        value = attribute.value;
                        specified = attribute.specified;
                        if (name == 'value' && 'value' in node && node.value) {
                            specified = true;
                        } else if (name == 'type' && value == 'text') {
                            specified = true;
                        } else if (name == 'class' && !value) {
                            specified = false;
                        } else if (sizzleAttr.test(name)) {
                            specified = false;
                        } else if (name == 'complete') {
                            specified = false;
                        } else if (name == 'altHtml') {
                            specified = false;
                        } else if (name == 'start' && dom.is(node, 'ul')) {
                            specified = false;
                        } else if (name == 'start' && dom.is(node, 'ol') && value == '1') {
                            specified = false;
                        } else if (name.indexOf('_moz') >= 0) {
                            specified = false;
                        } else if (scriptAttr.test(name)) {
                            specified = !!options.scripts;
                        } else if (name == 'data-role' && value == 'resizable' && (dom.is(node, 'tr') || dom.is(node, 'td'))) {
                            specified = false;
                        }
                        if (specified) {
                            result.push(attribute);
                        }
                    }
                    return result;
                }
                function attr(node, attributes) {
                    var i, l, attribute, name, value;
                    attributes = attributes || specifiedAttributes(node);
                    if (dom.is(node, 'img')) {
                        var width = node.style.width, height = node.style.height, $node = $(node);
                        if (width && pixelRe.test(width)) {
                            $node.attr('width', parseInt(width, 10));
                            dom.unstyle(node, { width: undefined });
                        }
                        if (height && pixelRe.test(height)) {
                            $node.attr('height', parseInt(height, 10));
                            dom.unstyle(node, { height: undefined });
                        }
                    }
                    if (!attributes.length) {
                        return;
                    }
                    for (i = 0, l = attributes.length; i < l; i++) {
                        attribute = attributes[i];
                        name = attribute.nodeName;
                        value = attribute.value;
                        if (name == 'class' && value == 'k-table') {
                            continue;
                        }
                        name = name.replace(scriptAttr, '');
                        result.push(' ');
                        result.push(name);
                        result.push('="');
                        if (name == 'style') {
                            styleAttr(value || node.style.cssText);
                        } else if (name == 'src' || name == 'href') {
                            result.push(kendo.htmlEncode(node.getAttribute(name, 2)));
                        } else {
                            result.push(dom.fillAttrs[name] ? name : value);
                        }
                        result.push('"');
                    }
                }
                function children(node, skip, skipEncoding) {
                    for (var childNode = node.firstChild; childNode; childNode = childNode.nextSibling) {
                        child(childNode, skip, skipEncoding);
                    }
                }
                function text(node) {
                    return node.nodeValue.replace(/\ufeff/g, '');
                }
                function isEmptyBomNode(node) {
                    if (dom.isBom(node)) {
                        do {
                            node = node.parentNode;
                            if (dom.is(node, TD) && node.childNodes.length === 1) {
                                return true;
                            }
                            if (node.childNodes.length !== 1) {
                                return false;
                            }
                        } while (!dom.isBlock(node));
                        return true;
                    }
                    return false;
                }
                function child(node, skip, skipEncoding) {
                    var nodeType = node.nodeType, tagName, mapper, parent, value, previous, jqNode;
                    if (immutables && Editor.Immutables.immutable(node)) {
                        result.push(immutables.serialize(node));
                    } else if (nodeType == 1) {
                        tagName = dom.name(node);
                        jqNode = $(node);
                        if (jqNode.hasClass('k-table-resize-handle-wrapper') || jqNode.hasClass('k-column-resize-handle-wrapper') || jqNode.hasClass('k-row-resize-handle-wrapper')) {
                            return;
                        }
                        if (!tagName || dom.insignificant(node)) {
                            return;
                        }
                        if (!options.scripts && (tagName == 'script' || tagName == 'k:script')) {
                            return;
                        }
                        mapper = tagMap[tagName];
                        if (mapper) {
                            if (typeof mapper.semantic == 'undefined' || options.semantic ^ mapper.semantic) {
                                mapper.start(node);
                                children(node, false, mapper.skipEncoding);
                                mapper.end(node);
                                return;
                            }
                        }
                        result.push('<');
                        result.push(tagName);
                        attr(node);
                        if (dom.empty[tagName]) {
                            result.push(' />');
                        } else {
                            result.push('>');
                            children(node, skip || dom.is(node, 'pre'));
                            result.push('</');
                            result.push(tagName);
                            result.push('>');
                        }
                    } else if (nodeType == 3) {
                        if (isEmptyBomNode(node)) {
                            result.push('&nbsp;');
                            return;
                        }
                        value = text(node);
                        if (!skip && supportsLeadingWhitespace) {
                            parent = node.parentNode;
                            previous = node.previousSibling;
                            if (!previous) {
                                previous = (dom.isInline(parent) ? parent : node).previousSibling;
                            }
                            if (!previous || previous.innerHTML === '' || dom.isBlock(previous)) {
                                value = value.replace(/^[\r\n\v\f\t ]+/, '');
                            }
                            value = value.replace(/ +/, ' ');
                        }
                        result.push(skipEncoding ? value : dom.encode(value, options));
                    } else if (nodeType == 4) {
                        result.push('<![CDATA[');
                        result.push(node.data);
                        result.push(']]>');
                    } else if (nodeType == 8) {
                        if (node.data.indexOf('[CDATA[') < 0) {
                            result.push('<!--');
                            result.push(node.data);
                            result.push('-->');
                        } else {
                            result.push('<!');
                            result.push(node.data);
                            result.push('>');
                        }
                    }
                }
                function textOnly(root) {
                    var childrenCount = root.childNodes.length;
                    var textChild = childrenCount && root.firstChild.nodeType == 3;
                    return textChild && (childrenCount == 1 || childrenCount == 2 && dom.insignificant(root.lastChild));
                }
                function runCustom() {
                    if ($.isFunction(options.custom)) {
                        result = options.custom(result) || result;
                    }
                }
                if (textOnly(root)) {
                    result = dom.encode(text(root.firstChild).replace(/[\r\n\v\f\t ]+/, ' '), options);
                    runCustom();
                    return result;
                }
                children(root);
                result = result.join('');
                runCustom();
                if (result.replace(brRe, '').replace(emptyPRe, '') === '') {
                    return '';
                }
                return result;
            }
        };
        extend(Editor, { Serializer: Serializer });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/components', ['editor/serializer'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, DropDownList = kendo.ui.DropDownList, dom = kendo.ui.editor.Dom;
        var SelectBox = DropDownList.extend({
            init: function (element, options) {
                var that = this;
                DropDownList.fn.init.call(that, element, options);
                if (kendo.support.mobileOS.ios) {
                    this._initSelectOverlay();
                    this.bind('dataBound', $.proxy(this._initSelectOverlay, this));
                }
                that.text(that.options.title);
                that.element.attr('title', that.options.title);
                that.wrapper.attr('title', that.options.title);
                that.bind('open', function () {
                    if (that.options.autoSize) {
                        var list = that.list, listWidth;
                        list.css({
                            whiteSpace: 'nowrap',
                            width: 'auto'
                        });
                        listWidth = list.width();
                        if (listWidth > 0) {
                            listWidth += 20;
                        } else {
                            listWidth = that._listWidth;
                        }
                        list.css('width', listWidth + kendo.support.scrollbar());
                        that._listWidth = listWidth;
                    }
                });
            },
            options: {
                name: 'SelectBox',
                index: -1
            },
            _initSelectOverlay: function () {
                var selectBox = this;
                var value = selectBox.value();
                var view = this.dataSource.view();
                var item;
                var html = '';
                var encode = kendo.htmlEncode;
                for (var i = 0; i < view.length; i++) {
                    item = view[i];
                    html += '<option value=\'' + encode(item.value) + '\'';
                    if (item.value == value) {
                        html += ' selected';
                    }
                    html += '>' + encode(item.text) + '</option>';
                }
                var select = $('<select class=\'k-select-overlay\'>' + html + '</select>');
                var wrapper = $(this.element).closest('.k-widget');
                wrapper.next('.k-select-overlay').remove();
                select.insertAfter(wrapper);
                select.on('change', function () {
                    selectBox.value(this.value);
                    selectBox.trigger('change');
                });
            },
            value: function (value) {
                var that = this, result = DropDownList.fn.value.call(that, value);
                if (value === undefined) {
                    return result;
                }
                if (!DropDownList.fn.value.call(that)) {
                    that.text(that.options.title);
                }
            },
            decorate: function (body) {
                var that = this, dataSource = that.dataSource, items = dataSource.data(), i, tag, className, style;
                if (body) {
                    that.list.css('background-color', dom.getEffectiveBackground($(body)));
                }
                for (i = 0; i < items.length; i++) {
                    tag = items[i].tag || 'span';
                    className = items[i].className;
                    style = dom.inlineStyle(body, tag, { className: className });
                    style = style.replace(/"/g, '\'');
                    items[i].style = style + ';display:inline-block';
                }
                dataSource.trigger('change');
            }
        });
        kendo.ui.plugin(SelectBox);
        kendo.ui.editor.SelectBox = SelectBox;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/range', ['editor/components'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, browser = kendo.support.browser, dom = Editor.Dom, findNodeIndex = dom.findNodeIndex, isDataNode = dom.isDataNode, findClosestAncestor = dom.findClosestAncestor, getNodeLength = dom.getNodeLength, normalize = dom.normalize;
        var SelectionUtils = {
            selectionFromWindow: function (window) {
                if (!('getSelection' in window)) {
                    return new W3CSelection(window.document);
                }
                return window.getSelection();
            },
            selectionFromRange: function (range) {
                var rangeDocument = RangeUtils.documentFromRange(range);
                return SelectionUtils.selectionFromDocument(rangeDocument);
            },
            selectionFromDocument: function (document) {
                return SelectionUtils.selectionFromWindow(dom.windowFromDocument(document));
            }
        };
        var W3CRange = Class.extend({
            init: function (doc) {
                $.extend(this, {
                    ownerDocument: doc,
                    startContainer: doc,
                    endContainer: doc,
                    commonAncestorContainer: doc,
                    startOffset: 0,
                    endOffset: 0,
                    collapsed: true
                });
            },
            setStart: function (node, offset) {
                this.startContainer = node;
                this.startOffset = offset;
                updateRangeProperties(this);
                fixIvalidRange(this, true);
            },
            setEnd: function (node, offset) {
                this.endContainer = node;
                this.endOffset = offset;
                updateRangeProperties(this);
                fixIvalidRange(this, false);
            },
            setStartBefore: function (node) {
                this.setStart(node.parentNode, findNodeIndex(node));
            },
            setStartAfter: function (node) {
                this.setStart(node.parentNode, findNodeIndex(node) + 1);
            },
            setEndBefore: function (node) {
                this.setEnd(node.parentNode, findNodeIndex(node));
            },
            setEndAfter: function (node) {
                this.setEnd(node.parentNode, findNodeIndex(node) + 1);
            },
            selectNode: function (node) {
                this.setStartBefore(node);
                this.setEndAfter(node);
            },
            selectNodeContents: function (node) {
                this.setStart(node, 0);
                this.setEnd(node, node[node.nodeType === 1 ? 'childNodes' : 'nodeValue'].length);
            },
            collapse: function (toStart) {
                var that = this;
                if (toStart) {
                    that.setEnd(that.startContainer, that.startOffset);
                } else {
                    that.setStart(that.endContainer, that.endOffset);
                }
            },
            deleteContents: function () {
                var that = this, range = that.cloneRange();
                if (that.startContainer != that.commonAncestorContainer) {
                    that.setStartAfter(findClosestAncestor(that.commonAncestorContainer, that.startContainer));
                }
                that.collapse(true);
                (function deleteSubtree(iterator) {
                    while (iterator.next()) {
                        if (iterator.hasPartialSubtree()) {
                            deleteSubtree(iterator.getSubtreeIterator());
                        } else {
                            iterator.remove();
                        }
                    }
                }(new RangeIterator(range)));
            },
            cloneContents: function () {
                var document = RangeUtils.documentFromRange(this);
                return function cloneSubtree(iterator) {
                    var node, frag = document.createDocumentFragment();
                    while (node = iterator.next()) {
                        node = node.cloneNode(!iterator.hasPartialSubtree());
                        if (iterator.hasPartialSubtree()) {
                            node.appendChild(cloneSubtree(iterator.getSubtreeIterator()));
                        }
                        frag.appendChild(node);
                    }
                    return frag;
                }(new RangeIterator(this));
            },
            extractContents: function () {
                var that = this, range = that.cloneRange();
                if (that.startContainer != that.commonAncestorContainer) {
                    that.setStartAfter(findClosestAncestor(that.commonAncestorContainer, that.startContainer));
                }
                that.collapse(true);
                var document = RangeUtils.documentFromRange(that);
                return function extractSubtree(iterator) {
                    var node, frag = document.createDocumentFragment();
                    while (node = iterator.next()) {
                        if (iterator.hasPartialSubtree()) {
                            node = node.cloneNode(false);
                            node.appendChild(extractSubtree(iterator.getSubtreeIterator()));
                        } else {
                            iterator.remove(that.originalRange);
                        }
                        frag.appendChild(node);
                    }
                    return frag;
                }(new RangeIterator(range));
            },
            insertNode: function (node) {
                var that = this;
                if (isDataNode(that.startContainer)) {
                    if (that.startOffset != that.startContainer.nodeValue.length) {
                        dom.splitDataNode(that.startContainer, that.startOffset);
                    }
                    dom.insertAfter(node, that.startContainer);
                } else {
                    dom.insertAt(that.startContainer, node, that.startOffset);
                }
                that.setStart(that.startContainer, that.startOffset);
            },
            cloneRange: function () {
                return $.extend(new W3CRange(this.ownerDocument), {
                    startContainer: this.startContainer,
                    endContainer: this.endContainer,
                    commonAncestorContainer: this.commonAncestorContainer,
                    startOffset: this.startOffset,
                    endOffset: this.endOffset,
                    collapsed: this.collapsed,
                    originalRange: this
                });
            },
            toString: function () {
                var startNodeName = this.startContainer.nodeName, endNodeName = this.endContainer.nodeName;
                return [
                    startNodeName == '#text' ? this.startContainer.nodeValue : startNodeName,
                    '(',
                    this.startOffset,
                    ') : ',
                    endNodeName == '#text' ? this.endContainer.nodeValue : endNodeName,
                    '(',
                    this.endOffset,
                    ')'
                ].join('');
            }
        });
        W3CRange.fromNode = function (node) {
            return new W3CRange(node.ownerDocument);
        };
        function compareBoundaries(start, end, startOffset, endOffset) {
            if (start == end) {
                return endOffset - startOffset;
            }
            var container = end;
            while (container && container.parentNode != start) {
                container = container.parentNode;
            }
            if (container) {
                return findNodeIndex(container) - startOffset;
            }
            container = start;
            while (container && container.parentNode != end) {
                container = container.parentNode;
            }
            if (container) {
                return endOffset - findNodeIndex(container) - 1;
            }
            var root = dom.commonAncestor(start, end);
            var startAncestor = start;
            while (startAncestor && startAncestor.parentNode != root) {
                startAncestor = startAncestor.parentNode;
            }
            if (!startAncestor) {
                startAncestor = root;
            }
            var endAncestor = end;
            while (endAncestor && endAncestor.parentNode != root) {
                endAncestor = endAncestor.parentNode;
            }
            if (!endAncestor) {
                endAncestor = root;
            }
            if (startAncestor == endAncestor) {
                return 0;
            }
            return findNodeIndex(endAncestor) - findNodeIndex(startAncestor);
        }
        function fixIvalidRange(range, toStart) {
            function isInvalidRange(range) {
                try {
                    return compareBoundaries(range.startContainer, range.endContainer, range.startOffset, range.endOffset) < 0;
                } catch (ex) {
                    return true;
                }
            }
            if (isInvalidRange(range)) {
                if (toStart) {
                    range.commonAncestorContainer = range.endContainer = range.startContainer;
                    range.endOffset = range.startOffset;
                } else {
                    range.commonAncestorContainer = range.startContainer = range.endContainer;
                    range.startOffset = range.endOffset;
                }
                range.collapsed = true;
            }
        }
        function updateRangeProperties(range) {
            range.collapsed = range.startContainer == range.endContainer && range.startOffset == range.endOffset;
            var node = range.startContainer;
            while (node && node != range.endContainer && !dom.isAncestorOf(node, range.endContainer)) {
                node = node.parentNode;
            }
            range.commonAncestorContainer = node;
        }
        var RangeIterator = Class.extend({
            init: function (range) {
                $.extend(this, {
                    range: range,
                    _current: null,
                    _next: null,
                    _end: null
                });
                if (range.collapsed) {
                    return;
                }
                var root = range.commonAncestorContainer;
                this._next = range.startContainer == root && !isDataNode(range.startContainer) ? range.startContainer.childNodes[range.startOffset] : findClosestAncestor(root, range.startContainer);
                this._end = range.endContainer == root && !isDataNode(range.endContainer) ? range.endContainer.childNodes[range.endOffset] : findClosestAncestor(root, range.endContainer).nextSibling;
            },
            hasNext: function () {
                return !!this._next;
            },
            next: function () {
                var that = this, current = that._current = that._next;
                that._next = that._current && that._current.nextSibling != that._end ? that._current.nextSibling : null;
                if (isDataNode(that._current)) {
                    if (that.range.endContainer == that._current) {
                        current = current.cloneNode(true);
                        current.deleteData(that.range.endOffset, current.length - that.range.endOffset);
                    }
                    if (that.range.startContainer == that._current) {
                        current = current.cloneNode(true);
                        current.deleteData(0, that.range.startOffset);
                    }
                }
                return current;
            },
            traverse: function (callback) {
                var that = this, current;
                function next() {
                    that._current = that._next;
                    that._next = that._current && that._current.nextSibling != that._end ? that._current.nextSibling : null;
                    return that._current;
                }
                while (current = next()) {
                    if (that.hasPartialSubtree()) {
                        that.getSubtreeIterator().traverse(callback);
                    } else {
                        callback(current);
                    }
                }
                return current;
            },
            remove: function (originalRange) {
                var that = this, inStartContainer = that.range.startContainer == that._current, inEndContainer = that.range.endContainer == that._current, start, end, delta;
                if (isDataNode(that._current) && (inStartContainer || inEndContainer)) {
                    start = inStartContainer ? that.range.startOffset : 0;
                    end = inEndContainer ? that.range.endOffset : that._current.length;
                    delta = end - start;
                    if (originalRange && (inStartContainer || inEndContainer)) {
                        if (that._current == originalRange.startContainer && start <= originalRange.startOffset) {
                            originalRange.startOffset -= delta;
                        }
                        if (that._current == originalRange.endContainer && end <= originalRange.endOffset) {
                            originalRange.endOffset -= delta;
                        }
                    }
                    that._current.deleteData(start, delta);
                } else {
                    var parent = that._current.parentNode;
                    if (originalRange && (that.range.startContainer == parent || that.range.endContainer == parent)) {
                        var nodeIndex = findNodeIndex(that._current);
                        if (parent == originalRange.startContainer && nodeIndex <= originalRange.startOffset) {
                            originalRange.startOffset -= 1;
                        }
                        if (parent == originalRange.endContainer && nodeIndex < originalRange.endOffset) {
                            originalRange.endOffset -= 1;
                        }
                    }
                    dom.remove(that._current);
                }
            },
            hasPartialSubtree: function () {
                return !isDataNode(this._current) && (dom.isAncestorOrSelf(this._current, this.range.startContainer) || dom.isAncestorOrSelf(this._current, this.range.endContainer));
            },
            getSubtreeIterator: function () {
                return new RangeIterator(this.getSubRange());
            },
            getSubRange: function () {
                var that = this, subRange = that.range.cloneRange();
                subRange.selectNodeContents(that._current);
                if (dom.isAncestorOrSelf(that._current, that.range.startContainer)) {
                    subRange.setStart(that.range.startContainer, that.range.startOffset);
                }
                if (dom.isAncestorOrSelf(that._current, that.range.endContainer)) {
                    subRange.setEnd(that.range.endContainer, that.range.endOffset);
                }
                return subRange;
            }
        });
        var W3CSelection = Class.extend({
            init: function (doc) {
                this.ownerDocument = doc;
                this.rangeCount = 1;
            },
            addRange: function (range) {
                var textRange = this.ownerDocument.body.createTextRange();
                adoptContainer(textRange, range, false);
                adoptContainer(textRange, range, true);
                textRange.select();
            },
            removeAllRanges: function () {
                var selection = this.ownerDocument.selection;
                if (selection.type != 'None') {
                    selection.empty();
                }
            },
            getRangeAt: function () {
                var textRange, range = new W3CRange(this.ownerDocument), selection = this.ownerDocument.selection, element, commonAncestor;
                try {
                    textRange = selection.createRange();
                    element = textRange.item ? textRange.item(0) : textRange.parentElement();
                    if (element.ownerDocument != this.ownerDocument) {
                        return range;
                    }
                } catch (ex) {
                    return range;
                }
                if (selection.type == 'Control') {
                    range.selectNode(textRange.item(0));
                } else {
                    commonAncestor = textRangeContainer(textRange);
                    adoptEndPoint(textRange, range, commonAncestor, true);
                    adoptEndPoint(textRange, range, commonAncestor, false);
                    if (range.startContainer.nodeType == 9) {
                        range.setStart(range.endContainer, range.startOffset);
                    }
                    if (range.endContainer.nodeType == 9) {
                        range.setEnd(range.startContainer, range.endOffset);
                    }
                    if (textRange.compareEndPoints('StartToEnd', textRange) === 0) {
                        range.collapse(false);
                    }
                    var startContainer = range.startContainer, endContainer = range.endContainer, body = this.ownerDocument.body;
                    if (!range.collapsed && range.startOffset === 0 && range.endOffset == getNodeLength(range.endContainer) && !(startContainer == endContainer && isDataNode(startContainer) && startContainer.parentNode == body)) {
                        var movedStart = false, movedEnd = false;
                        while (findNodeIndex(startContainer) === 0 && startContainer == startContainer.parentNode.firstChild && startContainer != body) {
                            startContainer = startContainer.parentNode;
                            movedStart = true;
                        }
                        while (findNodeIndex(endContainer) == getNodeLength(endContainer.parentNode) - 1 && endContainer == endContainer.parentNode.lastChild && endContainer != body) {
                            endContainer = endContainer.parentNode;
                            movedEnd = true;
                        }
                        if (startContainer == body && endContainer == body && movedStart && movedEnd) {
                            range.setStart(startContainer, 0);
                            range.setEnd(endContainer, getNodeLength(body));
                        }
                    }
                }
                return range;
            }
        });
        function textRangeContainer(textRange) {
            var left = textRange.duplicate(), right = textRange.duplicate();
            left.collapse(true);
            right.collapse(false);
            return dom.commonAncestor(textRange.parentElement(), left.parentElement(), right.parentElement());
        }
        function adoptContainer(textRange, range, start) {
            var container = range[start ? 'startContainer' : 'endContainer'], offset = range[start ? 'startOffset' : 'endOffset'], textOffset = 0, isData = isDataNode(container), anchorNode = isData ? container : container.childNodes[offset] || null, anchorParent = isData ? container.parentNode : container, doc = range.ownerDocument, cursor = doc.body.createTextRange(), cursorNode;
            if (container.nodeType == 3 || container.nodeType == 4) {
                textOffset = offset;
            }
            if (!anchorParent) {
                anchorParent = doc.body;
            }
            if (anchorParent.nodeName.toLowerCase() == 'img') {
                cursor.moveToElementText(anchorParent);
                cursor.collapse(false);
                textRange.setEndPoint(start ? 'StartToStart' : 'EndToStart', cursor);
            } else {
                cursorNode = anchorParent.insertBefore(dom.create(doc, 'a'), anchorNode);
                cursor.moveToElementText(cursorNode);
                dom.remove(cursorNode);
                cursor[start ? 'moveStart' : 'moveEnd']('character', textOffset);
                cursor.collapse(false);
                textRange.setEndPoint(start ? 'StartToStart' : 'EndToStart', cursor);
            }
        }
        function adoptEndPoint(textRange, range, commonAncestor, start) {
            var cursorNode = dom.create(range.ownerDocument, 'a'), cursor = textRange.duplicate(), comparison = start ? 'StartToStart' : 'StartToEnd', result, parent, target, previous, next, args, index, appended = false;
            cursorNode.innerHTML = '\uFEFF';
            cursor.collapse(start);
            parent = cursor.parentElement();
            if (!dom.isAncestorOrSelf(commonAncestor, parent)) {
                parent = commonAncestor;
            }
            do {
                if (appended) {
                    parent.insertBefore(cursorNode, cursorNode.previousSibling);
                } else {
                    parent.appendChild(cursorNode);
                    appended = true;
                }
                cursor.moveToElementText(cursorNode);
            } while ((result = cursor.compareEndPoints(comparison, textRange)) > 0 && cursorNode.previousSibling);
            target = cursorNode.nextSibling;
            if (result == -1 && isDataNode(target)) {
                cursor.setEndPoint(start ? 'EndToStart' : 'EndToEnd', textRange);
                dom.remove(cursorNode);
                args = [
                    target,
                    cursor.text.length
                ];
            } else {
                previous = !start && cursorNode.previousSibling;
                next = start && cursorNode.nextSibling;
                if (isDataNode(next)) {
                    args = [
                        next,
                        0
                    ];
                } else if (isDataNode(previous)) {
                    args = [
                        previous,
                        previous.length
                    ];
                } else {
                    index = findNodeIndex(cursorNode);
                    if (parent.nextSibling && index == parent.childNodes.length - 1) {
                        args = [
                            parent.nextSibling,
                            0
                        ];
                    } else {
                        args = [
                            parent,
                            index
                        ];
                    }
                }
                dom.remove(cursorNode);
            }
            range[start ? 'setStart' : 'setEnd'].apply(range, args);
        }
        var RangeEnumerator = Class.extend({
            init: function (range) {
                this.enumerate = function () {
                    var nodes = [];
                    function visit(node) {
                        if (dom.is(node, 'img') || node.nodeType == 3 && (!dom.isEmptyspace(node) || node.nodeValue == '\uFEFF')) {
                            nodes.push(node);
                        } else {
                            node = node.firstChild;
                            while (node) {
                                visit(node);
                                node = node.nextSibling;
                            }
                        }
                    }
                    new RangeIterator(range).traverse(visit);
                    return nodes;
                };
            }
        });
        var ImmutablesRangeIterator = RangeIterator.extend({
            hasPartialSubtree: function () {
                var immutable = Editor.Immutables && Editor.Immutables.immutable;
                return immutable && !immutable(this._current) && RangeIterator.fn.hasPartialSubtree.call(this);
            },
            getSubtreeIterator: function () {
                return new ImmutablesRangeIterator(this.getSubRange());
            }
        });
        var ImmutablesRangeEnumerator = Class.extend({
            init: function (range) {
                this.enumerate = function () {
                    var nodes = [];
                    var immutable = Editor.Immutables && Editor.Immutables.immutable;
                    function visit(node) {
                        if (immutable && !immutable(node)) {
                            if (dom.is(node, 'img') || node.nodeType == 3 && (!dom.isEmptyspace(node) || node.nodeValue == '\uFEFF')) {
                                nodes.push(node);
                            } else {
                                node = node.firstChild;
                                while (node) {
                                    visit(node);
                                    node = node.nextSibling;
                                }
                            }
                        }
                    }
                    new ImmutablesRangeIterator(range).traverse(visit);
                    return nodes;
                };
            }
        });
        var RestorePoint = Class.extend({
            init: function (range, body, options) {
                var that = this;
                that.range = range;
                that.rootNode = RangeUtils.documentFromRange(range);
                that.body = body || that.getEditable(range);
                if (dom.name(that.body) != 'body') {
                    that.rootNode = that.body;
                }
                that.startContainer = that.nodeToPath(range.startContainer);
                that.endContainer = that.nodeToPath(range.endContainer);
                that.startOffset = that.offset(range.startContainer, range.startOffset);
                that.endOffset = that.offset(range.endContainer, range.endOffset);
                that.immutables = options && options.immutables;
                if (that.immutables) {
                    that.serializedImmutables = Editor.Immutables.removeImmutables(that.body);
                }
                that.html = that.body.innerHTML;
                if (that.immutables && !that.serializedImmutables.empty) {
                    Editor.Immutables.restoreImmutables(that.body, that.serializedImmutables);
                }
            },
            index: function (node) {
                var result = 0, lastType = node.nodeType;
                while (node = node.previousSibling) {
                    var nodeType = node.nodeType;
                    if (nodeType != 3 || lastType != nodeType) {
                        result++;
                    }
                    lastType = nodeType;
                }
                return result;
            },
            getEditable: function (range) {
                var root = range.commonAncestorContainer;
                while (root && (root.nodeType == 3 || root.attributes && (!root.attributes.contentEditable || root.attributes.contentEditable.nodeValue.toLowerCase() == 'false'))) {
                    root = root.parentNode;
                }
                return root;
            },
            restoreHtml: function () {
                var that = this;
                dom.removeChildren(that.body);
                that.body.innerHTML = that.html;
                if (that.immutables && !that.serializedImmutables.empty) {
                    Editor.Immutables.restoreImmutables(that.body, that.serializedImmutables);
                }
            },
            offset: function (node, value) {
                if (node.nodeType == 3) {
                    while ((node = node.previousSibling) && node.nodeType == 3) {
                        value += node.nodeValue.length;
                    }
                }
                return value;
            },
            nodeToPath: function (node) {
                var path = [];
                while (node != this.rootNode) {
                    path.push(this.index(node));
                    node = node.parentNode;
                }
                return path;
            },
            toRangePoint: function (range, start, path, denormalizedOffset) {
                var node = this.rootNode, length = path.length, offset = denormalizedOffset;
                while (length--) {
                    node = node.childNodes[path[length]];
                    // if (node) node = node.childNodes[path[length]]; //Custom Change// // don't keep//
                }
                while (node && node.nodeType == 3 && node.nodeValue.length < offset) {
                    offset -= node.nodeValue.length;
                    node = node.nextSibling;
                }
                if (node && offset >= 0) {
                    range[start ? 'setStart' : 'setEnd'](node, offset);
                }
            },
            toRange: function () {
                var that = this, result = that.range.cloneRange();
                that.toRangePoint(result, true, that.startContainer, that.startOffset);
                that.toRangePoint(result, false, that.endContainer, that.endOffset);
                return result;
            }
        });
        var Marker = Class.extend({
            init: function () {
                this.caret = null;
            },
            addCaret: function (range) {
                var that = this;
                var caret = that.caret = dom.create(RangeUtils.documentFromRange(range), 'span', { className: 'k-marker' });
                range.insertNode(caret);
                dom.stripBomNode(caret.previousSibling);
                dom.stripBomNode(caret.nextSibling);
                range.selectNode(caret);
                return caret;
            },
            removeCaret: function (range) {
                var that = this, previous = that.caret.previousSibling, startOffset = 0;
                if (previous) {
                    startOffset = isDataNode(previous) ? previous.nodeValue.length : findNodeIndex(previous);
                }
                var container = that.caret.parentNode;
                var containerIndex = previous ? findNodeIndex(previous) : 0;
                dom.remove(that.caret);
                normalize(container);
                var node = container.childNodes[containerIndex];
                if (isDataNode(node)) {
                    range.setStart(node, startOffset);
                } else if (node) {
                    var textNode = dom.lastTextNode(node);
                    if (textNode) {
                        range.setStart(textNode, textNode.nodeValue.length);
                    } else {
                        range[previous ? 'setStartAfter' : 'setStartBefore'](node);
                    }
                } else {
                    if (!browser.msie && !container.innerHTML) {
                        container.innerHTML = '<br _moz_dirty="" />';
                    }
                    range.selectNodeContents(container);
                }
                range.collapse(true);
            },
            add: function (range, expand) {
                var that = this;
                var collapsed = range.collapsed && !RangeUtils.isExpandable(range);
                var doc = RangeUtils.documentFromRange(range);
                if (expand && range.collapsed) {
                    that.addCaret(range);
                    range = RangeUtils.expand(range);
                }
                var rangeBoundary = range.cloneRange();
                rangeBoundary.collapse(false);
                that.end = dom.create(doc, 'span', { className: 'k-marker' });
                rangeBoundary.insertNode(that.end);
                rangeBoundary = range.cloneRange();
                rangeBoundary.collapse(true);
                that.start = that.end.cloneNode(true);
                rangeBoundary.insertNode(that.start);
                that._removeDeadMarkers(that.start, that.end);
                if (collapsed) {
                    var bom = doc.createTextNode('\uFEFF');
                    dom.insertAfter(bom.cloneNode(), that.start);
                    dom.insertBefore(bom, that.end);
                }
                normalize(range.commonAncestorContainer);
                range.setStartBefore(that.start);
                range.setEndAfter(that.end);
                return range;
            },
            _removeDeadMarkers: function (start, end) {
                if (start.previousSibling && start.previousSibling.nodeValue == '\uFEFF') {
                    dom.remove(start.previousSibling);
                }
                if (end.nextSibling && end.nextSibling.nodeValue == '\uFEFF') {
                    dom.remove(end.nextSibling);
                }
            },
            _normalizedIndex: function (node) {
                var index = findNodeIndex(node);
                var pointer = node;
                while (pointer.previousSibling) {
                    if (pointer.nodeType == 3 && pointer.previousSibling.nodeType == 3) {
                        index--;
                    }
                    pointer = pointer.previousSibling;
                }
                return index;
            },
            remove: function (range) {
                var that = this, start = that.start, end = that.end, shouldNormalizeStart, shouldNormalizeEnd, shouldNormalize;
                normalize(range.commonAncestorContainer);
                while (!start.nextSibling && start.parentNode) {
                    start = start.parentNode;
                }
                while (!end.previousSibling && end.parentNode) {
                    end = end.parentNode;
                }
                shouldNormalizeStart = start.previousSibling && start.previousSibling.nodeType == 3 && (start.nextSibling && start.nextSibling.nodeType == 3);
                shouldNormalizeEnd = end.previousSibling && end.previousSibling.nodeType == 3 && (end.nextSibling && end.nextSibling.nodeType == 3);
                shouldNormalize = shouldNormalizeStart && shouldNormalizeEnd;
                start = start.nextSibling;
                end = end.previousSibling;
                var isBomSelected = start === end && dom.isBom(start);
                if (isBomSelected && start.length > 1) {
                    start.nodeValue = start.nodeValue.charAt(0);
                }
                var collapsed = isBomSelected;
                var collapsedToStart = false;
                if (start == that.end) {
                    collapsedToStart = !!that.start.previousSibling;
                    start = end = that.start.previousSibling || that.end.nextSibling;
                    collapsed = true;
                }
                dom.remove(that.start);
                dom.remove(that.end);
                if (!start || !end) {
                    range.selectNodeContents(range.commonAncestorContainer);
                    range.collapse(true);
                    return;
                }
                var startOffset = collapsed ? isDataNode(start) ? start.nodeValue.length : start.childNodes.length : 0;
                var endOffset = isDataNode(end) ? end.nodeValue.length : end.childNodes.length;
                if (start.nodeType == 3) {
                    while (start.previousSibling && start.previousSibling.nodeType == 3) {
                        start = start.previousSibling;
                        startOffset += start.nodeValue.length;
                    }
                }
                if (end.nodeType == 3) {
                    while (end.previousSibling && end.previousSibling.nodeType == 3) {
                        end = end.previousSibling;
                        endOffset += end.nodeValue.length;
                    }
                }
                var startParent = start.parentNode;
                var endParent = end.parentNode;
                var startIndex = this._normalizedIndex(start);
                var endIndex = this._normalizedIndex(end);
                normalize(startParent);
                if (start.nodeType == 3) {
                    start = startParent.childNodes[startIndex];
                }
                normalize(endParent);
                if (end.nodeType == 3) {
                    end = endParent.childNodes[endIndex];
                }
                if (collapsed) {
                    if (start.nodeType == 3) {
                        range.setStart(start, startOffset);
                    } else {
                        range[collapsedToStart ? 'setStartAfter' : 'setStartBefore'](start);
                    }
                    range.collapse(true);
                } else {
                    if (start.nodeType == 3) {
                        range.setStart(start, startOffset);
                    } else {
                        range.setStartBefore(start);
                    }
                    if (end.nodeType == 3) {
                        range.setEnd(end, endOffset);
                    } else {
                        range.setEndAfter(end);
                    }
                }
                if (that.caret) {
                    that.removeCaret(range);
                }
            }
        });
        var boundary = /[\u0009-\u000d]|\u0020|\u00a0|\ufeff|\.|,|;|:|!|\(|\)|\?/;
        var RangeUtils = {
            nodes: function (range) {
                var nodes = RangeUtils.textNodes(range);
                if (!nodes.length) {
                    range.selectNodeContents(range.commonAncestorContainer);
                    nodes = RangeUtils.textNodes(range);
                    if (!nodes.length) {
                        nodes = dom.significantChildNodes(range.commonAncestorContainer);
                    }
                }
                return nodes;
            },
            textNodes: function (range) {
                return new RangeEnumerator(range).enumerate();
            },
            editableTextNodes: function (range) {
                var nodes = [], immutableParent = Editor.Immutables && Editor.Immutables.immutableParent;
                if (immutableParent && !immutableParent(range.commonAncestorContainer)) {
                    nodes = new ImmutablesRangeEnumerator(range).enumerate();
                }
                return nodes;
            },
            documentFromRange: function (range) {
                var startContainer = range.startContainer;
                return startContainer.nodeType == 9 ? startContainer : startContainer.ownerDocument;
            },
            createRange: function (document) {
                if (browser.msie && browser.version < 9) {
                    return new W3CRange(document);
                }
                return document.createRange();
            },
            selectRange: function (range) {
                var image = RangeUtils.image(range);
                if (image) {
                    range.setStartAfter(image);
                    range.setEndAfter(image);
                }
                var selection = SelectionUtils.selectionFromRange(range);
                selection.removeAllRanges();
                selection.addRange(range);
            },
            stringify: function (range) {
                return kendo.format('{0}:{1} - {2}:{3}', dom.name(range.startContainer), range.startOffset, dom.name(range.endContainer), range.endOffset);
            },
            split: function (range, node, trim) {
                function partition(start) {
                    var partitionRange = range.cloneRange();
                    partitionRange.collapse(start);
                    partitionRange[start ? 'setStartBefore' : 'setEndAfter'](node);
                    var contents = partitionRange.extractContents();
                    if (trim) {
                        contents = dom.trim(contents);
                    }
                    dom[start ? 'insertBefore' : 'insertAfter'](contents, node);
                }
                partition(true);
                partition(false);
            },
            mapAll: function (range, map) {
                var nodes = [];
                new RangeIterator(range).traverse(function (node) {
                    var mapped = map(node);
                    if (mapped && $.inArray(mapped, nodes) < 0) {
                        nodes.push(mapped);
                    }
                });
                return nodes;
            },
            getAll: function (range, predicate) {
                var selector = predicate;
                if (typeof predicate == 'string') {
                    predicate = function (node) {
                        return dom.is(node, selector);
                    };
                }
                return RangeUtils.mapAll(range, function (node) {
                    if (predicate(node)) {
                        return node;
                    }
                });
            },
            getMarkers: function (range) {
                return RangeUtils.getAll(range, function (node) {
                    return node.className == 'k-marker';
                });
            },
            image: function (range) {
                var nodes = RangeUtils.getAll(range, 'img');
                if (nodes.length == 1) {
                    return nodes[0];
                }
            },
            isStartOf: function (originalRange, node) {
                if (originalRange.startOffset !== 0) {
                    return false;
                }
                var range = originalRange.cloneRange();
                while (range.startOffset === 0 && range.startContainer != node) {
                    var index = dom.findNodeIndex(range.startContainer);
                    var parent = range.startContainer.parentNode;
                    while (index > 0 && parent[index - 1] && dom.insignificant(parent[index - 1])) {
                        index--;
                    }
                    range.setStart(parent, index);
                }
                return range.startOffset === 0 && range.startContainer == node;
            },
            isEndOf: function (originalRange, node) {
                var range = originalRange.cloneRange();
                range.collapse(false);
                var start = range.startContainer;
                if (dom.isDataNode(start) && range.startOffset == dom.getNodeLength(start)) {
                    range.setStart(start.parentNode, dom.findNodeIndex(start) + 1);
                    range.collapse(true);
                }
                range.setEnd(node, dom.getNodeLength(node));
                var nodes = [];
                function visit(node) {
                    if (!dom.insignificant(node) && !(dom.isDataNode(node) && /^[\ufeff]*$/.test(node.nodeValue))) {
                        nodes.push(node);
                    }
                }
                new RangeIterator(range).traverse(visit);
                return !nodes.length;
            },
            wrapSelectedElements: function (range) {
                var startEditable = dom.editableParent(range.startContainer);
                var endEditable = dom.editableParent(range.endContainer);
                while (range.startOffset === 0 && range.startContainer != startEditable) {
                    range.setStart(range.startContainer.parentNode, dom.findNodeIndex(range.startContainer));
                }
                function isEnd(offset, container) {
                    var length = dom.getNodeLength(container);
                    if (offset == length) {
                        return true;
                    }
                    for (var i = offset; i < length; i++) {
                        if (!dom.insignificant(container.childNodes[i])) {
                            return false;
                        }
                    }
                    return true;
                }
                while (isEnd(range.endOffset, range.endContainer) && range.endContainer != endEditable) {
                    range.setEnd(range.endContainer.parentNode, dom.findNodeIndex(range.endContainer) + 1);
                }
                return range;
            },
            expand: function (range) {
                var result = range.cloneRange();
                var startContainer = result.startContainer.childNodes[result.startOffset === 0 ? 0 : result.startOffset - 1];
                var endContainer = result.endContainer.childNodes[result.endOffset];
                if (!isDataNode(startContainer) || !isDataNode(endContainer)) {
                    return result;
                }
                var beforeCaret = startContainer.nodeValue;
                var afterCaret = endContainer.nodeValue;
                if (!beforeCaret || !afterCaret) {
                    return result;
                }
                var startOffset = beforeCaret.split('').reverse().join('').search(boundary);
                var endOffset = afterCaret.search(boundary);
                if (!startOffset || !endOffset) {
                    return result;
                }
                endOffset = endOffset == -1 ? afterCaret.length : endOffset;
                startOffset = startOffset == -1 ? 0 : beforeCaret.length - startOffset;
                result.setStart(startContainer, startOffset);
                result.setEnd(endContainer, endOffset);
                return result;
            },
            isExpandable: function (range) {
                var node = range.startContainer;
                var rangeDocument = RangeUtils.documentFromRange(range);
                if (node == rangeDocument || node == rangeDocument.body) {
                    return false;
                }
                var result = range.cloneRange();
                var value = node.nodeValue;
                if (!value) {
                    return false;
                }
                var beforeCaret = value.substring(0, result.startOffset);
                var afterCaret = value.substring(result.startOffset);
                var startOffset = 0, endOffset = 0;
                if (beforeCaret) {
                    startOffset = beforeCaret.split('').reverse().join('').search(boundary);
                }
                if (afterCaret) {
                    endOffset = afterCaret.search(boundary);
                }
                return startOffset && endOffset;
            }
        };
        extend(Editor, {
            SelectionUtils: SelectionUtils,
            W3CRange: W3CRange,
            RangeIterator: RangeIterator,
            W3CSelection: W3CSelection,
            RangeEnumerator: RangeEnumerator,
            RestorePoint: RestorePoint,
            Marker: Marker,
            RangeUtils: RangeUtils
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/immutables', ['editor/range'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, Class = kendo.Class, Editor = kendo.ui.editor, dom = Editor.Dom, template = kendo.template, RangeUtils = Editor.RangeUtils, complexBlocks = [
                'ul',
                'ol',
                'tbody',
                'thead',
                'table'
            ], toolsToBeUpdated = [
                'bold',
                'italic',
                'underline',
                'strikethrough',
                'superscript',
                'subscript',
                'forecolor',
                'backcolor',
                'fontname',
                'fontsize',
                'createlink',
                'unlink',
                'autolink',
                'addcolumnleft',
                'addcolumnright',
                'addrowabove',
                'addrowbelow',
                'deleterow',
                'deletecolumn',
                'mergecells',
                'formatting',
                'cleanformatting'
            ], IMMUTABALE = 'k-immutable', IMMUTABALE_MARKER_SELECTOR = '[' + IMMUTABALE + ']', IMMUTABLE_SELECTOR = '[contenteditable=\'false\']';
        var rootCondition = function (node) {
            return $(node).is('body,.k-editor');
        };
        var immutable = function (node) {
            return node.getAttribute && node.getAttribute('contenteditable') == 'false';
        };
        var immutableParent = function (node) {
            return dom.closestBy(node, immutable, rootCondition);
        };
        var expandImmutablesIn = function (range) {
            var startImmutableParent = immutableParent(range.startContainer);
            var endImmutableParent = immutableParent(range.endContainer);
            if (startImmutableParent || endImmutableParent) {
                if (startImmutableParent) {
                    range.setStartBefore(startImmutableParent);
                }
                if (endImmutableParent) {
                    range.setEndAfter(endImmutableParent);
                }
            }
        };
        var immutablesContext = function (range) {
            if (immutableParent(range.commonAncestorContainer)) {
                return true;
            } else if (immutableParent(range.startContainer) || immutableParent(range.endContainer)) {
                var editableNodes = RangeUtils.editableTextNodes(range);
                if (editableNodes.length === 0) {
                    return true;
                }
            }
            return false;
        };
        var randomId = function (length) {
            var result = '';
            var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
            for (var i = length || 10; i > 0; --i) {
                result += chars.charAt(Math.round(Math.random() * (chars.length - 1)));
            }
            return result;
        };
        var removeImmutables = function (root) {
            var serializedImmutables = { empty: true }, nodeName, id, serialized;
            $(root).find(IMMUTABLE_SELECTOR).each(function (i, node) {
                nodeName = dom.name(node);
                id = randomId();
                serialized = '<' + nodeName + ' ' + IMMUTABALE + '=\'' + id + '\'></' + nodeName + '>';
                serializedImmutables[id] = {
                    node: node,
                    style: $(node).attr('style')
                };
                serializedImmutables.empty = false;
                $(node).replaceWith(serialized);
            });
            return serializedImmutables;
        };
        var restoreImmutables = function (root, serializedImmutables) {
            var id, immutable;
            $(root).find(IMMUTABALE_MARKER_SELECTOR).each(function (i, node) {
                id = node.getAttribute(IMMUTABALE);
                immutable = serializedImmutables[id];
                $(node).replaceWith(immutable.node);
                if (immutable.style != $(immutable.node).attr('style')) {
                    $(immutable.node).removeAttr('style').attr('style', immutable.style);
                }
            });
        };
        var deletingKey = function (keyCode) {
            var keys = kendo.keys;
            return keyCode === keys.BACKSPACE || keyCode == keys.DELETE;
        };
        var updateToolOptions = function (tool) {
            var options = tool ? tool.options : undefined;
            if (options && options.finder) {
                options.finder._initOptions({ immutables: true });
            }
        };
        var Immutables = Class.extend({
            init: function (editor) {
                this.editor = editor;
                this.serializedImmutables = {};
                this.options = $.extend({}, editor && editor.options && editor.options.immutables);
                var tools = editor.toolbar.tools;
                updateToolOptions(tools.justifyLeft);
                updateToolOptions(tools.justifyCenter);
                updateToolOptions(tools.justifyRight);
                updateToolOptions(tools.justifyFull);
            },
            serialize: function (node) {
                var result = this._toHtml(node), id;
                if (result.indexOf(IMMUTABALE) === -1) {
                    id = this.randomId();
                    result = result.replace(/>/, ' ' + IMMUTABALE + '="' + id + '">');
                } else {
                    id = result.match(/k-immutable\s*=\s*['"](.*)['"]/)[1];
                }
                this.serializedImmutables[id] = node;
                return result;
            },
            _toHtml: function (node) {
                var serialization = this.options.serialization;
                var serializationType = typeof serialization;
                var nodeName;
                switch (serializationType) {
                case 'string':
                    return template(serialization)(node);
                case 'function':
                    return serialization(node);
                default:
                    nodeName = dom.name(node);
                    return '<' + nodeName + '></' + nodeName + '>';
                }
            },
            deserialize: function (node) {
                var that = this;
                var deserialization = this.options.deserialization;
                $(IMMUTABALE_MARKER_SELECTOR, node).each(function () {
                    var id = this.getAttribute(IMMUTABALE);
                    var immutable = that.serializedImmutables[id];
                    if (kendo.isFunction(deserialization)) {
                        deserialization(this, immutable);
                    }
                    $(this).replaceWith(immutable);
                });
                that.serializedImmutables = {};
            },
            randomId: function (length) {
                return randomId(length);
            },
            keydown: function (e, range) {
                var isDeleting = deletingKey(e.keyCode);
                var shouldCancelEvent = isDeleting && this._cancelDeleting(e, range) || !isDeleting && this._cancelTyping(e, range);
                if (shouldCancelEvent) {
                    e.preventDefault();
                    return true;
                }
            },
            _cancelTyping: function (e, range) {
                var editor = this.editor;
                var keyboard = editor.keyboard;
                return range.collapsed && !keyboard.typingInProgress && keyboard.isTypingKey(e) && immutablesContext(range);
            },
            _cancelDeleting: function (e, range) {
                var keys = kendo.keys;
                var backspace = e.keyCode === keys.BACKSPACE;
                var del = e.keyCode == keys.DELETE;
                if (!backspace && !del) {
                    return false;
                }
                var cancelDeleting = false;
                if (range.collapsed) {
                    if (immutablesContext(range)) {
                        return true;
                    }
                    var immutable = this.nextImmutable(range, del);
                    if (immutable && backspace) {
                        var closestSelectionLi = dom.closest(range.commonAncestorContainer, 'li');
                        if (closestSelectionLi) {
                            var closestImmutableLi = dom.closest(immutable, 'li');
                            if (closestImmutableLi && closestImmutableLi !== closestSelectionLi) {
                                return cancelDeleting;
                            }
                        }
                    }
                    if (immutable && !dom.tableCell(immutable)) {
                        if (dom.parentOfType(immutable, complexBlocks) === dom.parentOfType(range.commonAncestorContainer, complexBlocks)) {
                            while (immutable && immutable.parentNode.childNodes.length == 1) {
                                immutable = immutable.parentNode;
                            }
                            if (dom.tableCell(immutable)) {
                                return cancelDeleting;
                            }
                            this._removeImmutable(immutable, range);
                        }
                        cancelDeleting = true;
                    }
                }
                return cancelDeleting;
            },
            nextImmutable: function (range, forwards) {
                var commonContainer = range.commonAncestorContainer;
                if (dom.isBom(commonContainer) || (forwards && RangeUtils.isEndOf(range, commonContainer) || !forwards && RangeUtils.isStartOf(range, commonContainer))) {
                    var next = this._nextNode(commonContainer, forwards);
                    if (next && dom.isBlock(next) && !immutableParent(next)) {
                        while (next && next.children && next.children[forwards ? 0 : next.children.length - 1]) {
                            next = next.children[forwards ? 0 : next.children.length - 1];
                        }
                    }
                    return immutableParent(next);
                }
            },
            _removeImmutable: function (immutable, range) {
                var editor = this.editor;
                var startRestorePoint = new Editor.RestorePoint(range, editor.body);
                dom.remove(immutable);
                Editor._finishUpdate(editor, startRestorePoint);
            },
            _nextNode: function (node, forwards) {
                var sibling = forwards ? 'nextSibling' : 'previousSibling';
                var current = node, next;
                while (current && !next) {
                    next = current[sibling];
                    if (next && dom.isDataNode(next) && /^\s|[\ufeff]$/.test(next.nodeValue)) {
                        current = next;
                        next = current[sibling];
                    }
                    if (!next) {
                        current = current.parentNode;
                    }
                }
                return next;
            }
        });
        Immutables.immutable = immutable;
        Immutables.immutableParent = immutableParent;
        Immutables.expandImmutablesIn = expandImmutablesIn;
        Immutables.immutablesContext = immutablesContext;
        Immutables.toolsToBeUpdated = toolsToBeUpdated;
        Immutables.removeImmutables = removeImmutables;
        Immutables.restoreImmutables = restoreImmutables;
        Editor.Immutables = Immutables;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/command', ['editor/immutables'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, editorNS = kendo.ui.editor, dom = editorNS.Dom, RestorePoint = editorNS.RestorePoint, Marker = editorNS.Marker, extend = $.extend;
        function finishUpdate(editor, startRestorePoint) {
            var endRestorePoint = editor.selectionRestorePoint = new RestorePoint(editor.getRange(), editor.body);
            var command = new GenericCommand(startRestorePoint, endRestorePoint);
            command.editor = editor;
            editor.undoRedoStack.push(command);
            return endRestorePoint;
        }
        var Command = Class.extend({
            init: function (options) {
                this.options = options;
                this.restorePoint = new RestorePoint(options.range, options.body, { immutables: options.immutables });
                this.marker = new Marker();
                this.formatter = options.formatter;
            },
            getRange: function () {
                return this.restorePoint.toRange();
            },
            lockRange: function (expand) {
                return this.marker.add(this.getRange(), expand);
            },
            releaseRange: function (range) {
                this.marker.remove(range);
                this.editor.selectRange(range);
            },
            undo: function () {
                var point = this.restorePoint;
                point.restoreHtml();
                this.editor.selectRange(point.toRange());
            },
            redo: function () {
                this.exec();
            },
            createDialog: function (content, options) {
                var editor = this.editor;
                return $(content).appendTo(document.body).kendoWindow(extend({}, editor.options.dialogOptions, options)).closest('.k-window').toggleClass('k-rtl', kendo.support.isRtl(editor.wrapper)).end();
            },
            exec: function () {
                var range = this.lockRange(true);
                this.formatter.editor = this.editor;
                this.formatter.toggle(range);
                this.releaseRange(range);
            },
            immutables: function () {
                return this.editor && this.editor.options.immutables;
            },
            expandImmutablesIn: function (range) {
                if (this.immutables()) {
                    kendo.ui.editor.Immutables.expandImmutablesIn(range);
                    this.restorePoint = new RestorePoint(range, this.editor.body);
                }
            }
        });
        var GenericCommand = Class.extend({
            init: function (startRestorePoint, endRestorePoint) {
                this.body = startRestorePoint.body;
                this.startRestorePoint = startRestorePoint;
                this.endRestorePoint = endRestorePoint;
            },
            redo: function () {
                dom.removeChildren(this.body);
                this.body.innerHTML = this.endRestorePoint.html;
                this.editor.selectRange(this.endRestorePoint.toRange());
            },
            undo: function () {
                dom.removeChildren(this.body);
                this.body.innerHTML = this.startRestorePoint.html;
                this.editor.selectRange(this.startRestorePoint.toRange());
            }
        });
        extend(editorNS, {
            _finishUpdate: finishUpdate,
            Command: Command,
            GenericCommand: GenericCommand
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/toolbar', ['editor/range'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo;
        var ui = kendo.ui;
        var editorNS = ui.editor;
        var Widget = ui.Widget;
        var extend = $.extend;
        var proxy = $.proxy;
        var keys = kendo.keys;
        var NS = '.kendoEditor';
        var EditorUtils = editorNS.EditorUtils;
        var ToolTemplate = editorNS.ToolTemplate;
        var Tool = editorNS.Tool;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var OVERFLOWANCHOR = 'overflowAnchor';
        var focusable = '.k-tool-group:visible a.k-tool:not(.k-state-disabled),' + '.k-tool.k-overflow-anchor:visible,' + '.k-tool-group:visible .k-widget.k-colorpicker,' + '.k-tool-group:visible .k-selectbox,' + '.k-tool-group:visible .k-dropdown,' + '.k-tool-group:visible .k-combobox .k-input';
        var toolNamesByCssClass = {
            'k-i-sup-script': 'superscript',
            'k-i-sub-script': 'subscript',
            'k-i-align-left': 'justifyLeft',
            'k-i-align-center': 'justifyCenter',
            'k-i-align-right': 'justifyRight',
            'k-i-align-justify': 'justifyFull',
            'k-i-list-unordered': 'insertUnorderedList',
            'k-i-list-ordered': 'insertOrderedList',
            'k-i-login': 'import',
            'k-i-indent-increase': 'indent',
            'k-i-indent-decrease': 'outdent',
            'k-i-link-horizontal': 'createLink',
            'k-i-unlink-horizontal': 'unlink',
            'k-i-image': 'insertImage',
            'k-i-file-add': 'insertFile',
            'k-i-html': 'viewHtml',
            'k-i-foreground-color': 'foreColor',
            'k-i-paint': 'backColor',
            'k-i-table-insert': 'createTable',
            'k-i-table-column-insert-left': 'addColumnLeft',
            'k-i-table-column-insert-right': 'addColumnRight',
            'k-i-table-row-insert-above': 'addRowAbove',
            'k-i-table-row-insert-below': 'addRowBelow',
            'k-i-table-row-delete': 'deleteRow',
            'k-i-table-column-delete': 'deleteColumn',
            'k-i-table-properties': 'tableWizard',
            'k-i-table-wizard': 'tableWizardInsert',
            'k-i-clear-css': 'cleanFormatting'
        };
        var OverflowAnchorTool = Tool.extend({
            initialize: function (ui, options) {
                ui.attr({ unselectable: 'on' });
                var toolbar = options.editor.toolbar;
                ui.attr('aria-controls', options.editor.element.attr('id')).on('click', $.proxy(function () {
                    this.overflowPopup.toggle();
                }, toolbar));
            },
            options: { name: OVERFLOWANCHOR },
            command: $.noop,
            update: $.noop,
            destroy: $.noop
        });
        EditorUtils.registerTool(OVERFLOWANCHOR, new OverflowAnchorTool({
            key: '',
            ctrl: true,
            template: new ToolTemplate({ template: EditorUtils.overflowAnchorTemplate })
        }));
        var Toolbar = Widget.extend({
            init: function (element, options) {
                var that = this;
                options = extend({}, options, { name: 'EditorToolbar' });
                Widget.fn.init.call(that, element, options);
                if (options.popup) {
                    that._initPopup();
                }
                if (options.resizable && options.resizable.toolbar) {
                    that._resizeHandler = kendo.onResize(function () {
                        that.resize(true);
                    });
                    that.element.addClass('k-toolbar-resizable');
                }
            },
            events: ['execute'],
            groups: {
                basic: [
                    'bold',
                    'italic',
                    'underline',
                    'strikethrough'
                ],
                scripts: [
                    'subscript',
                    'superscript'
                ],
                alignment: [
                    'justifyLeft',
                    'justifyCenter',
                    'justifyRight',
                    'justifyFull'
                ],
                links: [
                    'insertImage',
                    'insertFile',
                    'createLink',
                    'unlink'
                ],
                lists: [
                    'insertUnorderedList',
                    'insertOrderedList',
                    'indent',
                    'outdent'
                ],
                tables: [
                    'createTable',
                    'addColumnLeft',
                    'addColumnRight',
                    'addRowAbove',
                    'addRowBelow',
                    'deleteRow',
                    'deleteColumn'
                ],
                advanced: [
                    'viewHtml',
                    'cleanFormatting',
                    'print',
                    'pdf',
                    'exportAs',
                    'import'
                ],
                fonts: [
                    'fontName',
                    'fontSize'
                ],
                colors: [
                    'foreColor',
                    'backColor'
                ]
            },
            overflowFlaseTools: [
                'formatting',
                'fontName',
                'fontSize',
                'foreColor',
                'backColor',
                'insertHtml'
            ],
            _initPopup: function () {
                var that = this;
                this.window = $(this.element).wrap('<div class=\'editorToolbarWindow k-header\' />').parent().prepend('<button class=\'k-button k-bare k-editortoolbar-dragHandle\'><span class=\'k-icon k-i-handler-drag\' /></button>').kendoWindow({
                    title: false,
                    resizable: false,
                    draggable: { dragHandle: '.k-editortoolbar-dragHandle' },
                    animation: {
                        open: { effects: 'fade:in' },
                        close: { effects: 'fade:out' }
                    },
                    minHeight: 42,
                    visible: false,
                    autoFocus: false,
                    actions: [],
                    dragend: function () {
                        this._moved = true;
                    }
                }).on('mousedown', function (e) {
                    if (!$(e.target).is('.k-icon')) {
                        that.preventPopupHide = true;
                    }
                }).on('focusout', function () {
                    that.options.editor.element.focusout();
                }).data('kendoWindow');
            },
            _toggleOverflowStyles: function (element, show) {
                element.find('> li').toggleClass('k-item k-state-default', show).find('.k-tool:not(.k-state-disabled),.k-overflow-button').toggleClass('k-overflow-button k-button', show);
            },
            _initOverflowPopup: function (ui) {
                var that = this;
                var popupTemplate = '<ul class=\'k-editor-overflow-popup k-overflow-container k-list-container\'></ul>';
                that.overflowPopup = $(popupTemplate).appendTo('body').kendoPopup({
                    anchor: ui,
                    origin: 'bottom right',
                    position: 'top right',
                    copyAnchorStyles: false,
                    open: function (e) {
                        if (this.element.is(':empty')) {
                            e.preventDefault();
                        }
                        that._toggleOverflowStyles(this.element, true);
                        ui.attr('aria-expanded', true);
                    },
                    close: function () {
                        ui.attr('aria-expanded', false);
                    },
                    activate: proxy(that.focusOverflowPopup, that)
                }).data('kendoPopup');
            },
            items: function () {
                var isResizable = this.options.resizable && this.options.resizable.toolbar, popup, result;
                result = this.element.children().find('> *, select');
                if (isResizable) {
                    popup = this.overflowPopup;
                    result = result.add(popup.element.children().find('> *'));
                }
                return result;
            },
            focused: function () {
                return this.element.find('.k-state-focused').length > 0 || this.preventPopupHide || this.overflowPopup && this.overflowPopup.visible();
            },
            toolById: function (name) {
                var id, tools = this.tools;
                for (id in tools) {
                    if (id.toLowerCase() == name) {
                        return tools[id];
                    }
                }
            },
            toolGroupFor: function (toolName) {
                var i, groups = this.groups;
                if (this.isCustomTool(toolName)) {
                    return 'custom';
                }
                for (i in groups) {
                    if ($.inArray(toolName, groups[i]) >= 0) {
                        return i;
                    }
                }
            },
            bindTo: function (editor) {
                var that = this, window = that.window;
                if (that._editor) {
                    that._editor.unbind('select', proxy(that.resize, that));
                }
                that._editor = editor;
                if (that.options.resizable && that.options.resizable.toolbar) {
                    editor.options.tools.push(OVERFLOWANCHOR);
                }
                that.tools = that.expandTools(editor.options.tools);
                that.render();
                that.element.find('.k-combobox .k-input').keydown(function (e) {
                    var combobox = $(this).closest('.k-combobox').data('kendoComboBox'), key = e.keyCode;
                    if (key == keys.RIGHT || key == keys.LEFT) {
                        combobox.close();
                    } else if (key == keys.DOWN) {
                        if (!combobox.dropDown.isOpened()) {
                            e.stopImmediatePropagation();
                            combobox.open();
                        }
                    }
                });
                that._attachEvents();
                that.items().each(function initializeTool() {
                    var toolName = that._toolName(this), tool = toolName !== 'moreVertical' ? that.tools[toolName] : that.tools.overflowAnchor, options = tool && tool.options, messages = editor.options.messages, description = options && options.tooltip || messages[toolName], ui = $(this);
                    if (!tool || !tool.initialize) {
                        return;
                    }
                    if (toolName == 'fontSize' || toolName == 'fontName') {
                        var inheritText = messages[toolName + 'Inherit'];
                        ui.find('input').val(inheritText).end().find('span.k-input').text(inheritText).end();
                    }
                    tool.initialize(ui, {
                        title: that._appendShortcutSequence(description, tool),
                        editor: that._editor
                    });
                    ui.closest('.k-widget', that.element).addClass('k-editor-widget');
                    ui.closest('.k-colorpicker', that.element).next('.k-colorpicker').addClass('k-editor-widget');
                });
                editor.bind('select', proxy(that.resize, that));
                that.update();
                if (window) {
                    window.wrapper.css({
                        top: '',
                        left: '',
                        width: ''
                    });
                }
            },
            show: function () {
                var that = this, window = that.window, editorOptions = that.options.editor, wrapper, editorElement, editorOffset, browser = kendo.support.browser;
                if (window) {
                    wrapper = window.wrapper;
                    editorElement = editorOptions.element;
                    if (!wrapper.is(':visible') || !that.window.options.visible) {
                        if (!wrapper[0].style.width) {
                            wrapper.width(this._getWindowWidth());
                        }
                        if (!window._moved) {
                            editorOffset = editorElement.offset();
                            wrapper.css({
                                top: Math.max(0, parseInt(editorOffset.top, 10) - outerHeight(wrapper) - parseInt(that.window.element.css('padding-bottom'), 10)),
                                left: Math.max(0, parseInt(editorOffset.left, 10))
                            });
                        }
                        if ((browser.msie || browser.edge) && that._overlaps(editorElement)) {
                            setTimeout(function () {
                                window.open();
                            }, 0);
                        } else {
                            window.open();
                        }
                    }
                }
            },
            _getWindowWidth: function () {
                var that = this, wrapper = that.window.wrapper, editorElement = that.options.editor.element;
                return outerWidth(editorElement) - parseInt(wrapper.css('border-left-width'), 10) - parseInt(wrapper.css('border-right-width'), 10);
            },
            _overlaps: function (box) {
                var toolbarWrapper = this.window.wrapper, toolbarWrapperOffset = toolbarWrapper.offset(), toolbarWrapperLeft = toolbarWrapperOffset.left, toolbarWrapperTop = toolbarWrapperOffset.top, boxOffset = box.offset(), boxOffsetLeft = boxOffset.left, boxOffsetTop = boxOffset.top;
                return !(boxOffsetLeft + box.width() < toolbarWrapperLeft || boxOffsetLeft > toolbarWrapperLeft + toolbarWrapper.width() || boxOffsetTop + box.height() < toolbarWrapperTop || boxOffsetTop > toolbarWrapperTop + toolbarWrapper.height());
            },
            hide: function () {
                if (this.window) {
                    this.window.close();
                }
            },
            focus: function () {
                var TABINDEX = 'tabIndex';
                var element = this.element;
                var tabIndex = this._editor.element.attr(TABINDEX);
                element.attr(TABINDEX, tabIndex || 0).focus().find(focusable).first().focus();
                if (!tabIndex && tabIndex !== 0) {
                    element.removeAttr(TABINDEX);
                }
            },
            focusOverflowPopup: function () {
                var TABINDEX = 'tabIndex';
                var element = this.overflowPopup.element;
                var tabIndex = this._editor.element.attr(TABINDEX);
                element.closest('.k-animation-container').addClass('k-overflow-wrapper');
                element.attr(TABINDEX, tabIndex || 0).find(focusable).first().focus();
                if (!tabIndex && tabIndex !== 0) {
                    element.removeAttr(TABINDEX);
                }
            },
            _appendShortcutSequence: function (localizedText, tool) {
                if (!tool.key) {
                    return localizedText;
                }
                var res = localizedText + ' (';
                if (tool.ctrl) {
                    res += 'Ctrl + ';
                }
                if (tool.shift) {
                    res += 'Shift + ';
                }
                if (tool.alt) {
                    res += 'Alt + ';
                }
                res += tool.key + ')';
                return res;
            },
            _nativeTools: [
                'insertLineBreak',
                'insertParagraph',
                'redo',
                'undo',
                'autoLink'
            ],
            tools: {},
            isCustomTool: function (toolName) {
                return !(toolName in kendo.ui.Editor.defaultTools);
            },
            expandTools: function (tools) {
                var currentTool, i, nativeTools = this._nativeTools, options, defaultTools = kendo.deepExtend({}, kendo.ui.Editor.defaultTools), result = {}, name;
                for (i = 0; i < tools.length; i++) {
                    currentTool = tools[i];
                    name = currentTool.name;
                    if ($.isPlainObject(currentTool)) {
                        if (name && defaultTools[name]) {
                            result[name] = extend({}, defaultTools[name]);
                            extend(result[name].options, currentTool);
                        } else {
                            options = extend({
                                cssClass: 'k-i-gear',
                                type: 'button',
                                title: ''
                            }, currentTool);
                            if (!options.name) {
                                options.name = 'custom';
                            }
                            options.cssClass = 'k-' + options.name;
                            if (!options.template && options.type == 'button') {
                                options.template = editorNS.EditorUtils.buttonTemplate;
                                options.title = options.title || options.tooltip;
                            }
                            result[name] = { options: options };
                        }
                    } else if (defaultTools[currentTool]) {
                        result[currentTool] = defaultTools[currentTool];
                    }
                }
                for (i = 0; i < nativeTools.length; i++) {
                    if (!result[nativeTools[i]]) {
                        result[nativeTools[i]] = defaultTools[nativeTools[i]];
                    }
                }
                return result;
            },
            render: function () {
                var that = this, tools = that.tools, options, template, toolElement, toolName, editorElement = that._editor.element, element = that.element.empty(), groupName, newGroupName, toolConfig = that._editor.options.tools, browser = kendo.support.browser, group, i, groupPosition = 0, resizable = that.options.resizable && that.options.resizable.toolbar, overflowFlaseTools = this.overflowFlaseTools;
                function stringify(template) {
                    var result;
                    if (template.getHtml) {
                        result = template.getHtml();
                    } else {
                        if (!$.isFunction(template)) {
                            template = kendo.template(template);
                        }
                        result = template(options);
                    }
                    return $.trim(result);
                }
                function endGroup() {
                    if (group.children().length) {
                        if (resizable) {
                            group.data('position', groupPosition);
                            groupPosition++;
                        }
                        group.appendTo(element);
                    }
                }
                function startGroup(toolName) {
                    if (toolName !== OVERFLOWANCHOR) {
                        group = $('<li class=\'k-tool-group\' role=\'presentation\' />');
                        group.data('overflow', $.inArray(toolName, overflowFlaseTools) === -1 ? true : false);
                    } else {
                        group = $('<li class=\'k-overflow-tools\' />');
                    }
                }
                element.empty();
                if (toolConfig.length) {
                    toolName = toolConfig[0].name || toolConfig[0];
                }
                startGroup(toolName, overflowFlaseTools);
                for (i = 0; i < toolConfig.length; i++) {
                    toolName = toolConfig[i].name || toolConfig[i];
                    options = tools[toolName] && tools[toolName].options;
                    if (!options && $.isPlainObject(toolName)) {
                        options = toolName;
                    }
                    template = options && options.template;
                    if (toolName == 'break') {
                        endGroup();
                        $('<li class=\'k-row-break\' />').appendTo(that.element);
                        startGroup(toolName, overflowFlaseTools);
                    }
                    if (!template) {
                        continue;
                    }
                    newGroupName = that.toolGroupFor(toolName);
                    if (groupName != newGroupName || toolName == OVERFLOWANCHOR) {
                        endGroup();
                        startGroup(toolName, overflowFlaseTools);
                        groupName = newGroupName;
                    }
                    if (toolName == OVERFLOWANCHOR) {
                        template.options.title = that.options.messages.overflowAnchor;
                    }
                    template = stringify(template);
                    toolElement = $(template).appendTo(group);
                    if (newGroupName == 'custom') {
                        endGroup();
                        startGroup(toolName, overflowFlaseTools);
                    }
                    if (options.exec && toolElement.hasClass('k-tool')) {
                        toolElement.click(proxy(options.exec, editorElement[0]));
                    }
                }
                endGroup();
                $(that.element).children(':has(> .k-tool)').addClass('k-button-group');
                if (that.options.popup && browser.msie && browser.version < 9) {
                    that.window.wrapper.find('*').attr('unselectable', 'on');
                }
                that.updateGroups();
                if (resizable) {
                    that._initOverflowPopup(that.element.find('.k-overflow-anchor'));
                }
                that.angular('compile', function () {
                    return { elements: that.element };
                });
            },
            updateGroups: function () {
                $(this.element).children().each(function () {
                    $(this).addClass('k-state-disabled');
                    $(this).children().filter(function () {
                        return !$(this).hasClass('k-state-disabled');
                    }).removeClass('k-group-end').first().addClass('k-group-start').end().last().addClass('k-group-end').end().parent().removeClass('k-state-disabled').css('display', '');
                });
            },
            decorateFrom: function (body) {
                this.items().filter('.k-decorated').each(function () {
                    var selectBox = $(this).data('kendoSelectBox');
                    if (selectBox) {
                        selectBox.decorate(body);
                    }
                });
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                var id, tools = this.tools;
                for (id in tools) {
                    if (tools[id].destroy) {
                        tools[id].destroy();
                    }
                }
                if (this.window) {
                    this.window.destroy();
                }
                if (this._resizeHandler) {
                    kendo.unbindResize(this._resizeHandler);
                }
                if (this.overflowPopup) {
                    this.overflowPopup.destroy();
                }
            },
            _attachEvents: function () {
                var that = this, popupElement = that.overflowPopup ? that.overflowPopup.element : $([]);
                that.attachToolsEvents(that.element.add(popupElement));
            },
            attachToolsEvents: function (element) {
                var that = this, buttons = '[role=button].k-tool', enabledButtons = buttons + ':not(.k-state-disabled)', disabledButtons = buttons + '.k-state-disabled', dropdown = '.k-dropdown', colorpicker = '.k-colorpicker', editorTools = [
                        buttons,
                        dropdown,
                        colorpicker
                    ].join(',');
                element.off(NS).on('mouseenter' + NS, enabledButtons, function () {
                    $(this).addClass('k-state-hover');
                }).on('mouseleave' + NS, enabledButtons, function () {
                    $(this).removeClass('k-state-hover');
                }).on('mousedown' + NS, editorTools, function (e) {
                    e.preventDefault();
                }).on('keydown' + NS, focusable, function (e) {
                    var current = this;
                    var resizable = that.options.resizable && that.options.resizable.toolbar;
                    var direction = kendo.support.isRtl(that.element) ? -1 : 1;
                    var focusableItems;
                    var focusElement, currentContainer, keyCode = e.keyCode;
                    function move(direction, container, constrain) {
                        var tools = container.find(focusable);
                        var index = tools.index(current) + direction;
                        if (constrain) {
                            index = Math.max(0, Math.min(tools.length - 1, index));
                        }
                        return tools[index];
                    }
                    if (keyCode == keys.RIGHT || keyCode == keys.LEFT) {
                        if (!$(current).is('.k-dropdown')) {
                            focusElement = move(keyCode == keys.RIGHT ? 1 * direction : -1 * direction, that.element, true);
                        } else {
                            focusElement = $(current);
                        }
                    } else if (resizable && (keyCode == keys.UP || keyCode == keys.DOWN)) {
                        focusElement = move(keyCode == keys.DOWN ? 1 : -1, that.overflowPopup.element, true);
                    } else if (keyCode == keys.HOME) {
                        focusElement = that.element.find(focusable)[0];
                        e.preventDefault();
                    } else if (keyCode == keys.END) {
                        focusableItems = that.element.find(focusable).filter(function () {
                            return $(this).css('visibility') !== 'hidden';
                        });
                        focusElement = focusableItems[focusableItems.length - 1];
                        e.preventDefault();
                    } else if (keyCode == keys.ESC) {
                        if (that.overflowPopup && that.overflowPopup.visible()) {
                            that.overflowPopup.close();
                        }
                        focusElement = that._editor;
                    } else if (keyCode == keys.TAB && !(e.ctrlKey || e.altKey)) {
                        if (resizable) {
                            currentContainer = $(current.parentElement).hasClass('k-overflow-tool-group') ? that.overflowPopup.element : that.element;
                        } else {
                            currentContainer = that.element;
                        }
                        if (e.shiftKey) {
                            focusElement = move(-1, currentContainer);
                        } else {
                            focusElement = move(1, currentContainer);
                            if (!focusElement || $(focusElement).closest('.k-overflow-tools').css('visibility') === 'hidden') {
                                focusElement = that._editor;
                            }
                        }
                    }
                    if (focusElement) {
                        e.preventDefault();
                        focusElement.focus();
                    }
                    if ((keyCode === keys.ENTER || keyCode === keys.SPACEBAR) && $(current).is('a') && !$(current).attr('href')) {
                        that._executeToolCommand(current, e);
                    }
                }).on('click' + NS, enabledButtons, function (e) {
                    that._executeToolCommand(this, e);
                }).on('click' + NS, disabledButtons, function (e) {
                    e.preventDefault();
                });
            },
            _executeToolCommand: function (toolElement, e) {
                var that = this;
                var button = $(toolElement);
                e.preventDefault();
                e.stopPropagation();
                button.removeClass('k-state-hover');
                if (!button.is('[data-popup]')) {
                    that._editor.exec(that._toolName(toolElement));
                }
            },
            _toolName: function (element) {
                if (!element) {
                    return;
                }
                var className = element.className;
                if (/k-tool\b/i.test(className)) {
                    className = element.firstChild.className;
                }
                var tool = $.grep(className.split(' '), function (x) {
                    return !/^k-(widget|tool|tool-icon|icon|state-hover|header|combobox|dropdown|selectbox|colorpicker)$/i.test(x);
                });
                if (tool[0]) {
                    var toolname = tool[0];
                    if (toolNamesByCssClass[toolname]) {
                        toolname = toolNamesByCssClass[toolname];
                    }
                    if (toolname.indexOf('k-i-') >= 0) {
                        return kendo.toCamelCase(toolname.substring(toolname.indexOf('k-i-') + 4));
                    } else {
                        return toolname.substring(toolname.lastIndexOf('-') + 1);
                    }
                }
                return 'custom';
            },
            refreshTools: function () {
                var that = this, editor = that._editor, range = editor.getRange(), nodes = editorNS.RangeUtils.textNodes(range), immutables = editor.options.immutables, immutablesContext = that._immutablesContext(range);
                nodes = editorNS.Dom.filterBy(nodes, editorNS.Dom.htmlIndentSpace, true);
                if (!nodes.length) {
                    nodes = [range.startContainer];
                }
                that.items().each(function () {
                    var tool = that.tools[that._toolName(this)];
                    if (tool) {
                        var ui = $(this);
                        if (tool.update) {
                            tool.update(ui, nodes);
                        }
                        if (immutables) {
                            that._updateImmutablesState(tool, ui, immutablesContext);
                        }
                    }
                });
                this.update();
            },
            _immutablesContext: function (range) {
                if (this._editor.options.immutables) {
                    if (range.collapsed) {
                        return editorNS.Immutables.immutablesContext(range);
                    } else {
                        return editorNS.RangeUtils.editableTextNodes(range).length === 0;
                    }
                }
            },
            _updateImmutablesState: function (tool, ui, immutablesContext) {
                var name = tool.name;
                var uiElement = ui;
                var trackImmutables = tool.options.trackImmutables;
                if (trackImmutables === undefined) {
                    trackImmutables = $.inArray(name, editorNS.Immutables.toolsToBeUpdated) > -1;
                }
                if (trackImmutables) {
                    var display = immutablesContext ? 'none' : '';
                    if (!ui.is('.k-tool')) {
                        var uiData = ui.data();
                        for (var key in uiData) {
                            if (key.match(/^kendo[A-Z][a-zA-Z]*/)) {
                                var widget = uiData[key];
                                uiElement = widget.wrapper;
                                break;
                            }
                        }
                    }
                    uiElement.css('display', display);
                    var groupUi = uiElement.closest('li');
                    if (groupUi.children(':visible').length === 0) {
                        groupUi.css('display', display);
                    }
                }
            },
            update: function () {
                this.updateGroups();
            },
            _resize: function (e) {
                var containerWidth = e.width;
                var resizable = this.options.resizable && this.options.resizable.toolbar;
                var popup = this.overflowPopup;
                var editorElement = this.options.editor.element;
                var toolbarWindow = this.window;
                this.refreshTools();
                if (!resizable) {
                    return;
                }
                if (toolbarWindow) {
                    toolbarWindow.wrapper.width(this._getWindowWidth());
                    if (!toolbarWindow._moved) {
                        toolbarWindow.wrapper.css({ left: Math.max(0, parseInt(editorElement.offset().left, 10)) });
                    }
                }
                if (popup.visible()) {
                    popup.close(true);
                }
                this._refreshWidths();
                this._shrink(containerWidth);
                this._stretch(containerWidth);
                this._toggleOverflowStyles(this.element, false);
                this._toggleOverflowStyles(this.overflowPopup.element, true);
                this.element.children('li.k-overflow-tools').css('visibility', popup.element.is(':empty') ? 'hidden' : 'visible');
            },
            _refreshWidths: function () {
                this.element.children('li').each(function (idx, element) {
                    var group = $(element);
                    group.data('outerWidth', outerWidth(group, true));
                });
            },
            _shrink: function (width) {
                var group, visibleGroups;
                if (width < this._groupsWidth()) {
                    visibleGroups = this._visibleGroups().filter(':not(.k-overflow-tools)');
                    for (var i = visibleGroups.length - 1; i >= 0; i--) {
                        group = visibleGroups.eq(i);
                        if (width > this._groupsWidth()) {
                            break;
                        } else {
                            this._hideGroup(group);
                        }
                    }
                }
            },
            _stretch: function (width) {
                var group, hiddenGroups;
                if (width > this._groupsWidth()) {
                    hiddenGroups = this._hiddenGroups();
                    for (var i = 0; i < hiddenGroups.length; i++) {
                        group = hiddenGroups.eq(i);
                        if (width < this._groupsWidth() || !this._showGroup(group, width)) {
                            break;
                        }
                    }
                }
            },
            _hiddenGroups: function () {
                var popup = this.overflowPopup;
                var hiddenGroups = this.element.children('li.k-tool-group').filter(':hidden');
                hiddenGroups = hiddenGroups.add(popup.element.children('li'));
                hiddenGroups.sort(function (a, b) {
                    return $(a).data('position') > $(b).data('position') ? 1 : -1;
                });
                return hiddenGroups;
            },
            _visibleGroups: function () {
                return this.element.children('li.k-tool-group, li.k-overflow-tools').filter(':visible');
            },
            _groupsWidth: function () {
                var width = 0;
                this._visibleGroups().each(function () {
                    width += $(this).data('outerWidth');
                });
                return Math.ceil(width);
            },
            _hideGroup: function (group) {
                if (group.data('overflow')) {
                    var popup = this.overflowPopup;
                    group.detach().prependTo(popup.element).addClass('k-overflow-tool-group');
                } else {
                    group.hide();
                }
            },
            _showGroup: function (group, width) {
                var position, previous;
                if (group.length && width > this._groupsWidth() + group.data('outerWidth') && !group.hasClass('k-state-disabled')) {
                    if (group.hasClass('k-overflow-tool-group')) {
                        position = group.data('position');
                        if (position === 0) {
                            group.detach().prependTo(this.element);
                        } else {
                            previous = this.element.children().filter(function (idx, element) {
                                return $(element).data('position') === position - 1;
                            });
                            group.detach().insertAfter(previous);
                        }
                        group.removeClass('k-overflow-tool-group');
                    } else {
                        group.show();
                    }
                    return true;
                }
                return false;
            }
        });
        $.extend(editorNS, { Toolbar: Toolbar });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/viewhtml', ['editor/command'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, dom = Editor.Dom;
        var ViewHtmlCommand = Command.extend({
            init: function (options) {
                var cmd = this;
                cmd.options = options;
                Command.fn.init.call(cmd, options);
                cmd.attributes = null;
                cmd.async = true;
            },
            exec: function () {
                var that = this, editor = that.editor, options = editor.options, messages = editor.options.messages, dialog = $(kendo.template(ViewHtmlCommand.template)(messages)).appendTo(document.body), textarea = '.k-editor-textarea', content, comments;
                options.serialization.immutables = editor.immutables;
                comments = dom.getAllComments(editor.body);
                content = EditorUtils.cacheComments(editor.value(), comments);
                content = ViewHtmlCommand.indent(content);
                content = EditorUtils.retrieveComments(content, comments);
                options.serialization.immutables = undefined;
                function apply(e) {
                    options.deserialization.immutables = editor.immutables;
                    editor.value(dialog.find(textarea).val());
                    options.deserialization.immutables = undefined;
                    close(e);
                    if (that.change) {
                        that.change();
                    }
                    editor.trigger('change');
                }
                function close(e) {
                    e.preventDefault();
                    dialog.data('kendoWindow').destroy();
                    if (editor.immutables) {
                        editor.immutables.serializedImmutables = {};
                    }
                    editor.focus();
                }
                this.createDialog(dialog, {
                    title: messages.viewHtml,
                    close: close,
                    visible: false
                }).find(textarea).val(content).end().find('.k-dialog-update').click(apply).end().find('.k-dialog-close').click(close).end().data('kendoWindow').center().open();
                dialog.find(textarea).focus();
            }
        });
        extend(ViewHtmlCommand, {
            template: '<div class=\'k-editor-dialog k-popup-edit-form k-viewhtml-dialog\'>' + '<div class=\'k-edit-form-container\'></div>' + '<textarea class=\'k-editor-textarea k-input\'></textarea>' + '<div class=\'k-edit-buttons k-state-default\'>' + '<button class=\'k-dialog-update k-button k-primary\'>#: dialogUpdate #</button>' + '<button class=\'k-dialog-close k-button\'>#: dialogCancel #</button>' + '</div>' + '</div>' + '</div>',
            indent: function (content) {
                return content.replace(/<\/(p|li|ul|ol|h[1-6]|table|tr|td|th)>/gi, '</$1>\n').replace(/<(ul|ol)([^>]*)><li/gi, '<$1$2>\n<li').replace(/<br \/>/gi, '<br />\n').replace(/\n$/, '');
            }
        });
        kendo.ui.editor.ViewHtmlCommand = ViewHtmlCommand;
        Editor.EditorUtils.registerTool('viewHtml', new Tool({
            command: ViewHtmlCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'View HTML'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/format', ['editor/command'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, Tool = Editor.Tool, Command = Editor.Command, EditorUtils = Editor.EditorUtils;
        var FormatCommand = Command.extend({
            init: function (options) {
                options.formatter = options.formatter();
                var finder = options.formatter.finder;
                if (finder && EditorUtils.formatByName('immutable', finder.format)) {
                    finder._initOptions({ immutables: options.immutables });
                }
                Command.fn.init.call(this, options);
            }
        });
        var FormatTool = Tool.extend({
            init: function (options) {
                Tool.fn.init.call(this, options);
            },
            command: function (commandArguments) {
                var that = this;
                return new FormatCommand(extend(commandArguments, { formatter: that.options.formatter }));
            },
            update: function (ui, nodes) {
                var isFormatted = this.options.finder.isFormatted(nodes);
                ui.toggleClass('k-state-selected', isFormatted);
                ui.attr('aria-pressed', isFormatted);
            }
        });
        $.extend(Editor, {
            FormatCommand: FormatCommand,
            FormatTool: FormatTool
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/inlineformat', ['editor/plugins/format'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, Editor = kendo.ui.editor, formats = kendo.ui.Editor.fn.options.formats, EditorUtils = Editor.EditorUtils, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, FormatTool = Editor.FormatTool, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, extend = $.extend, registerTool = Editor.EditorUtils.registerTool, registerFormat = Editor.EditorUtils.registerFormat, MOUSEDOWN_NS = 'mousedown.kendoEditor', KEYDOWN_NS = 'keydown.kendoEditor', KMARKER = 'k-marker';
        var InlineFormatFinder = Class.extend({
            init: function (format) {
                this.format = format;
            },
            numberOfSiblings: function (referenceNode) {
                var textNodesCount = 0, elementNodesCount = 0, markerCount = 0, parentNode = referenceNode.parentNode, node;
                for (node = parentNode.firstChild; node; node = node.nextSibling) {
                    if (node != referenceNode) {
                        if (node.className == KMARKER) {
                            markerCount++;
                        } else if (node.nodeType == 3) {
                            textNodesCount++;
                        } else {
                            elementNodesCount++;
                        }
                    }
                }
                if (markerCount > 1 && parentNode.firstChild.className == KMARKER && parentNode.lastChild.className == KMARKER) {
                    return 0;
                } else {
                    return elementNodesCount + textNodesCount;
                }
            },
            findSuitable: function (sourceNode, skip) {
                if (!skip && this.numberOfSiblings(sourceNode) > 0) {
                    return null;
                }
                var node = sourceNode.parentNode;
                var tags = this.format[0].tags;
                while (!dom.ofType(node, tags)) {
                    if (this.numberOfSiblings(node) > 0) {
                        return null;
                    }
                    node = node.parentNode;
                }
                return node;
            },
            findFormat: function (sourceNode) {
                var format = this.format, attrEquals = dom.attrEquals, i, len, node, tags, attributes;
                for (i = 0, len = format.length; i < len; i++) {
                    node = sourceNode;
                    tags = format[i].tags;
                    attributes = format[i].attr;
                    if (node && dom.ofType(node, tags) && attrEquals(node, attributes)) {
                        return node;
                    }
                    while (node) {
                        node = dom.parentOfType(node, tags);
                        if (node && attrEquals(node, attributes)) {
                            return node;
                        }
                    }
                }
                return null;
            },
            isFormatted: function (nodes) {
                var i, len;
                for (i = 0, len = nodes.length; i < len; i++) {
                    if (this.findFormat(nodes[i])) {
                        return true;
                    }
                }
                return false;
            }
        });
        var InlineFormatter = Class.extend({
            init: function (format, values) {
                this.finder = new InlineFormatFinder(format);
                this.attributes = extend({}, format[0].attr, values);
                this.tag = format[0].tags[0];
            },
            wrap: function (node) {
                return dom.wrap(node, dom.create(node.ownerDocument, this.tag, this.attributes));
            },
            activate: function (range, nodes) {
                if (this.finder.isFormatted(nodes)) {
                    this.split(range);
                    this.remove(nodes);
                } else {
                    this.apply(nodes);
                }
            },
            toggle: function (range) {
                var textNodes = this.immutables() ? RangeUtils.editableTextNodes : RangeUtils.textNodes;
                var nodes = textNodes(range);
                if (nodes.length > 0) {
                    this.activate(range, nodes);
                }
            },
            immutables: function () {
                return this.editor && this.editor.options.immutables;
            },
            apply: function (nodes) {
                var formatNodes = [];
                var i, l, node, formatNode;
                if (nodes.length > 1) {
                    for (i = 0, l = nodes.length; i < l; i++) {
                        node = nodes[i];
                        formatNode = this.format(node, true);
                        formatNodes.push(formatNode);
                    }
                } else {
                    node = nodes[0];
                    formatNode = this.format(node, false);
                }
                this.consolidate(formatNodes);
            },
            format: function (node, outerMostInline) {
                var formatNode = this.finder.findSuitable(node);
                var attributes = this.attributes;
                var styleAttr = attributes ? attributes.style || {} : {};
                if (formatNode) {
                    if (dom.is(formatNode, 'font')) {
                        if (styleAttr.color) {
                            formatNode.removeAttribute('color');
                        }
                        if (styleAttr.fontName) {
                            formatNode.removeAttribute('face');
                        }
                        if (styleAttr.fontSize) {
                            formatNode.removeAttribute('size');
                        }
                    }
                    dom.attr(formatNode, attributes);
                } else {
                    while (!dom.isBlock(node.parentNode) && node.parentNode.childNodes.length == 1 && node.parentNode.contentEditable !== 'true' && outerMostInline) {
                        node = node.parentNode;
                    }
                    formatNode = this.wrap(node);
                }
                return formatNode;
            },
            remove: function (nodes) {
                var i, l, formatNode;
                for (i = 0, l = nodes.length; i < l; i++) {
                    formatNode = this.finder.findFormat(nodes[i]);
                    if (formatNode) {
                        if (this.attributes && this.attributes.style) {
                            dom.unstyle(formatNode, this.attributes.style);
                            if (!formatNode.style.cssText && !formatNode.attributes['class']) {
                                dom.unwrap(formatNode);
                            }
                        } else {
                            dom.unwrap(formatNode);
                        }
                    }
                }
            },
            split: function (range) {
                var nodes = RangeUtils.textNodes(range);
                var l = nodes.length;
                var i, formatNode;
                if (l > 0) {
                    for (i = 0; i < l; i++) {
                        formatNode = this.finder.findFormat(nodes[i]);
                        if (formatNode) {
                            RangeUtils.split(range, formatNode, true);
                        }
                    }
                }
            },
            consolidate: function (nodes) {
                var node, last;
                while (nodes.length > 1) {
                    node = nodes.pop();
                    last = nodes[nodes.length - 1];
                    if (node.previousSibling && node.previousSibling.className == KMARKER) {
                        last.appendChild(node.previousSibling);
                    }
                    if (node.tagName == last.tagName && node.previousSibling == last && node.style.cssText == last.style.cssText && node.className === last.className) {
                        while (node.firstChild) {
                            last.appendChild(node.firstChild);
                        }
                        dom.remove(node);
                    }
                }
            }
        });
        var GreedyInlineFormatFinder = InlineFormatFinder.extend({
            init: function (format, greedyProperty) {
                this.format = format;
                this.greedyProperty = greedyProperty;
                InlineFormatFinder.fn.init.call(this, format);
            },
            getInlineCssValue: function (node) {
                var attributes = node.attributes;
                var trim = $.trim;
                var i, l, attribute, name, attributeValue, css, pair, cssIndex, len;
                var propertyAndValue, property, value;
                if (!attributes) {
                    return;
                }
                for (i = 0, l = attributes.length; i < l; i++) {
                    attribute = attributes[i];
                    name = attribute.nodeName;
                    attributeValue = attribute.nodeValue;
                    if (attribute.specified && name == 'style') {
                        css = trim(attributeValue || node.style.cssText).split(';');
                        for (cssIndex = 0, len = css.length; cssIndex < len; cssIndex++) {
                            pair = css[cssIndex];
                            if (pair.length) {
                                propertyAndValue = pair.split(':');
                                property = trim(propertyAndValue[0].toLowerCase());
                                value = trim(propertyAndValue[1]);
                                if (property != this.greedyProperty) {
                                    continue;
                                }
                                return property.indexOf('color') >= 0 ? dom.toHex(value) : value;
                            }
                        }
                    }
                }
            },
            getFormatInner: function (node) {
                var $node = $(dom.isDataNode(node) ? node.parentNode : node);
                var parents = $node.parentsUntil('[contentEditable]').addBack().toArray().reverse();
                var i, len, value;
                for (i = 0, len = parents.length; i < len; i++) {
                    value = this.greedyProperty == 'className' ? parents[i].className : this.getInlineCssValue(parents[i]);
                    if (value) {
                        return value;
                    }
                }
                return 'inherit';
            },
            getFormat: function (nodes) {
                var result = this.getFormatInner(nodes[0]), i, len;
                for (i = 1, len = nodes.length; i < len; i++) {
                    if (result != this.getFormatInner(nodes[i])) {
                        return '';
                    }
                }
                return result;
            },
            isFormatted: function (nodes) {
                return this.getFormat(nodes) !== '';
            }
        });
        var GreedyInlineFormatter = InlineFormatter.extend({
            init: function (format, values, greedyProperty) {
                InlineFormatter.fn.init.call(this, format, values);
                this.values = values;
                this.finder = new GreedyInlineFormatFinder(format, greedyProperty);
                if (greedyProperty) {
                    this.greedyProperty = kendo.toCamelCase(greedyProperty);
                }
            },
            activate: function (range, nodes) {
                var greedyProperty = this.greedyProperty;
                var action = 'apply';
                this.split(range);
                if (greedyProperty && this.values.style[greedyProperty] == 'inherit') {
                    action = 'remove';
                }
                this[action](nodes);
            }
        });
        var InlineFormatTool = FormatTool.extend({
            init: function (options) {
                FormatTool.fn.init.call(this, extend(options, {
                    finder: new InlineFormatFinder(options.format),
                    formatter: function () {
                        return new InlineFormatter(options.format);
                    }
                }));
            }
        });
        var DelayedExecutionTool = Tool.extend({
            update: function (ui, nodes) {
                var list = ui.data(this.type);
                list.close();
                list.value(this.finder.getFormat(nodes));
            }
        });
        var FontTool = DelayedExecutionTool.extend({
            init: function (options) {
                Tool.fn.init.call(this, options);
                this.type = kendo.support.browser.msie || kendo.support.touch ? 'kendoDropDownList' : 'kendoComboBox';
                this.format = [{
                        tags: [
                            'span',
                            'font'
                        ]
                    }];
                this.finder = new GreedyInlineFormatFinder(this.format, options.cssAttr);
            },
            command: function (commandArguments) {
                var options = this.options, format = this.format, style = {};
                return new Editor.FormatCommand(extend(commandArguments, {
                    formatter: function () {
                        style[options.domAttr] = commandArguments.value;
                        return new GreedyInlineFormatter(format, { style: style }, options.cssAttr);
                    }
                }));
            },
            initialize: function (ui, initOptions) {
                var editor = initOptions.editor, options = this.options, toolName = options.name, dataSource, range, defaultValue = [];
                if (options.defaultValue) {
                    defaultValue = [{
                            text: editor.options.messages[options.defaultValue[0].text],
                            value: options.defaultValue[0].value
                        }];
                }
                dataSource = defaultValue.concat(options.items ? options.items : editor.options[toolName] || []);
                ui.attr({ title: initOptions.title });
                ui[this.type]({
                    dataTextField: 'text',
                    dataValueField: 'value',
                    dataSource: dataSource,
                    change: function () {
                        editor._range = range;
                        Tool.exec(editor, toolName, this.value());
                    },
                    close: function () {
                        setTimeout(function () {
                            editor._deleteSavedRange();
                        }, 0);
                    },
                    highlightFirst: false
                });
                ui.closest('.k-widget').removeClass('k-' + toolName).find('*').addBack().attr('unselectable', 'on');
                var widget = ui.data(this.type);
                widget.value('inherit');
                widget.wrapper.on(MOUSEDOWN_NS, '.k-select,.k-input', function () {
                    var newRange = editor.getRange();
                    range = editor._containsRange(newRange) ? newRange : range;
                }).on(KEYDOWN_NS, function (e) {
                    if (e.keyCode === kendo.keys.ENTER) {
                        editor._deleteSavedRange();
                        e.preventDefault();
                    }
                });
            }
        });
        var ColorTool = Tool.extend({
            init: function (options) {
                Tool.fn.init.call(this, options);
                this.format = [{
                        tags: [
                            'span',
                            'font'
                        ]
                    }];
                this.finder = new GreedyInlineFormatFinder(this.format, options.cssAttr);
            },
            options: { palette: 'websafe' },
            update: function () {
                this._widget.close();
            },
            command: function (commandArguments) {
                var options = this.options, format = this.format, style = {};
                return new Editor.FormatCommand(extend(commandArguments, {
                    formatter: function () {
                        style[options.domAttr] = commandArguments.value;
                        return new GreedyInlineFormatter(format, { style: style }, options.cssAttr);
                    }
                }));
            },
            initialize: function (ui, initOptions) {
                var that = this, editor = initOptions.editor, toolName = this.name, options = extend({}, ColorTool.fn.options, this.options), palette = options.palette, columns = options.columns;
                ui = this._widget = new kendo.ui.ColorPicker(ui, {
                    toolIcon: 'k-icon k-i-' + EditorUtils.getToolCssClass(options.name),
                    palette: palette,
                    columns: columns,
                    change: function () {
                        var color = ui.value();
                        if (kendo.support.browser.msie && that.storedRange && that._inputFocused) {
                            editor.selectRange(that.storedRange);
                        }
                        if (color) {
                            Tool.exec(editor, toolName, color);
                        }
                        delete that.storedRange;
                        delete that._inputFocused;
                        editor.focus();
                    },
                    open: function (e) {
                        var picker = e.sender;
                        that.storedRange = editor.getRange();
                        picker._popup.element.on(MOUSEDOWN_NS, function (e) {
                            if (!$(e.target).is('input.k-color-value')) {
                                e.preventDefault();
                            }
                        });
                        if (!picker._popup.element.is('[unselectable=\'on\']')) {
                            picker._popup.element.attr({ unselectable: 'on' }).find('*:not(input)').attr('unselectable', 'on').end().find('input').on('focus', function () {
                                that._inputFocused = true;
                            });
                        }
                    },
                    close: function (e) {
                        e.sender._popup.element.off(MOUSEDOWN_NS);
                        if (kendo.support.browser.msie && that.storedRange && that._inputFocused) {
                            editor.selectRange(that.storedRange);
                        }
                    },
                    activate: function (e) {
                        e.preventDefault();
                        if (e.sender._value.toCssRgba() === 'rgba(255, 255, 255, 0)') {
                            return;
                        }
                        ui.trigger('change');
                    }
                });
                ui.wrapper.attr({
                    title: initOptions.title,
                    unselectable: 'on'
                }).find('*:not(input)').attr('unselectable', 'on');
                ui.value('transparent');
            }
        });
        extend(Editor, {
            InlineFormatFinder: InlineFormatFinder,
            InlineFormatter: InlineFormatter,
            DelayedExecutionTool: DelayedExecutionTool,
            GreedyInlineFormatFinder: GreedyInlineFormatFinder,
            GreedyInlineFormatter: GreedyInlineFormatter,
            InlineFormatTool: InlineFormatTool,
            FontTool: FontTool,
            ColorTool: ColorTool
        });
        registerFormat('bold', [
            {
                tags: [
                    'strong',
                    'b'
                ]
            },
            {
                tags: ['span'],
                attr: { style: { fontWeight: 'bold' } }
            }
        ]);
        registerTool('bold', new InlineFormatTool({
            key: 'B',
            ctrl: true,
            format: formats.bold,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Bold'
            })
        }));
        registerFormat('italic', [
            {
                tags: [
                    'em',
                    'i'
                ]
            },
            {
                tags: ['span'],
                attr: { style: { fontStyle: 'italic' } }
            }
        ]);
        registerTool('italic', new InlineFormatTool({
            key: 'I',
            ctrl: true,
            format: formats.italic,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Italic'
            })
        }));
        registerFormat('underline', [
            {
                tags: ['span'],
                attr: { style: { textDecoration: 'underline' } }
            },
            { tags: ['u'] }
        ]);
        registerTool('underline', new InlineFormatTool({
            key: 'U',
            ctrl: true,
            format: formats.underline,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Underline'
            })
        }));
        registerFormat('strikethrough', [
            {
                tags: [
                    'del',
                    'strike'
                ]
            },
            {
                tags: ['span'],
                attr: { style: { textDecoration: 'line-through' } }
            }
        ]);
        registerTool('strikethrough', new InlineFormatTool({
            format: formats.strikethrough,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Strikethrough'
            })
        }));
        registerFormat('superscript', [{ tags: ['sup'] }]);
        registerTool('superscript', new InlineFormatTool({
            format: formats.superscript,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Superscript'
            })
        }));
        registerFormat('subscript', [{ tags: ['sub'] }]);
        registerTool('subscript', new InlineFormatTool({
            format: formats.subscript,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Subscript'
            })
        }));
        registerTool('foreColor', new ColorTool({
            cssAttr: 'color',
            domAttr: 'color',
            name: 'foreColor',
            template: new ToolTemplate({
                template: EditorUtils.colorPickerTemplate,
                title: 'Color'
            })
        }));
        registerTool('backColor', new ColorTool({
            cssAttr: 'background-color',
            domAttr: 'backgroundColor',
            name: 'backColor',
            template: new ToolTemplate({
                template: EditorUtils.colorPickerTemplate,
                title: 'Background Color'
            })
        }));
        registerTool('fontName', new FontTool({
            cssAttr: 'font-family',
            domAttr: 'fontFamily',
            name: 'fontName',
            defaultValue: [{
                    text: 'fontNameInherit',
                    value: 'inherit'
                }],
            template: new ToolTemplate({
                template: EditorUtils.comboBoxTemplate,
                title: 'Font Name'
            })
        }));
        registerTool('fontSize', new FontTool({
            cssAttr: 'font-size',
            domAttr: 'fontSize',
            name: 'fontSize',
            defaultValue: [{
                    text: 'fontSizeInherit',
                    value: 'inherit'
                }],
            template: new ToolTemplate({
                template: EditorUtils.comboBoxTemplate,
                title: 'Font Size'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/link', ['editor/plugins/inlineformat'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, Class = kendo.Class, extend = $.extend, proxy = $.proxy, Editor = kendo.ui.editor, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, InlineFormatter = Editor.InlineFormatter, InlineFormatFinder = Editor.InlineFormatFinder, textNodes = RangeUtils.textNodes, editableTextNodes = RangeUtils.editableTextNodes, registerTool = Editor.EditorUtils.registerTool, keys = kendo.keys;
        var HTTP_PROTOCOL = 'http://';
        var protocolRegExp = /^\w*:\/\//;
        var endLinkCharsRegExp = /[\w\/\$\-_\*\?]/i;
        var LinkFormatFinder = Class.extend({
            findSuitable: function (sourceNode) {
                return dom.parentOfType(sourceNode, ['a']);
            }
        });
        var LinkFormatter = Class.extend({
            init: function () {
                this.finder = new LinkFormatFinder();
            },
            apply: function (range, attributes) {
                var nodes = this.immutables ? editableTextNodes(range) : textNodes(range);
                var markers, doc, formatter, a, parent;
                if (attributes.innerText) {
                    doc = RangeUtils.documentFromRange(range);
                    markers = RangeUtils.getMarkers(range);
                    range.deleteContents();
                    a = dom.create(doc, 'a', attributes);
                    range.insertNode(a);
                    parent = a.parentNode;
                    if (dom.name(parent) == 'a') {
                        dom.insertAfter(a, parent);
                    }
                    if (dom.emptyNode(parent)) {
                        dom.remove(parent);
                    }
                    var ref = a;
                    for (var i = 0; i < markers.length; i++) {
                        dom.insertAfter(markers[i], ref);
                        ref = markers[i];
                    }
                    if (markers.length) {
                        dom.insertBefore(doc.createTextNode('\uFEFF'), markers[1] || markers[0]);
                        dom.insertAfter(doc.createTextNode('\uFEFF'), markers[1] || markers[0]);
                        range.setStartBefore(markers[0]);
                        range.setEndAfter(markers[markers.length - 1]);
                    }
                } else {
                    formatter = new InlineFormatter([{ tags: ['a'] }], attributes);
                    formatter.finder = this.finder;
                    formatter.apply(nodes);
                }
            }
        });
        var UnlinkCommand = Command.extend({
            init: function (options) {
                var that = this;
                options.formatter = {
                    toggle: function (range) {
                        var nodes = that.immutables() ? editableTextNodes(range) : textNodes(range);
                        new InlineFormatter([{ tags: ['a'] }]).remove(nodes);
                    }
                };
                this.options = options;
                Command.fn.init.call(this, options);
            }
        });
        var LinkCommand = Command.extend({
            init: function (options) {
                var that;
                this.options = options;
                Command.fn.init.call(this, options);
                this.formatter = new LinkFormatter();
                if (!options.url) {
                    this.attributes = null;
                    this.async = true;
                } else {
                    this.exec = function () {
                        this.formatter.immutables = that && that.immutables();
                        this.formatter.apply(options.range, {
                            href: options.url,
                            innerText: options.text || options.url,
                            target: options.target
                        });
                    };
                }
            },
            _dialogTemplate: function () {
                return kendo.template('<div class="k-editor-dialog k-popup-edit-form">' + '<div class="k-edit-form-container">' + '<div class=\'k-edit-label\'>' + '<label for=\'k-editor-link-url\'>#: messages.linkWebAddress #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type=\'text\' class=\'k-textbox\' id=\'k-editor-link-url\'>' + '</div>' + '<div class=\'k-edit-label k-editor-link-text-row\'>' + '<label for=\'k-editor-link-text\'>#: messages.linkText #</label>' + '</div>' + '<div class=\'k-edit-field k-editor-link-text-row\'>' + '<input type=\'text\' class=\'k-textbox\' id=\'k-editor-link-text\'>' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for=\'k-editor-link-title\'>#: messages.linkToolTip #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type=\'text\' class=\'k-textbox\' id=\'k-editor-link-title\'>' + '</div>' + '<div class=\'k-edit-label\'></div>' + '<div class=\'k-edit-field\'>' + '<input type=\'checkbox\' class=\'k-checkbox\' id=\'k-editor-link-target\'>' + '<label for=\'k-editor-link-target\' class=\'k-checkbox-label\'>#: messages.linkOpenInNewWindow #</label>' + '</div>' + '<div class=\'k-edit-buttons k-state-default\'>' + '<button class="k-dialog-insert k-button k-primary">#: messages.dialogInsert #</button>' + '<button class="k-dialog-close k-button">#: messages.dialogCancel #</button>' + '</div>' + '</div>' + '</div>')({ messages: this.editor.options.messages });
            },
            exec: function () {
                var messages = this.editor.options.messages;
                this._initialText = '';
                this._range = this.lockRange(true);
                this.formatter.immutables = this.immutables();
                var nodes = textNodes(this._range);
                var a = nodes.length ? this.formatter.finder.findSuitable(nodes[0]) : null;
                var img = nodes.length && dom.name(nodes[0]) == 'img';
                var dialog = this.createDialog(this._dialogTemplate(), {
                    title: messages.createLink,
                    close: proxy(this._close, this),
                    visible: false
                });
                if (a) {
                    this._range.selectNodeContents(a);
                    nodes = textNodes(this._range);
                }
                this._initialText = this.linkText(nodes);
                dialog.find('.k-dialog-insert').click(proxy(this._apply, this)).end().find('.k-dialog-close').click(proxy(this._close, this)).end().find('.k-edit-field input').keydown(proxy(this._keydown, this)).end().find('#k-editor-link-url').val(this.linkUrl(a)).end().find('#k-editor-link-text').val(this._initialText).end().find('#k-editor-link-title').val(a ? a.title : '').end().find('#k-editor-link-target').attr('checked', a ? a.target == '_blank' : false).end().find('.k-editor-link-text-row').toggle(!img);
                this._dialog = dialog.data('kendoWindow').center().open();
                $('#k-editor-link-url', dialog).focus().select();
            },
            _keydown: function (e) {
                var keys = kendo.keys;
                if (e.keyCode == keys.ENTER) {
                    this._apply(e);
                } else if (e.keyCode == keys.ESC) {
                    this._close(e);
                }
            },
            _apply: function (e) {
                var element = this._dialog.element;
                var href = $('#k-editor-link-url', element).val();
                var title, text, target;
                var textInput = $('#k-editor-link-text', element);
                if (href && href != HTTP_PROTOCOL) {
                    if (href.indexOf('@') > 0 && !/^(\w+:)|(\/\/)/i.test(href)) {
                        href = 'mailto:' + href;
                    }
                    this.attributes = { href: href };
                    title = $('#k-editor-link-title', element).val();
                    if (title) {
                        this.attributes.title = title;
                    }
                    if (textInput.is(':visible')) {
                        text = textInput.val();
                        if (!text && !this._initialText) {
                            this.attributes.innerText = href;
                        } else if (text && text !== this._initialText) {
                            this.attributes.innerText = dom.stripBom(text);
                        }
                    }
                    target = $('#k-editor-link-target', element).is(':checked');
                    this.attributes.target = target ? '_blank' : null;
                    this.formatter.apply(this._range, this.attributes);
                }
                this._close(e);
                if (this.change) {
                    this.change();
                }
            },
            _close: function (e) {
                e.preventDefault();
                this._dialog.destroy();
                dom.windowFromDocument(RangeUtils.documentFromRange(this._range)).focus();
                this.releaseRange(this._range);
            },
            linkUrl: function (anchor) {
                if (anchor) {
                    return anchor.getAttribute('href', 2);
                }
                return HTTP_PROTOCOL;
            },
            linkText: function (nodes) {
                var text = '';
                var i;
                for (i = 0; i < nodes.length; i++) {
                    text += nodes[i].nodeValue;
                }
                return dom.stripBom(text || '');
            },
            redo: function () {
                var range = this.lockRange(true);
                this.formatter.apply(range, this.attributes);
                this.releaseRange(range);
            }
        });
        var AutoLinkCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this.formatter = new LinkFormatter();
            },
            exec: function () {
                var detectedLink = this.detectLink();
                if (!detectedLink) {
                    return;
                }
                var range = this.getRange();
                var linkMarker = new kendo.ui.editor.Marker();
                var linkRange = range.cloneRange();
                linkRange.setStart(detectedLink.start.node, detectedLink.start.offset);
                linkRange.setEnd(detectedLink.end.node, detectedLink.end.offset);
                range = this.lockRange();
                linkMarker.add(linkRange);
                this.formatter.apply(linkRange, { href: this._ensureWebProtocol(detectedLink.text) });
                linkMarker.remove(linkRange);
                this.releaseRange(range);
            },
            detectLink: function () {
                var range = this.getRange();
                var startNode = range.startContainer;
                var startOffset = range.startOffset;
                var prev = startNode.previousSibling;
                if (!prev && (dom.isBom(startNode) && !startNode.nextSibling || !startOffset && dom.isDataNode(startNode))) {
                    startNode = startNode.parentNode;
                    startOffset = 0;
                }
                var traverser = new LeftDomTextTraverser({
                    node: startNode,
                    offset: startOffset,
                    cancelAtNode: function (node) {
                        return node && dom.name(node) === 'a';
                    }
                });
                var detection = new DomTextLinkDetection(traverser);
                return detection.detectLink();
            },
            changesContent: function () {
                return !!this.detectLink();
            },
            _ensureWebProtocol: function (linkText) {
                var hasProtocol = this._hasProtocolPrefix(linkText);
                return hasProtocol ? linkText : this._prefixWithWebProtocol(linkText);
            },
            _hasProtocolPrefix: function (linkText) {
                return protocolRegExp.test(linkText);
            },
            _prefixWithWebProtocol: function (linkText) {
                return HTTP_PROTOCOL + linkText;
            }
        });
        var UnlinkTool = Tool.extend({
            init: function (options) {
                this.options = options;
                this.finder = new InlineFormatFinder([{ tags: ['a'] }]);
                Tool.fn.init.call(this, $.extend(options, { command: UnlinkCommand }));
            },
            initialize: function (ui, options) {
                Tool.fn.initialize.call(this, ui, options);
                ui.addClass('k-state-disabled');
            },
            update: function (ui, nodes) {
                ui.toggleClass('k-state-disabled', !this.finder.isFormatted(nodes)).removeClass('k-state-hover');
            }
        });
        var DomTextLinkDetection = Class.extend({
            init: function (traverser) {
                this.traverser = traverser;
                this.start = DomPos();
                this.end = DomPos();
                this.text = '';
            },
            detectLink: function () {
                var node = this.traverser.node;
                var offset = this.traverser.offset;
                if (dom.isDataNode(node)) {
                    var text = node.data.substring(0, offset);
                    if (/\s{2}$/.test(dom.stripBom(text))) {
                        return;
                    }
                } else if (offset === 0) {
                    var p = dom.closestEditableOfType(node, dom.blockElements);
                    if (p && p.previousSibling) {
                        this.traverser.init({ node: p.previousSibling });
                    }
                }
                this.traverser.traverse($.proxy(this._detectEnd, this));
                if (!this.end.blank()) {
                    this.traverser = this.traverser.clone(this.end);
                    this.traverser.traverse($.proxy(this._detectStart, this));
                    if (!this._isLinkDetected()) {
                        var puntuationOptions = this.traverser.extendOptions(this.start);
                        var puntuationTraverser = new RightDomTextTraverser(puntuationOptions);
                        puntuationTraverser.traverse($.proxy(this._skipStartPuntuation, this));
                        if (!this._isLinkDetected()) {
                            this.start = DomPos();
                        }
                    }
                }
                if (this.start.blank()) {
                    return null;
                } else {
                    return {
                        start: this.start,
                        end: this.end,
                        text: this.text
                    };
                }
            },
            _isLinkDetected: function () {
                return protocolRegExp.test(this.text) || /^w{3}\./i.test(this.text);
            },
            _detectEnd: function (text, node) {
                var i = lastIndexOfRegExp(text, endLinkCharsRegExp);
                if (i > -1) {
                    this.end.node = node;
                    this.end.offset = i + 1;
                    return false;
                }
            },
            _detectStart: function (text, node) {
                var i = lastIndexOfRegExp(text, /\s/);
                var ii = i + 1;
                this.text = text.substring(ii) + this.text;
                this.start.node = node;
                this.start.offset = ii;
                if (i > -1) {
                    return false;
                }
            },
            _skipStartPuntuation: function (text, node, offset) {
                var i = indexOfRegExp(text, /\w/);
                var ii = i;
                if (i === -1) {
                    ii = text.length;
                }
                this.text = this.text.substring(ii);
                this.start.node = node;
                this.start.offset = ii + (offset | 0);
                if (i > -1) {
                    return false;
                }
            }
        });
        function lastIndexOfRegExp(str, search) {
            var i = str.length;
            while (i-- && !search.test(str[i])) {
            }
            return i;
        }
        function indexOfRegExp(str, search) {
            var r = search.exec(str);
            return r ? r.index : -1;
        }
        var DomPos = function () {
            return {
                node: null,
                offset: null,
                blank: function () {
                    return this.node === null && this.offset === null;
                }
            };
        };
        var DomTextTraverser = Class.extend({
            init: function (options) {
                this.node = options.node;
                this.offset = options.offset === undefined ? dom.isDataNode(this.node) && this.node.length || 0 : options.offset;
                this.cancelAtNode = options.cancelAtNode || this.cancelAtNode || $.noop;
            },
            traverse: function (callback) {
                if (!callback) {
                    return;
                }
                this.cancel = false;
                this._traverse(callback, this.node, this.offset);
            },
            _traverse: function (callback, node, offset) {
                if (!node || this.cancel) {
                    return;
                }
                if (node.nodeType === 3) {
                    var text = node.data;
                    if (offset !== undefined) {
                        text = this.subText(text, offset);
                    }
                    this.cancel = callback(text, node, offset) === false;
                } else {
                    var edgeNode = this.edgeNode(node);
                    this.cancel = this.cancel || this.cancelAtNode(edgeNode);
                    return this._traverse(callback, edgeNode);
                }
                var next = this.next(node);
                if (!next) {
                    var parent = node.parentNode;
                    while (!next && dom.isInline(parent)) {
                        next = this.next(parent);
                        parent = parent.parentNode;
                    }
                }
                this.cancel = this.cancel || this.cancelAtNode(next);
                this._traverse(callback, next);
            },
            extendOptions: function (o) {
                return $.extend({
                    node: this.node,
                    offset: this.offset,
                    cancelAtNode: this.cancelAtNode
                }, o || {});
            },
            edgeNode: function (node) {
            },
            next: function (node) {
            },
            subText: function (text, offset) {
            }
        });
        var LeftDomTextTraverser = DomTextTraverser.extend({
            subText: function (text, splitIndex) {
                return text.substring(0, splitIndex);
            },
            next: function (node) {
                return node.previousSibling;
            },
            edgeNode: function (node) {
                return node.lastChild;
            },
            clone: function (options) {
                var o = this.extendOptions(options);
                return new LeftDomTextTraverser(o);
            }
        });
        var RightDomTextTraverser = DomTextTraverser.extend({
            subText: function (text, splitIndex) {
                return text.substring(splitIndex);
            },
            next: function (node) {
                return node.nextSibling;
            },
            edgeNode: function (node) {
                return node.firstChild;
            },
            clone: function (options) {
                var o = this.extendOptions(options);
                return new RightDomTextTraverser(o);
            }
        });
        extend(kendo.ui.editor, {
            LinkFormatFinder: LinkFormatFinder,
            LinkFormatter: LinkFormatter,
            UnlinkCommand: UnlinkCommand,
            LinkCommand: LinkCommand,
            AutoLinkCommand: AutoLinkCommand,
            UnlinkTool: UnlinkTool,
            DomTextLinkDetection: DomTextLinkDetection,
            LeftDomTextTraverser: LeftDomTextTraverser,
            RightDomTextTraverser: RightDomTextTraverser
        });
        registerTool('createLink', new Tool({
            key: 'K',
            ctrl: true,
            command: LinkCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Create Link'
            })
        }));
        registerTool('unlink', new UnlinkTool({
            key: 'K',
            ctrl: true,
            shift: true,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Remove Link'
            })
        }));
        registerTool('autoLink', new Tool({
            key: [
                keys.ENTER,
                keys.SPACEBAR
            ],
            keyPressCommand: true,
            command: AutoLinkCommand
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/formatblock', ['editor/plugins/format'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, formats = kendo.ui.Editor.fn.options.formats, dom = Editor.Dom, ToolTemplate = Editor.ToolTemplate, FormatTool = Editor.FormatTool, EditorUtils = Editor.EditorUtils, registerTool = EditorUtils.registerTool, registerFormat = EditorUtils.registerFormat, RangeUtils = Editor.RangeUtils;
        var BlockFormatFinder = Class.extend({
            init: function (format) {
                this.format = format;
            },
            contains: function (node, children) {
                var i, len, child;
                for (i = 0, len = children.length; i < len; i++) {
                    child = children[i];
                    if (!child || !dom.isAncestorOrSelf(node, child)) {
                        return false;
                    }
                }
                return true;
            },
            findSuitable: function (nodes) {
                var format = this.format, suitable = [], i, len, candidate;
                for (i = 0, len = nodes.length; i < len; i++) {
                    for (var f = format.length - 1; f >= 0; f--) {
                        candidate = dom.ofType(nodes[i], format[f].tags) ? nodes[i] : dom.closestEditableOfType(nodes[i], format[f].tags);
                        if (candidate) {
                            break;
                        }
                    }
                    if (!candidate || candidate.contentEditable === 'true') {
                        return [];
                    }
                    if ($.inArray(candidate, suitable) < 0) {
                        suitable.push(candidate);
                    }
                }
                this._resolveListsItems(suitable);
                for (i = 0, len = suitable.length; i < len; i++) {
                    if (this.contains(suitable[i], suitable)) {
                        return [suitable[i]];
                    }
                }
                return suitable;
            },
            _resolveListsItems: function (nodes) {
                var i, node, wrapper;
                for (i = 0; i < nodes.length; i++) {
                    node = nodes[i];
                    wrapper = dom.is(node, 'li') ? node : dom.wrapper(node);
                    wrapper = wrapper && dom.list(wrapper) ? wrapper.children[0] : wrapper;
                    if (dom.is(wrapper, 'li')) {
                        node = nodes[i] = wrapper;
                    }
                }
            },
            findFormat: function (sourceNode) {
                var format = this.format, i, len, node, tags, attributes;
                var editableParent = dom.editableParent(sourceNode);
                var immutables = this.options && this.options.immutables;
                var ImmutablesNS = Editor.Immutables;
                for (i = 0, len = format.length; i < len; i++) {
                    node = sourceNode;
                    tags = format[i].tags;
                    attributes = format[i].attr;
                    if (immutables && tags && tags[0] == 'immutable') {
                        var immutable = ImmutablesNS.immutableParent(node);
                        if (immutable && dom.attrEquals(immutable, attributes)) {
                            return node;
                        }
                    }
                    while (node && dom.isAncestorOf(editableParent, node)) {
                        if (dom.ofType(node, tags) && dom.attrEquals(node, attributes)) {
                            return node;
                        }
                        node = node.parentNode;
                    }
                }
                return null;
            },
            getFormat: function (nodes) {
                var that = this, findFormat = function (node) {
                        return that.findFormat(dom.isDataNode(node) ? node.parentNode : node);
                    }, result = findFormat(nodes[0]), i, len;
                if (!result) {
                    return '';
                }
                for (i = 1, len = nodes.length; i < len; i++) {
                    if (result != findFormat(nodes[i])) {
                        return '';
                    }
                }
                return result.nodeName.toLowerCase();
            },
            isFormatted: function (nodes) {
                for (var i = 0, len = nodes.length; i < len; i++) {
                    if (!this.findFormat(nodes[i])) {
                        return false;
                    }
                }
                return true;
            }
        });
        var BlockFormatter = Class.extend({
            init: function (format, values) {
                this.format = format;
                this.values = values;
                this.finder = new BlockFormatFinder(format);
            },
            wrap: function (tag, attributes, nodes) {
                var commonAncestor = nodes.length == 1 ? dom.blockParentOrBody(nodes[0]) : dom.commonAncestor.apply(null, nodes);
                if (dom.isInline(commonAncestor)) {
                    commonAncestor = dom.blockParentOrBody(commonAncestor);
                }
                var ancestors = dom.significantChildNodes(commonAncestor), position = dom.findNodeIndex(ancestors[0]), wrapper = dom.create(commonAncestor.ownerDocument, tag, attributes), i, ancestor;
                for (i = 0; i < ancestors.length; i++) {
                    ancestor = ancestors[i];
                    if (dom.isBlock(ancestor)) {
                        dom.attr(ancestor, attributes);
                        if (wrapper.childNodes.length) {
                            dom.insertBefore(wrapper, ancestor);
                            wrapper = wrapper.cloneNode(false);
                        }
                        position = dom.findNodeIndex(ancestor) + 1;
                        continue;
                    }
                    wrapper.appendChild(ancestor);
                }
                if (wrapper.firstChild) {
                    dom.insertAt(commonAncestor, wrapper, position);
                }
            },
            apply: function (nodes) {
                var format, values = this.values;
                function attributes(format) {
                    return extend({}, format && format.attr, values);
                }
                this._handleImmutables(nodes, true);
                var images = dom.filter('img', nodes);
                var imageFormat = EditorUtils.formatByName('img', this.format);
                var imageAttributes = attributes(imageFormat);
                $.each(images, function () {
                    dom.attr(this, imageAttributes);
                });
                if (images.length == nodes.length) {
                    return;
                }
                var nonImages = dom.filter('img', nodes, true);
                var formatNodes = this.finder.findSuitable(nonImages);
                if (formatNodes.length) {
                    for (var i = 0, len = formatNodes.length; i < len; i++) {
                        format = EditorUtils.formatByName(dom.name(formatNodes[i]), this.format);
                        dom.attr(formatNodes[i], attributes(format));
                    }
                } else {
                    format = this.format[0];
                    this.wrap(format.tags[0], attributes(format), nonImages);
                }
            },
            _handleImmutables: function (nodes, applyFormatting) {
                if (!this.immutables()) {
                    return;
                }
                var immutableFormat = EditorUtils.formatByName('immutable', this.format);
                if (!immutableFormat) {
                    return;
                }
                var ImmutablesNS = Editor.Immutables;
                var l = nodes.length - 1;
                for (var i = l; i >= 0; i--) {
                    var immutableParent = ImmutablesNS.immutableParent(nodes[i]);
                    if (!immutableParent) {
                        continue;
                    }
                    if (immutableParent !== nodes[i + 1]) {
                        if (applyFormatting) {
                            dom.attr(immutableParent, immutableFormat.attr);
                        } else {
                            dom.unstyle(immutableParent, immutableFormat.attr.style);
                        }
                    }
                    nodes.splice(i, 1);
                }
            },
            immutables: function () {
                return this.editor && this.editor.options.immutables;
            },
            remove: function (nodes) {
                var i, l, formatNode, namedFormat, name;
                this._handleImmutables(nodes, false);
                for (i = 0, l = nodes.length; i < l; i++) {
                    formatNode = this.finder.findFormat(nodes[i]);
                    if (formatNode) {
                        name = dom.name(formatNode);
                        namedFormat = EditorUtils.formatByName(name, this.format);
                        if (namedFormat.attr.style) {
                            dom.unstyle(formatNode, namedFormat.attr.style);
                        }
                        if (namedFormat.attr.className) {
                            dom.removeClass(formatNode, namedFormat.attr.className);
                        }
                    }
                }
            },
            toggle: function (range) {
                var that = this, nodes = dom.filterBy(RangeUtils.nodes(range), dom.htmlIndentSpace, true);
                if (that.finder.isFormatted(nodes)) {
                    that.remove(nodes);
                } else {
                    that.apply(nodes);
                }
            }
        });
        var GreedyBlockFormatter = Class.extend({
            init: function (format, values) {
                var that = this;
                that.format = format;
                that.values = values;
                that.finder = new BlockFormatFinder(format);
            },
            apply: function (nodes) {
                var format = this.format;
                var blocks = dom.blockParents(nodes);
                var formatTag = format[0].tags[0];
                var i, len, list, formatter, range;
                var element;
                var tagName;
                var block;
                var immutalbeParent;
                if (blocks.length) {
                    for (i = 0, len = blocks.length; i < len; i++) {
                        block = blocks[i];
                        immutalbeParent = this.immutables() && Editor.Immutables.immutableParent(block);
                        if (!immutalbeParent) {
                            tagName = dom.name(block);
                            if (tagName == 'li') {
                                list = block.parentNode;
                                formatter = new Editor.ListFormatter(list.nodeName.toLowerCase(), formatTag);
                                range = this.editor.createRange();
                                range.selectNode(blocks[i]);
                                formatter.toggle(range);
                            } else if (formatTag && (tagName == 'td' || block.attributes.contentEditable)) {
                                new BlockFormatter(format, this.values).apply(block.childNodes);
                            } else {
                                element = dom.changeTag(block, formatTag);
                                dom.attr(element, format[0].attr);
                            }
                        }
                    }
                } else {
                    var blockFormatter = new BlockFormatter(format, this.values);
                    blockFormatter.editor = this.editor;
                    blockFormatter.apply(nodes);
                }
            },
            toggle: function (range) {
                var nodes = RangeUtils.textNodes(range);
                if (!nodes.length) {
                    range.selectNodeContents(range.commonAncestorContainer);
                    nodes = RangeUtils.textNodes(range);
                    if (!nodes.length) {
                        nodes = dom.significantChildNodes(range.commonAncestorContainer);
                    }
                }
                this.apply(nodes);
            },
            immutables: function () {
                return this.editor && this.editor.options.immutables;
            }
        });
        var BlockFormatTool = FormatTool.extend({
            init: function (options) {
                FormatTool.fn.init.call(this, extend(options, {
                    finder: new BlockFormatFinder(options.format),
                    formatter: function () {
                        return new BlockFormatter(options.format);
                    }
                }));
            }
        });
        extend(Editor, {
            BlockFormatFinder: BlockFormatFinder,
            BlockFormatter: BlockFormatter,
            GreedyBlockFormatter: GreedyBlockFormatter,
            BlockFormatTool: BlockFormatTool
        });
        var listElements = [
            'ul',
            'ol',
            'li'
        ];
        registerFormat('justifyLeft', [
            {
                tags: dom.nonListBlockElements,
                attr: { style: { textAlign: 'left' } }
            },
            {
                tags: ['img'],
                attr: {
                    style: {
                        'float': 'left',
                        display: '',
                        marginLeft: '',
                        marginRight: ''
                    }
                }
            },
            {
                tags: ['immutable'],
                attr: {
                    style: {
                        'float': 'left',
                        display: '',
                        marginLeft: '',
                        marginRight: ''
                    }
                }
            },
            {
                tags: listElements,
                attr: {
                    style: {
                        textAlign: 'left',
                        listStylePosition: ''
                    }
                }
            }
        ]);
        registerTool('justifyLeft', new BlockFormatTool({
            format: formats.justifyLeft,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Justify Left'
            })
        }));
        registerFormat('justifyCenter', [
            {
                tags: dom.nonListBlockElements,
                attr: { style: { textAlign: 'center' } }
            },
            {
                tags: ['img'],
                attr: {
                    style: {
                        display: 'block',
                        marginLeft: 'auto',
                        marginRight: 'auto',
                        'float': ''
                    }
                }
            },
            {
                tags: ['immutable'],
                attr: {
                    style: {
                        display: 'block',
                        marginLeft: 'auto',
                        marginRight: 'auto',
                        'float': ''
                    }
                }
            },
            {
                tags: listElements,
                attr: {
                    style: {
                        textAlign: 'center',
                        listStylePosition: 'inside'
                    }
                }
            }
        ]);
        registerTool('justifyCenter', new BlockFormatTool({
            format: formats.justifyCenter,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Justify Center'
            })
        }));
        registerFormat('justifyRight', [
            {
                tags: dom.nonListBlockElements,
                attr: { style: { textAlign: 'right' } }
            },
            {
                tags: ['img'],
                attr: {
                    style: {
                        'float': 'right',
                        display: '',
                        marginLeft: '',
                        marginRight: ''
                    }
                }
            },
            {
                tags: ['immutable'],
                attr: {
                    style: {
                        'float': 'right',
                        display: '',
                        marginLeft: '',
                        marginRight: ''
                    }
                }
            },
            {
                tags: listElements,
                attr: {
                    style: {
                        textAlign: 'right',
                        listStylePosition: 'inside'
                    }
                }
            }
        ]);
        registerTool('justifyRight', new BlockFormatTool({
            format: formats.justifyRight,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Justify Right'
            })
        }));
        registerFormat('justifyFull', [
            {
                tags: dom.nonListBlockElements,
                attr: { style: { textAlign: 'justify' } }
            },
            {
                tags: ['img'],
                attr: {
                    style: {
                        display: 'block',
                        marginLeft: 'auto',
                        marginRight: 'auto',
                        'float': ''
                    }
                }
            },
            {
                tags: ['immutable'],
                attr: {
                    style: {
                        display: 'block',
                        marginLeft: 'auto',
                        marginRight: 'auto',
                        'float': ''
                    }
                }
            },
            {
                tags: listElements,
                attr: {
                    style: {
                        textAlign: 'justify',
                        listStylePosition: ''
                    }
                }
            }
        ]);
        registerTool('justifyFull', new BlockFormatTool({
            format: formats.justifyFull,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Justify Full'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/lists', ['editor/plugins/formatblock'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, EditorUtils = Editor.EditorUtils, Command = Editor.Command, ToolTemplate = Editor.ToolTemplate, FormatTool = Editor.FormatTool, BlockFormatFinder = Editor.BlockFormatFinder, textNodes = RangeUtils.textNodes, registerTool = Editor.EditorUtils.registerTool;
        var ListFormatFinder = BlockFormatFinder.extend({
            init: function (tag) {
                this.tag = tag;
                var tags = this.tags = [
                    tag == 'ul' ? 'ol' : 'ul',
                    tag
                ];
                BlockFormatFinder.fn.init.call(this, [{ tags: tags }]);
            },
            isFormatted: function (nodes) {
                var formatNodes = [];
                var formatNode, i;
                for (i = 0; i < nodes.length; i++) {
                    formatNode = this.findFormat(nodes[i]);
                    if (formatNode && dom.name(formatNode) == this.tag) {
                        formatNodes.push(formatNode);
                    }
                }
                if (formatNodes.length < 1) {
                    return false;
                }
                if (formatNodes.length != nodes.length) {
                    return false;
                }
                for (i = 0; i < formatNodes.length; i++) {
                    if (formatNodes[i].parentNode != formatNode.parentNode) {
                        break;
                    }
                    if (formatNodes[i] != formatNode) {
                        return false;
                    }
                }
                return true;
            },
            findSuitable: function (nodes) {
                var candidate = this.findFormat(nodes[0]);
                if (candidate && dom.name(candidate) == this.tag) {
                    return candidate;
                }
                return null;
            }
        });
        var ListFormatter = Class.extend({
            init: function (tag, unwrapTag) {
                var that = this;
                that.finder = new ListFormatFinder(tag);
                that.tag = tag;
                that.unwrapTag = unwrapTag;
            },
            isList: function (node) {
                return dom.list(node);
            },
            immutables: function () {
                return this.editor && !!this.editor.options.immutables;
            },
            wrap: function (list, nodes) {
                var li = dom.create(list.ownerDocument, 'li'), i, node, isImmutable = this.immutables() ? Editor.Immutables.immutable : $.noop;
                for (i = 0; i < nodes.length; i++) {
                    node = nodes[i];
                    if (dom.is(node, 'li')) {
                        list.appendChild(node);
                        continue;
                    }
                    if (this.isList(node)) {
                        while (node.firstChild) {
                            list.appendChild(node.firstChild);
                        }
                        continue;
                    }
                    if (dom.is(node, 'td')) {
                        while (node.firstChild) {
                            li.appendChild(node.firstChild);
                        }
                        list.appendChild(li);
                        node.appendChild(list);
                        list = list.cloneNode(false);
                        li = li.cloneNode(false);
                        continue;
                    }
                    li.appendChild(node);
                    if (dom.isBlock(node)) {
                        list.appendChild(li);
                        if (!isImmutable(node)) {
                            dom.unwrap(node);
                        }
                        li = li.cloneNode(false);
                    }
                }
                if (li.firstChild) {
                    list.appendChild(li);
                }
            },
            containsAny: function (parent, nodes) {
                for (var i = 0; i < nodes.length; i++) {
                    if (dom.isAncestorOrSelf(parent, nodes[i])) {
                        return true;
                    }
                }
                return false;
            },
            suitable: function (candidate, nodes) {
                if (candidate.className == 'k-marker') {
                    var sibling = candidate.nextSibling;
                    if (sibling && dom.isBlock(sibling)) {
                        return false;
                    }
                    sibling = candidate.previousSibling;
                    if (sibling && dom.isBlock(sibling)) {
                        return false;
                    }
                }
                return this.containsAny(candidate, nodes) || dom.isInline(candidate) || candidate.nodeType == 3;
            },
            _parentLists: function (node) {
                var editable = dom.closestEditable(node);
                return $(node).parentsUntil(editable, 'ul,ol');
            },
            split: function (range) {
                var nodes = textNodes(range);
                var start, end, parents;
                if (nodes.length) {
                    start = dom.parentOfType(nodes[0], ['li']);
                    end = dom.parentOfType(nodes[nodes.length - 1], ['li']);
                    range.setStartBefore(start);
                    range.setEndAfter(end);
                    for (var i = 0, l = nodes.length; i < l; i++) {
                        var formatNode = this.finder.findFormat(nodes[i]);
                        if (formatNode) {
                            parents = this._parentLists(formatNode);
                            if (parents.length) {
                                RangeUtils.split(range, parents.last()[0], true);
                            } else {
                                RangeUtils.split(range, formatNode, true);
                            }
                        }
                    }
                }
            },
            merge: function (tag, formatNode) {
                var prev = formatNode.previousSibling, next;
                while (prev && (prev.className == 'k-marker' || prev.nodeType == 3 && dom.isWhitespace(prev))) {
                    prev = prev.previousSibling;
                }
                if (prev && dom.name(prev) == tag) {
                    while (formatNode.firstChild) {
                        prev.appendChild(formatNode.firstChild);
                    }
                    dom.remove(formatNode);
                    formatNode = prev;
                }
                next = formatNode.nextSibling;
                while (next && (next.className == 'k-marker' || next.nodeType == 3 && dom.isWhitespace(next))) {
                    next = next.nextSibling;
                }
                if (next && dom.name(next) == tag) {
                    while (formatNode.lastChild) {
                        next.insertBefore(formatNode.lastChild, next.firstChild);
                    }
                    dom.remove(formatNode);
                }
            },
            breakable: function (node) {
                return node != node.ownerDocument.body && !/table|tbody|tr|td/.test(dom.name(node)) && !node.attributes.contentEditable;
            },
            applyOnSection: function (section, nodes) {
                var tag = this.tag;
                var commonAncestor = dom.closestSplittableParent(nodes);
                var ancestors = [];
                var formatNode = this.finder.findSuitable(nodes);
                if (!formatNode) {
                    formatNode = new ListFormatFinder(tag == 'ul' ? 'ol' : 'ul').findSuitable(nodes);
                }
                var childNodes;
                if (/table|tbody/.test(dom.name(commonAncestor))) {
                    childNodes = $.map(nodes, function (node) {
                        return dom.parentOfType(node, ['td']);
                    });
                } else {
                    childNodes = dom.significantChildNodes(commonAncestor);
                    if ($.grep(childNodes, dom.isBlock).length) {
                        childNodes = $.grep(childNodes, $.proxy(function (node) {
                            return this.containsAny(node, nodes);
                        }, this));
                    }
                    if (!childNodes.length) {
                        childNodes = nodes;
                    }
                }
                function pushAncestor() {
                    ancestors.push(this);
                }
                for (var i = 0; i < childNodes.length; i++) {
                    var child = childNodes[i];
                    var suitable = (!formatNode || !dom.isAncestorOrSelf(formatNode, child)) && this.suitable(child, nodes);
                    if (!suitable) {
                        continue;
                    }
                    if (formatNode && this.isList(child)) {
                        $.each(child.children, pushAncestor);
                        dom.remove(child);
                    } else {
                        ancestors.push(child);
                    }
                }
                if (ancestors.length == childNodes.length && this.breakable(commonAncestor)) {
                    ancestors = [commonAncestor];
                }
                if (!formatNode) {
                    formatNode = dom.create(commonAncestor.ownerDocument, tag);
                    if (dom.isBlock(ancestors[0])) {
                        dom.mergeAttributes(ancestors[0], formatNode);
                    }
                    dom.insertBefore(formatNode, ancestors[0]);
                }
                this.wrap(formatNode, ancestors);
                while (dom.isBom(formatNode.nextSibling)) {
                    dom.remove(formatNode.nextSibling);
                }
                if (!dom.is(formatNode, tag)) {
                    dom.changeTag(formatNode, tag);
                }
                this.merge(tag, formatNode);
            },
            apply: function (nodes) {
                var i = 0, sections = [], lastSection, lastNodes, section, node, l = nodes.length, immutableParent = this.immutables() ? Editor.Immutables.immutableParent : $.noop;
                function addLastSection() {
                    if (lastSection) {
                        sections.push({
                            section: lastSection,
                            nodes: lastNodes
                        });
                    }
                }
                for (i = 0; i < l; i++) {
                    node = immutableParent(nodes[i]) || nodes[i];
                    section = dom.closestEditable(node, [
                        'td',
                        'body'
                    ]);
                    if (!lastSection || section != lastSection) {
                        addLastSection();
                        lastNodes = [node];
                        lastSection = section;
                    } else {
                        lastNodes.push(node);
                    }
                }
                addLastSection();
                for (i = 0; i < sections.length; i++) {
                    this.applyOnSection(sections[i].section, sections[i].nodes);
                }
            },
            unwrap: function (ul) {
                var fragment = ul.ownerDocument.createDocumentFragment(), unwrapTag = this.unwrapTag, parents, li, p, child;
                for (li = ul.firstChild; li; li = li.nextSibling) {
                    p = dom.create(ul.ownerDocument, unwrapTag || 'p');
                    while (li.firstChild) {
                        child = li.firstChild;
                        if (dom.isBlock(child)) {
                            if (p.firstChild) {
                                fragment.appendChild(p);
                                p = dom.create(ul.ownerDocument, unwrapTag || 'p');
                            }
                            fragment.appendChild(child);
                        } else {
                            p.appendChild(child);
                        }
                    }
                    if (p.firstChild) {
                        fragment.appendChild(p);
                    }
                }
                parents = this._parentLists(ul);
                if (parents[0]) {
                    dom.insertAfter(fragment, parents.last()[0]);
                    parents.last().remove();
                } else {
                    dom.insertAfter(fragment, ul);
                }
                dom.remove(ul);
            },
            remove: function (nodes) {
                var formatNode;
                for (var i = 0, l = nodes.length; i < l; i++) {
                    formatNode = this.finder.findFormat(nodes[i]);
                    if (formatNode) {
                        this.unwrap(formatNode);
                    }
                }
            },
            toggle: function (range) {
                var that = this, nodes = textNodes(range), ancestor = range.commonAncestorContainer;
                if (!nodes.length) {
                    range.selectNodeContents(ancestor);
                    nodes = textNodes(range);
                    if (!nodes.length) {
                        var text = ancestor.ownerDocument.createTextNode('');
                        range.startContainer.appendChild(text);
                        nodes = [text];
                        range.selectNode(text.parentNode);
                    }
                }
                nodes = dom.filterBy(nodes, dom.htmlIndentSpace, true);
                if (that.finder.isFormatted(nodes)) {
                    that.split(range);
                    that.remove(nodes);
                } else {
                    that.apply(nodes);
                }
            }
        });
        var ListCommand = Command.extend({
            init: function (options) {
                options.formatter = new ListFormatter(options.tag);
                Command.fn.init.call(this, options);
            }
        });
        var ListTool = FormatTool.extend({
            init: function (options) {
                this.options = options;
                FormatTool.fn.init.call(this, extend(options, { finder: new ListFormatFinder(options.tag) }));
            },
            command: function (commandArguments) {
                return new ListCommand(extend(commandArguments, { tag: this.options.tag }));
            }
        });
        extend(Editor, {
            ListFormatFinder: ListFormatFinder,
            ListFormatter: ListFormatter,
            ListCommand: ListCommand,
            ListTool: ListTool
        });
        registerTool('insertUnorderedList', new ListTool({
            tag: 'ul',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Insert unordered list'
            })
        }));
        registerTool('insertOrderedList', new ListTool({
            tag: 'ol',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Insert ordered list'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/formatting', ['editor/plugins/inlineformat'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Editor = kendo.ui.editor, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, DelayedExecutionTool = Editor.DelayedExecutionTool, Command = Editor.Command, dom = Editor.Dom, EditorUtils = Editor.EditorUtils, RangeUtils = Editor.RangeUtils, registerTool = EditorUtils.registerTool;
        var FormattingTool = DelayedExecutionTool.extend({
            init: function (options) {
                var that = this;
                Tool.fn.init.call(that, kendo.deepExtend({}, that.options, options));
                that.type = 'kendoSelectBox';
                that.finder = {
                    getFormat: function () {
                        return '';
                    }
                };
            },
            options: {
                items: [
                    {
                        text: 'Paragraph',
                        value: 'p'
                    },
                    {
                        text: 'Quotation',
                        value: 'blockquote'
                    },
                    {
                        text: 'Heading 1',
                        value: 'h1'
                    },
                    {
                        text: 'Heading 2',
                        value: 'h2'
                    },
                    {
                        text: 'Heading 3',
                        value: 'h3'
                    },
                    {
                        text: 'Heading 4',
                        value: 'h4'
                    },
                    {
                        text: 'Heading 5',
                        value: 'h5'
                    },
                    {
                        text: 'Heading 6',
                        value: 'h6'
                    }
                ],
                width: 110
            },
            toFormattingItem: function (item) {
                var value = item.value;
                if (!value) {
                    return item;
                }
                if (item.tag || item.className) {
                    return item;
                }
                var dot = value.indexOf('.');
                if (dot === 0) {
                    item.className = value.substring(1);
                } else if (dot == -1) {
                    item.tag = value;
                } else {
                    item.tag = value.substring(0, dot);
                    item.className = value.substring(dot + 1);
                }
                return item;
            },
            command: function (args) {
                var that = this;
                var item = args.value;
                item = this.toFormattingItem(item);
                return new Editor.FormatCommand({
                    range: args.range,
                    formatter: function () {
                        var formatter, tags = (item.tag || item.context || 'span').split(','), format = [{
                                    tags: tags,
                                    attr: { className: item.className || '' }
                                }];
                        if ($.inArray(tags[0], dom.inlineElements) >= 0) {
                            formatter = new Editor.GreedyInlineFormatter(format);
                        } else {
                            formatter = new Editor.GreedyBlockFormatter(format);
                        }
                        formatter.editor = that.editor;
                        return formatter;
                    }
                });
            },
            initialize: function (ui, initOptions) {
                var editor = initOptions.editor;
                var options = this.options;
                var toolName = options.name;
                var that = this;
                that.editor = editor;
                ui.width(options.width);
                ui.kendoSelectBox({
                    dataTextField: 'text',
                    dataValueField: 'value',
                    dataSource: options.items || editor.options[toolName],
                    title: editor.options.messages[toolName],
                    autoSize: true,
                    change: function () {
                        var dataItem = this.dataItem();
                        if (dataItem) {
                            Tool.exec(editor, toolName, dataItem.toJSON());
                        }
                    },
                    dataBound: function () {
                        var i, items = this.dataSource.data();
                        for (i = 0; i < items.length; i++) {
                            items[i] = that.toFormattingItem(items[i]);
                        }
                    },
                    highlightFirst: false,
                    template: kendo.template('<span unselectable="on" style="display:block;#=(data.style||"")#">#:data.text#</span>')
                });
                ui.addClass('k-decorated').closest('.k-widget').removeClass('k-' + toolName).find('*').addBack().attr('unselectable', 'on');
            },
            getFormattingValue: function (items, nodes) {
                for (var i = 0; i < items.length; i++) {
                    var item = items[i];
                    var tag = item.tag || item.context || '';
                    var className = item.className ? '.' + item.className : '';
                    var selector = tag + className;
                    var element = $(nodes[0]).closest(selector)[0];
                    if (!element) {
                        continue;
                    }
                    if (nodes.length == 1) {
                        return item.value;
                    }
                    for (var n = 1; n < nodes.length; n++) {
                        if (!$(nodes[n]).closest(selector)[0]) {
                            break;
                        } else if (n == nodes.length - 1) {
                            return item.value;
                        }
                    }
                }
                return '';
            },
            update: function (ui, nodes) {
                var selectBox = $(ui).data(this.type);
                if (!selectBox) {
                    return;
                }
                var dataSource = selectBox.dataSource, items = dataSource.data(), i, context, ancestor = dom.commonAncestor.apply(null, nodes);
                if (ancestor != dom.closestEditable(ancestor) && this._ancestor == ancestor) {
                    return;
                } else {
                    this._ancestor = ancestor;
                }
                for (i = 0; i < items.length; i++) {
                    context = items[i].context;
                    items[i].visible = !context || !!$(ancestor).closest(context).length;
                }
                dataSource.filter([{
                        field: 'visible',
                        operator: 'eq',
                        value: true
                    }]);
                DelayedExecutionTool.fn.update.call(this, ui, nodes);
                selectBox.value(this.getFormattingValue(dataSource.view(), nodes));
                selectBox.wrapper.toggleClass('k-state-disabled', !dataSource.view().length);
            },
            destroy: function () {
                this._ancestor = null;
            }
        });
        var CleanFormatCommand = Command.extend({
            exec: function () {
                var range = this.lockRange(true);
                this.tagsToClean = this.options.remove || 'strong,em,span,sup,sub,del,b,i,u,font'.split(',');
                RangeUtils.wrapSelectedElements(range);
                var nodes = RangeUtils.mapAll(range, function (node) {
                    return node;
                });
                for (var c = nodes.length - 1; c >= 0; c--) {
                    var node = nodes[c];
                    if (!this.immutableParent(node)) {
                        this.clean(node);
                    }
                }
                this.releaseRange(range);
            },
            clean: function (node) {
                if (!node || dom.isMarker(node)) {
                    return;
                }
                var name = dom.name(node);
                if (name == 'ul' || name == 'ol') {
                    var listFormatter = new Editor.ListFormatter(name);
                    var prev = node.previousSibling;
                    var next = node.nextSibling;
                    listFormatter.unwrap(node);
                    for (; prev && prev != next; prev = prev.nextSibling) {
                        this.clean(prev);
                    }
                } else if (name == 'blockquote') {
                    dom.changeTag(node, 'p');
                } else if (node.nodeType == 1 && !dom.insignificant(node)) {
                    for (var i = node.childNodes.length - 1; i >= 0; i--) {
                        this.clean(node.childNodes[i]);
                    }
                    node.removeAttribute('style');
                    node.removeAttribute('class');
                } else {
                    unwrapListItem(node);
                }
                if ($.inArray(name, this.tagsToClean) > -1) {
                    dom.unwrap(node);
                }
            },
            immutableParent: function (node) {
                return this.immutables() && Editor.Immutables.immutableParent(node);
            }
        });
        function unwrapListItem(node) {
            var li = dom.closestEditableOfType(node, ['li']);
            if (li) {
                var listFormatter = new Editor.ListFormatter(dom.name(li.parentNode));
                var range = kendo.ui.editor.W3CRange.fromNode(node);
                range.selectNode(li);
                listFormatter.toggle(range);
            }
        }
        $.extend(Editor, {
            FormattingTool: FormattingTool,
            CleanFormatCommand: CleanFormatCommand
        });
        registerTool('formatting', new FormattingTool({
            template: new ToolTemplate({
                template: EditorUtils.dropDownListTemplate,
                title: 'Format'
            })
        }));
        registerTool('cleanFormatting', new Tool({
            command: CleanFormatCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Clean formatting'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/image', [
        'kendo.imagebrowser',
        'editor/command'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, dom = Editor.Dom, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, RangeUtils = Editor.RangeUtils, Command = Editor.Command, keys = kendo.keys, KEDITORIMAGEURL = '#k-editor-image-url', KEDITORIMAGETITLE = '#k-editor-image-title', KEDITORIMAGEWIDTH = '#k-editor-image-width', KEDITORIMAGEHEIGHT = '#k-editor-image-height';
        var ImageCommand = Command.extend({
            init: function (options) {
                var that = this;
                Command.fn.init.call(that, options);
                that.async = true;
                that.attributes = {};
            },
            insertImage: function (img, range) {
                var attributes = this.attributes;
                var doc = RangeUtils.documentFromRange(range);
                if (attributes.src && attributes.src != 'http://') {
                    var removeIEAttributes = function () {
                        setTimeout(function () {
                            if (!attributes.width) {
                                img.removeAttribute('width');
                            }
                            if (!attributes.height) {
                                img.removeAttribute('height');
                            }
                            img.removeAttribute('complete');
                        });
                    };
                    if (!img) {
                        img = dom.create(doc, 'img', attributes);
                        img.onload = img.onerror = removeIEAttributes;
                        range.deleteContents();
                        range.insertNode(img);
                        if (!img.nextSibling) {
                            dom.insertAfter(doc.createTextNode('\uFEFF'), img);
                        }
                        removeIEAttributes();
                        range.setStartAfter(img);
                        range.setEndAfter(img);
                        RangeUtils.selectRange(range);
                        return true;
                    } else {
                        img.onload = img.onerror = removeIEAttributes;
                        dom.attr(img, attributes);
                        removeIEAttributes();
                    }
                }
                return false;
            },
            _dialogTemplate: function (showBrowser) {
                return kendo.template('<div class="k-editor-dialog k-popup-edit-form">' + '<div class="k-edit-form-container">' + '<div class="k-edit-form-content">' + '# if (showBrowser) { #' + '<div class="k-filebrowser k-imagebrowser"></div>' + '# } #' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-url">#: messages.imageWebAddress #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-textbox" id="k-editor-image-url">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-title">#: messages.imageAltText #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-textbox" id="k-editor-image-title">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-width">#: messages.imageWidth #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-textbox" id="k-editor-image-width">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-height">#: messages.imageHeight #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-textbox" id="k-editor-image-height">' + '</div>' + '</div>' + '<div class="k-edit-buttons k-state-default">' + '<button class="k-dialog-insert k-button k-primary">#: messages.dialogInsert #</button>' + '<button class="k-dialog-close k-button">#: messages.dialogCancel #</button>' + '</div>' + '</div>' + '</div>')({
                    messages: this.editor.options.messages,
                    showBrowser: showBrowser
                });
            },
            redo: function () {
                var that = this, range = that.lockRange();
                if (!that.insertImage(RangeUtils.image(range), range)) {
                    that.releaseRange(range);
                }
            },
            exec: function () {
                var that = this, range = that.lockRange(), applied = false, img = RangeUtils.image(range), imageWidth = img && img.getAttribute('width') || '', imageHeight = img && img.getAttribute('height') || '', dialog, isIE = kendo.support.browser.msie, options = that.editor.options, messages = options.messages, imageBrowser = options.imageBrowser, showBrowser = !!(kendo.ui.ImageBrowser && imageBrowser && imageBrowser.transport && imageBrowser.transport.read !== undefined), dialogOptions = {
                        title: messages.insertImage,
                        visible: false,
                        resizable: showBrowser
                    };
                this.expandImmutablesIn(range);
                function apply(e) {
                    var element = dialog.element, w = parseInt(element.find(KEDITORIMAGEWIDTH).val(), 10), h = parseInt(element.find(KEDITORIMAGEHEIGHT).val(), 10);
                    that.attributes = {
                        src: element.find(KEDITORIMAGEURL).val().replace(/ /g, '%20'),
                        alt: element.find(KEDITORIMAGETITLE).val()
                    };
                    that.attributes.width = null;
                    that.attributes.height = null;
                    if (!isNaN(w) && w > 0) {
                        that.attributes.width = w;
                    }
                    if (!isNaN(h) && h > 0) {
                        that.attributes.height = h;
                    }
                    applied = that.insertImage(img, range);
                    close(e);
                    if (that.change) {
                        that.change();
                    }
                }
                function close(e) {
                    e.preventDefault();
                    dialog.destroy();
                    dom.windowFromDocument(RangeUtils.documentFromRange(range)).focus();
                    if (!applied) {
                        that.releaseRange(range);
                    }
                }
                function keyDown(e) {
                    if (e.keyCode == keys.ENTER) {
                        apply(e);
                    } else if (e.keyCode == keys.ESC) {
                        close(e);
                    }
                }
                dialogOptions.close = close;
                if (showBrowser) {
                    dialogOptions.width = 750;
                }
                dialog = this.createDialog(that._dialogTemplate(showBrowser), dialogOptions).toggleClass('k-filebrowser-dialog', showBrowser).find('.k-dialog-insert').click(apply).end().find('.k-dialog-close').click(close).end().find('.k-edit-field input').keydown(keyDown).end().find(KEDITORIMAGEURL).val(img ? img.getAttribute('src', 2) : 'http://').end().find(KEDITORIMAGETITLE).val(img ? img.alt : '').end().find(KEDITORIMAGEWIDTH).val(imageWidth).end().find(KEDITORIMAGEHEIGHT).val(imageHeight).end().data('kendoWindow');
                var element = dialog.element;
                if (showBrowser) {
                    this._imageBrowser = new kendo.ui.ImageBrowser(element.find('.k-imagebrowser'), extend({}, imageBrowser));
                    this._imageBrowser.bind('change', function (ev) {
                        if (ev.selected.get('type') === 'f') {
                            element.find(KEDITORIMAGEURL).val(this.value());
                        }
                    });
                    this._imageBrowser.bind('apply', apply);
                }
                if (isIE) {
                    var dialogHeight = element.closest('.k-window').height();
                    element.css('max-height', dialogHeight);
                }
                dialog.center().open();
                element.find(KEDITORIMAGEURL).focus().select();
            }
        });
        kendo.ui.editor.ImageCommand = ImageCommand;
        registerTool('insertImage', new Editor.Tool({
            command: ImageCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Insert Image'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/import', ['editor/main'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, proxy = $.proxy, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, loadingOverlay = '<div contenteditable="false" class="k-loading-mask" style="width: 100%; height: 100%; position: absolute; top: 0px; left: 0px;"><div class="k-loading-image"></div><div class="k-loading-color"></div></div>';
        var ImportCommand = Command.extend({
            exec: function () {
                (this.editor._uploadWidget || this._initializeUploadWidget()).element.click();
            },
            _initializeUploadWidget: function () {
                var cmd = this;
                var editor = cmd.editor;
                var importOptions = editor.options['import'];
                var upload = $('<input id="editorImport" name="files" type="file" />').kendoUpload({
                    success: proxy(cmd._onUploadSuccess, cmd),
                    progress: proxy(cmd._onUploadProgress, cmd),
                    select: proxy(cmd._onUploadSelect, cmd),
                    error: proxy(cmd._onUploadError, cmd),
                    complete: proxy(cmd._onUploadComplete, cmd),
                    showFileList: false,
                    multiple: false,
                    async: {
                        saveUrl: importOptions.proxyUrl,
                        autoUpload: true,
                        saveField: 'file'
                    },
                    validation: {
                        allowedExtensions: importOptions.allowedExtensions,
                        maxFileSize: importOptions.maxFileSize
                    }
                }).getKendoUpload();
                editor._uploadWidget = upload;
                return upload;
            },
            _onUploadComplete: function (ev) {
                this._trigger('complete', ev);
                ev.sender.clearAllFiles();
                this._removeLoadingOverlay();
            },
            _onUploadSuccess: function (ev) {
                this.editor.value(ev.response.html.replace(/<\/?body>/gi, ''));
                this._trigger('success', ev);
            },
            _onUploadProgress: function (ev) {
                this._trigger('progress', ev);
            },
            _onUploadSelect: function (ev) {
                this._trigger('select', ev);
                if (!ev.files[0].validationErrors) {
                    this._initLoadingOverlay();
                }
            },
            _onUploadError: function (ev) {
                this._trigger('error', ev);
            },
            _trigger: function (eventType, uploadEvent) {
                var editor = this.editor;
                var importOptions = editor.options['import'];
                if (typeof importOptions[eventType] === 'function') {
                    importOptions[eventType].call(editor, uploadEvent);
                }
            },
            _initLoadingOverlay: function () {
                var editable = this.editor.body;
                if (Editor.Dom.is(editable, 'body')) {
                    this._iframeWrapper = this._container = this.editor.wrapper.find('iframe').parent().css({ position: 'relative' }).append(loadingOverlay);
                } else {
                    this._container = $(editable).append(loadingOverlay);
                }
                kendo.ui.progress(this._container, true);
            },
            _removeLoadingOverlay: function () {
                kendo.ui.progress(this._container, false);
                $(this._iframeWrapper).css({ position: '' });
                delete this._container;
                delete this._iframeWrapper;
            }
        });
        extend(Editor, { ImportCommand: ImportCommand });
        registerTool('import', new Tool({
            command: ImportCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Import'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/insert', ['editor/command'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, editorNS = kendo.ui.editor, Command = editorNS.Command, GenericCommand = editorNS.GenericCommand, EditorUtils = editorNS.EditorUtils, registerTool = EditorUtils.registerTool, Tool = editorNS.Tool, ToolTemplate = editorNS.ToolTemplate, RestorePoint = editorNS.RestorePoint, extend = $.extend;
        var InsertHtmlCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this.managesUndoRedo = true;
            },
            exec: function () {
                var editor = this.editor;
                var options = this.options;
                var range = options.range;
                var body = editor.body;
                var startRestorePoint = new RestorePoint(range, body);
                var html = options.html || options.value || '';
                editor.selectRange(range);
                editor.clipboard.paste(html, options);
                if (options.postProcess) {
                    options.postProcess(editor, editor.getRange());
                }
                var genericCommand = new GenericCommand(startRestorePoint, new RestorePoint(editor.getRange(), body));
                genericCommand.editor = editor;
                editor.undoRedoStack.push(genericCommand);
                editor.focus();
            }
        });
        var InsertHtmlTool = Tool.extend({
            initialize: function (ui, initOptions) {
                var editor = initOptions.editor, options = this.options, dataSource = options.items ? options.items : editor.options.insertHtml;
                this._selectBox = new editorNS.SelectBox(ui, {
                    dataSource: dataSource,
                    dataTextField: 'text',
                    dataValueField: 'value',
                    change: function () {
                        Tool.exec(editor, 'insertHtml', this.value());
                    },
                    title: editor.options.messages.insertHtml,
                    highlightFirst: false
                });
            },
            command: function (commandArguments) {
                return new InsertHtmlCommand(commandArguments);
            },
            update: function (ui) {
                var selectbox = ui.data('kendoSelectBox') || ui.find('select').data('kendoSelectBox');
                selectbox.close();
                selectbox.value(selectbox.options.title);
            }
        });
        extend(editorNS, {
            InsertHtmlCommand: InsertHtmlCommand,
            InsertHtmlTool: InsertHtmlTool
        });
        registerTool('insertHtml', new InsertHtmlTool({
            template: new ToolTemplate({
                template: EditorUtils.dropDownListTemplate,
                title: 'Insert HTML',
                initialValue: 'Insert HTML'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/export', ['editor/main'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, proxy = $.proxy, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, defaultExportAsItems = [
                {
                    text: 'Docx',
                    value: 'docx'
                },
                {
                    text: 'Rtf',
                    value: 'rtf'
                },
                {
                    text: 'Pdf',
                    value: 'pdf'
                },
                {
                    text: 'Html',
                    value: 'html'
                },
                {
                    text: 'Plain Text',
                    value: 'txt'
                }
            ];
        var ExportAsCommand = Command.extend({
            init: function (options) {
                var cmd = this;
                cmd.options = options;
                Command.fn.init.call(cmd, options);
                cmd.attributes = null;
                cmd.exportType = options.exportType;
            },
            exec: function () {
                var cmd = this;
                var range = this.lockRange(true);
                cmd.postToProxy();
                cmd.releaseRange(range);
            },
            postToProxy: function () {
                this.generateForm().appendTo('body').submit().remove();
            },
            generateForm: function () {
                var cmd = this;
                var exportAsOptions = cmd.editor.options.exportAs;
                var form = $('<form>').attr({
                    action: exportAsOptions && exportAsOptions.proxyURL || '',
                    method: 'POST'
                });
                form.append([
                    cmd.valueInput(),
                    cmd.exportTypeInput(),
                    cmd.fileNameInput()
                ]);
                return form;
            },
            valueInput: function () {
                var editor = this.editor;
                return $('<input>').attr({
                    value: editor.encodedValue(),
                    name: 'value',
                    type: 'hidden'
                });
            },
            exportTypeInput: function () {
                var cmd = this;
                return $('<input>').attr({
                    value: cmd.exportType,
                    name: 'exportType',
                    type: 'hidden'
                });
            },
            fileNameInput: function () {
                var editor = this.editor;
                var exportAsOptions = editor.options.exportAs;
                var fileName = exportAsOptions && exportAsOptions.fileName || editor.element.attr('id') || 'editor';
                return $('<input>').attr({
                    value: fileName,
                    name: 'fileName',
                    type: 'hidden'
                });
            }
        });
        var ExportAsTool = Tool.extend({
            init: function (options) {
                var tool = this;
                Tool.fn.init.call(tool, kendo.deepExtend({}, tool.options, options));
                tool.type = 'kendoSelectBox';
            },
            options: {
                items: defaultExportAsItems,
                width: 115
            },
            command: function (args) {
                var value = args.value;
                return new Editor.ExportAsCommand({
                    range: args.range,
                    exportType: value.exportType
                });
            },
            initialize: function (ui, initOptions) {
                var tool = this;
                var editor = initOptions.editor;
                var options = tool.options;
                var toolName = options.name;
                var changeHandler = proxy(tool.changeHandler, tool);
                var dataSource = options.items || editor.options[toolName];
                dataSource.unshift({
                    text: editor.options.messages[toolName],
                    value: ''
                });
                tool.editor = editor;
                ui.width(options.width);
                ui.kendoSelectBox({
                    dataTextField: 'text',
                    dataValueField: 'value',
                    dataSource: dataSource,
                    autoSize: true,
                    change: changeHandler,
                    open: function (e) {
                        var sender = e.sender;
                        sender.items()[0].style.display = 'none';
                        sender.unbind('open');
                    },
                    highlightFirst: false,
                    template: kendo.template('<span unselectable="on" style="display:block;#=(data.style||"")#">#:data.text#</span>')
                });
                ui.addClass('k-decorated').closest('.k-widget').removeClass('k-' + toolName).find('*').addBack().attr('unselectable', 'on');
            },
            changeHandler: function (e) {
                var sender = e.sender;
                var dataItem = sender.dataItem();
                var value = dataItem && dataItem.value;
                this._exec(value);
                sender.value('');
            },
            _exec: function (value) {
                if (value) {
                    Tool.exec(this.editor, this.options.name, { exportType: value });
                }
            },
            destroy: function () {
                this._ancestor = null;
            }
        });
        extend(Editor, {
            ExportAsTool: ExportAsTool,
            ExportAsCommand: ExportAsCommand
        });
        registerTool('exportAs', new ExportAsTool({
            template: new ToolTemplate({
                template: EditorUtils.dropDownListTemplate,
                title: 'Export As'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/indent', ['editor/plugins/formatblock'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, dom = Editor.Dom, EditorUtils = Editor.EditorUtils, registerTool = EditorUtils.registerTool, Command = Editor.Command, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, RangeUtils = Editor.RangeUtils, blockElements = dom.blockElements, BlockFormatFinder = Editor.BlockFormatFinder, BlockFormatter = Editor.BlockFormatter;
        function indent(node, value) {
            var isRtl = $(node).css('direction') == 'rtl', indentDirection = isRtl ? 'Right' : 'Left', property = dom.name(node) != 'td' ? 'margin' + indentDirection : 'padding' + indentDirection;
            if (value === undefined) {
                return node.style[property] || 0;
            } else {
                if (value > 0) {
                    node.style[property] = value + 'px';
                } else {
                    node.style[property] = '';
                    if (!node.style.cssText) {
                        node.removeAttribute('style');
                    }
                }
            }
        }
        var IndentFormatter = Class.extend({
            init: function () {
                this.finder = new BlockFormatFinder([{ tags: dom.blockElements }]);
            },
            apply: function (nodes) {
                nodes = dom.filterBy(nodes, dom.htmlIndentSpace, true);
                var formatNodes = this.finder.findSuitable(nodes), targets = [], i, len, formatNode, parentList, sibling;
                formatNodes = this.mapImmutables(formatNodes);
                if (formatNodes.length) {
                    for (i = 0, len = formatNodes.length; i < len; i++) {
                        if (dom.is(formatNodes[i], 'li')) {
                            if (!$(formatNodes[i]).index()) {
                                targets.push(formatNodes[i].parentNode);
                            } else if ($.inArray(formatNodes[i].parentNode, targets) < 0) {
                                targets.push(formatNodes[i]);
                            }
                        } else {
                            targets.push(formatNodes[i]);
                        }
                    }
                    while (targets.length) {
                        formatNode = targets.shift();
                        if (dom.is(formatNode, 'li')) {
                            parentList = formatNode.parentNode;
                            sibling = $(formatNode).prev('li');
                            var siblingList = sibling.find('ul,ol').last();
                            var nestedList = $(formatNode).children('ul,ol')[0];
                            if (nestedList && sibling[0]) {
                                if (siblingList[0]) {
                                    siblingList.append(formatNode);
                                    siblingList.append($(nestedList).children());
                                    dom.remove(nestedList);
                                } else {
                                    sibling.append(nestedList);
                                    nestedList.insertBefore(formatNode, nestedList.firstChild);
                                }
                            } else {
                                nestedList = sibling.children('ul,ol')[0];
                                if (!nestedList) {
                                    nestedList = dom.create(formatNode.ownerDocument, dom.name(parentList));
                                    sibling.append(nestedList);
                                }
                                while (formatNode && formatNode.parentNode == parentList) {
                                    nestedList.appendChild(formatNode);
                                    formatNode = targets.shift();
                                }
                            }
                        } else {
                            var marginLeft = parseInt(indent(formatNode), 10) + 30;
                            indent(formatNode, marginLeft);
                            for (var targetIndex = 0; targetIndex < targets.length; targetIndex++) {
                                if ($.contains(formatNode, targets[targetIndex])) {
                                    targets.splice(targetIndex, 1);
                                }
                            }
                        }
                    }
                } else {
                    var formatter = new BlockFormatter([{ tags: ['p'] }], { style: { marginLeft: 30 } });
                    formatter.apply(nodes);
                }
            },
            mapImmutables: function (nodes) {
                if (!this.immutables) {
                    return nodes;
                } else {
                    var immutables = [];
                    return $.map(nodes, function (node) {
                        var immutable = Editor.Immutables.immutableParent(node);
                        if (immutable) {
                            if ($.inArray(immutable, immutables) === -1) {
                                immutables.push(immutable);
                            } else {
                                return null;
                            }
                        }
                        return immutable || node;
                    });
                }
            },
            remove: function (nodes) {
                nodes = dom.filterBy(nodes, dom.htmlIndentSpace, true);
                var formatNodes = this.finder.findSuitable(nodes), targetNode, i, len, list, listParent, siblings, formatNode, marginLeft;
                formatNodes = this.mapImmutables(formatNodes);
                for (i = 0, len = formatNodes.length; i < len; i++) {
                    formatNode = $(formatNodes[i]);
                    if (formatNode.is('li')) {
                        list = formatNode.parent();
                        listParent = list.parent();
                        if (listParent.is('li,ul,ol') && !indent(list[0])) {
                            if (targetNode && $.contains(targetNode, listParent[0])) {
                                continue;
                            }
                            siblings = formatNode.nextAll('li');
                            if (siblings.length) {
                                $(list[0].cloneNode(false)).appendTo(formatNode).append(siblings);
                            }
                            if (listParent.is('li')) {
                                formatNode.insertAfter(listParent);
                            } else {
                                formatNode.appendTo(listParent);
                            }
                            if (!list.children('li').length) {
                                list.remove();
                            }
                            continue;
                        } else {
                            if (targetNode == list[0]) {
                                continue;
                            }
                            targetNode = list[0];
                        }
                    } else {
                        targetNode = formatNodes[i];
                    }
                    marginLeft = parseInt(indent(targetNode), 10) - 30;
                    indent(targetNode, marginLeft);
                }
            }
        });
        var IndentCommand = Command.extend({
            init: function (options) {
                var that = this;
                options.formatter = {
                    toggle: $.proxy(function (range) {
                        var indentFormatter = new IndentFormatter();
                        indentFormatter.immutables = this.editor && this.editor.options.immutables;
                        indentFormatter.apply(RangeUtils.nodes(range));
                    }, that)
                };
                Command.fn.init.call(this, options);
            }
        });
        var OutdentCommand = Command.extend({
            init: function (options) {
                var that = this;
                options.formatter = {
                    toggle: $.proxy(function (range) {
                        var indentFormatter = new IndentFormatter();
                        indentFormatter.immutables = this.editor && this.editor.options.immutables;
                        indentFormatter.remove(RangeUtils.nodes(range));
                    }, that)
                };
                Command.fn.init.call(this, options);
            }
        });
        var OutdentTool = Tool.extend({
            init: function (options) {
                Tool.fn.init.call(this, options);
                this.finder = new BlockFormatFinder([{ tags: blockElements }]);
            },
            initialize: function (ui, options) {
                Tool.fn.initialize.call(this, ui, options);
                $.extend(this.options, { immutables: options.editor && options.editor.options.immutables });
                ui.addClass('k-state-disabled');
            },
            update: function (ui, nodes) {
                var suitableNodes = this.finder.findSuitable(nodes), isOutdentable, listParentsCount, i, len, suitable, immutableParent;
                for (i = 0, len = suitableNodes.length; i < len; i++) {
                    suitable = suitableNodes[i];
                    if (this.options.immutables) {
                        immutableParent = Editor.Immutables.immutableParent(suitable);
                        if (immutableParent) {
                            suitable = immutableParent;
                        }
                    }
                    isOutdentable = indent(suitable);
                    if (!isOutdentable) {
                        listParentsCount = $(suitable).parents('ul,ol').length;
                        isOutdentable = dom.is(suitable, 'li') && (listParentsCount > 1 || indent(suitable.parentNode)) || dom.ofType(suitable, [
                            'ul',
                            'ol'
                        ]) && listParentsCount > 0;
                    }
                    if (isOutdentable) {
                        ui.removeClass('k-state-disabled');
                        return;
                    }
                }
                ui.addClass('k-state-disabled').removeClass('k-state-hover');
            }
        });
        extend(Editor, {
            IndentFormatter: IndentFormatter,
            IndentCommand: IndentCommand,
            OutdentCommand: OutdentCommand,
            OutdentTool: OutdentTool
        });
        registerTool('indent', new Tool({
            command: IndentCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Indent'
            })
        }));
        registerTool('outdent', new OutdentTool({
            command: OutdentCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Outdent'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/linebreak', ['editor/plugins/formatblock'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, extend = $.extend, editorNS = kendo.ui.editor, dom = editorNS.Dom, Command = editorNS.Command, Tool = editorNS.Tool, BlockFormatter = editorNS.BlockFormatter, normalize = dom.normalize, RangeUtils = editorNS.RangeUtils, registerTool = editorNS.EditorUtils.registerTool;
        var ParagraphCommand = Command.extend({
            init: function (options) {
                this.options = options;
                Command.fn.init.call(this, options);
            },
            _insertMarker: function (doc, range) {
                var marker = dom.create(doc, 'a'), container;
                marker.className = 'k-marker';
                range.insertNode(marker);
                if (!marker.parentNode) {
                    container = range.commonAncestorContainer;
                    container.innerHTML = '';
                    container.appendChild(marker);
                }
                normalize(marker.parentNode);
                return marker;
            },
            _moveFocus: function (range, candidate) {
                if (dom.isEmpty(candidate)) {
                    range.setStartBefore(candidate);
                } else {
                    range.selectNodeContents(candidate);
                    var focusNode = RangeUtils.textNodes(range)[0];
                    if (!focusNode) {
                        while (candidate.childNodes.length && !dom.is(candidate.firstChild, 'br')) {
                            candidate = candidate.firstChild;
                        }
                        focusNode = candidate;
                    }
                    if (dom.isEmpty(focusNode)) {
                        range.setStartBefore(focusNode);
                    } else {
                        if (dom.emptyNode(focusNode)) {
                            focusNode.innerHTML = '\uFEFF';
                        }
                        var startNode = focusNode.firstChild || focusNode;
                        if (dom.isDataNode(startNode)) {
                            range.setStart(startNode, 0);
                        } else {
                            range.setStartBefore(startNode);
                        }
                    }
                }
            },
            shouldTrim: function (range) {
                var blocks = 'p,h1,h2,h3,h4,h5,h6'.split(','), startInBlock = dom.parentOfType(range.startContainer, blocks), endInBlock = dom.parentOfType(range.endContainer, blocks);
                return startInBlock && !endInBlock || !startInBlock && endInBlock;
            },
            _blankAfter: function (node) {
                while (node && (dom.isMarker(node) || dom.stripBom(node.nodeValue) === '')) {
                    node = node.nextSibling;
                }
                return !node;
            },
            exec: function () {
                var range = this.getRange(), doc = RangeUtils.documentFromRange(range), parent, previous, next, emptyParagraphContent = editorNS.emptyElementContent, paragraph, marker, li, heading, tableNode, rng, shouldTrim;
                this.expandImmutablesIn(range);
                shouldTrim = this.shouldTrim(range);
                range.deleteContents();
                marker = this._insertMarker(doc, range);
                dom.stripBomNode(marker.previousSibling);
                dom.stripBomNode(marker.nextSibling);
                li = dom.closestEditableOfType(marker, ['li']);
                heading = dom.closestEditableOfType(marker, 'h1,h2,h3,h4,h5,h6'.split(','));
                tableNode = dom.is(marker.parentNode, 'table') && marker.parentNode;
                if (li) {
                    if (dom.emptyNode(li)) {
                        paragraph = dom.create(doc, 'p');
                        if (dom.next(li)) {
                            rng = range.cloneRange();
                            rng.selectNode(li);
                            RangeUtils.split(rng, li.parentNode);
                        }
                        var br = $('br', li);
                        if (br.length == 1) {
                            br.remove();
                        }
                        var parentNode = li.parentNode;
                        var parentChildrenLength = li.parentNode.children.length;
                        var firstChild = parentChildrenLength > 1 && li.childNodes.length == 1 && li.children[0];
                        dom.insertAfter(paragraph, parentNode);
                        dom.remove(parentChildrenLength == 1 ? li.parentNode : li);
                        if (firstChild && firstChild !== marker) {
                            paragraph.appendChild(firstChild);
                            paragraph.appendChild(marker);
                        } else {
                            paragraph.innerHTML = emptyParagraphContent;
                        }
                        next = paragraph;
                    }
                } else if (heading && this._blankAfter(marker)) {
                    paragraph = this._insertParagraphAfter(heading);
                    dom.remove(marker);
                    next = paragraph;
                } else if (tableNode) {
                    paragraph = this._insertParagraphAfter(tableNode);
                    dom.remove(marker);
                    next = paragraph;
                }
                if (!next) {
                    if (!(li || heading)) {
                        new BlockFormatter([{ tags: ['p'] }]).apply([marker]);
                    }
                    range.selectNode(marker);
                    parent = dom.parentOfType(marker, [li ? 'li' : heading ? dom.name(heading) : 'p']);
                    RangeUtils.split(range, parent, shouldTrim);
                    previous = parent.previousSibling;
                    if (dom.is(previous, 'li') && previous.firstChild && !dom.is(previous.firstChild, 'br')) {
                        previous = previous.firstChild;
                    }
                    next = parent.nextSibling;
                    this.clean(previous, { links: true });
                    this.clean(next, { links: true });
                    if (dom.is(next, 'li') && next.firstChild && !dom.is(next.firstChild, 'br')) {
                        next = next.firstChild;
                    }
                    dom.remove(parent);
                    normalize(previous);
                }
                normalize(next);
                this._moveFocus(range, next);
                range.collapse(true);
                dom.scrollTo(next, true);
                RangeUtils.selectRange(range);
            },
            _insertParagraphAfter: function (node) {
                var range = this.getRange();
                var doc = RangeUtils.documentFromRange(range);
                var emptyElementContent = editorNS.emptyElementContent;
                var paragraph = dom.create(doc, 'p');
                dom.insertAfter(paragraph, node);
                paragraph.innerHTML = emptyElementContent;
                return paragraph;
            },
            clean: function (node, options) {
                var root = node;
                if (node.firstChild && dom.is(node.firstChild, 'br')) {
                    dom.remove(node.firstChild);
                }
                if (dom.isDataNode(node) && !node.nodeValue) {
                    node = node.parentNode;
                }
                if (node) {
                    var siblings = false;
                    while (node.firstChild && node.firstChild.nodeType == 1) {
                        siblings = siblings || dom.significantNodes(node.childNodes).length > 1;
                        node = node.firstChild;
                    }
                    if (!dom.isEmpty(node) && /^\s*$/.test(node.innerHTML) && !siblings) {
                        $(root).find('.k-br').remove();
                        node.innerHTML = editorNS.emptyElementContent;
                    }
                    if (options && options.links) {
                        while (node != root) {
                            if (dom.is(node, 'a') && dom.emptyNode(node)) {
                                dom.unwrap(node);
                                break;
                            }
                            node = node.parentNode;
                        }
                    }
                }
            }
        });
        var NewLineCommand = Command.extend({
            init: function (options) {
                this.options = options;
                Command.fn.init.call(this, options);
            },
            exec: function () {
                var range = this.getRange();
                this.expandImmutablesIn(range);
                var br = dom.create(RangeUtils.documentFromRange(range), 'br');
                var node = range.startContainer;
                var filler;
                var browser = kendo.support.browser;
                var oldIE = browser.msie && browser.version < 11;
                var tableNode = dom.is(node, 'table') && node;
                range.deleteContents();
                if (tableNode) {
                    dom.insertAfter(br, tableNode);
                } else {
                    range.insertNode(br);
                }
                normalize(br.parentNode);
                if (!oldIE && (!br.nextSibling || dom.isWhitespace(br.nextSibling))) {
                    filler = br.cloneNode(true);
                    filler.className = 'k-br';
                    dom.insertAfter(filler, br);
                }
                range.setStartAfter(br);
                range.collapse(true);
                dom.scrollTo(br.nextSibling || br, true);
                RangeUtils.selectRange(range);
            }
        });
        extend(editorNS, {
            ParagraphCommand: ParagraphCommand,
            NewLineCommand: NewLineCommand
        });
        registerTool('insertLineBreak', new Tool({
            key: 13,
            shift: false, //Custom Change//
            command: NewLineCommand
        }));
        registerTool('insertParagraph', new Tool({
            key: 13,
            shift: true, //Custom Change//
            command: ParagraphCommand
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/file', [
        'kendo.filebrowser',
        'editor/plugins/link'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, dom = Editor.Dom, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, RangeUtils = Editor.RangeUtils, Command = Editor.Command, LinkFormatter = Editor.LinkFormatter, textNodes = RangeUtils.textNodes, keys = kendo.keys, KEDITORFILEURL = '#k-editor-file-url', KEDITORFILETEXT = '#k-editor-file-text', KEDITORFILETITLE = '#k-editor-file-title';
        var FileCommand = Command.extend({
            init: function (options) {
                var that = this;
                Command.fn.init.call(that, options);
                that.formatter = new LinkFormatter();
                that.async = true;
                that.attributes = {};
            },
            insertFile: function (file, range) {
                var attributes = this.attributes;
                var doc = RangeUtils.documentFromRange(range);
                if (attributes.href && attributes.href != 'http://') {
                    if (!file) {
                        file = dom.create(doc, 'a', { href: attributes.href });
                        file.innerHTML = attributes.innerHTML;
                        file.title = attributes.title;
                        range.deleteContents();
                        range.insertNode(file);
                        if (!file.nextSibling) {
                            dom.insertAfter(doc.createTextNode('\uFEFF'), file);
                        }
                        range.setStartAfter(file);
                        range.setEndAfter(file);
                        RangeUtils.selectRange(range);
                        return true;
                    } else {
                        dom.attr(file, attributes);
                    }
                }
                return false;
            },
            _dialogTemplate: function (showBrowser) {
                return kendo.template('<div class="k-editor-dialog k-popup-edit-form">' + '<div class="k-edit-form-container">' + '<div class="k-edit-form-content">' + '# if (showBrowser) { #' + '<div class="k-filebrowser"></div>' + '# } #' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-file-url">#: messages.fileWebAddress #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-textbox" id="k-editor-file-url">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-file-text">#: messages.fileText #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-textbox" id="k-editor-file-text">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-file-title">#: messages.fileTitle #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-textbox" id="k-editor-file-title">' + '</div>' + '</div>' + '<div class="k-edit-buttons k-state-default">' + '<button class="k-dialog-insert k-button k-primary">#: messages.dialogInsert #</button>' + '<button class="k-dialog-close k-button">#: messages.dialogCancel #</button>' + '</div>' + '</div>' + '</div>')({
                    messages: this.editor.options.messages,
                    showBrowser: showBrowser
                });
            },
            redo: function () {
                var that = this, range = that.lockRange();
                this.formatter.apply(range, this.attributes);
                that.releaseRange(range);
            },
            exec: function () {
                var that = this, range = that.lockRange(), nodes = textNodes(range), applied = false, file = nodes.length ? this.formatter.finder.findSuitable(nodes[0]) : null, dialog, isIE = kendo.support.browser.msie, options = that.editor.options, messages = options.messages, fileBrowser = options.fileBrowser, showBrowser = !!(kendo.ui.FileBrowser && fileBrowser && fileBrowser.transport && fileBrowser.transport.read !== undefined), dialogOptions = {
                        title: messages.insertFile,
                        visible: false,
                        resizable: showBrowser
                    };
                this.expandImmutablesIn(range);
                function apply(e) {
                    var element = dialog.element, href = element.find(KEDITORFILEURL).val().replace(/ /g, '%20'), innerHTML = element.find(KEDITORFILETEXT).val(), title = element.find(KEDITORFILETITLE).val();
                    that.attributes = {
                        href: href,
                        innerHTML: innerHTML !== '' ? innerHTML : href,
                        title: title
                    };
                    applied = that.insertFile(file, range);
                    close(e);
                    if (that.change) {
                        that.change();
                    }
                }
                function close(e) {
                    e.preventDefault();
                    dialog.destroy();
                    dom.windowFromDocument(RangeUtils.documentFromRange(range)).focus();
                    if (!applied) {
                        that.releaseRange(range);
                    }
                }
                function keyDown(e) {
                    if (e.keyCode == keys.ENTER) {
                        apply(e);
                    } else if (e.keyCode == keys.ESC) {
                        close(e);
                    }
                }
                dialogOptions.close = close;
                if (showBrowser) {
                    dialogOptions.width = 750;
                }
                dialog = this.createDialog(that._dialogTemplate(showBrowser), dialogOptions).toggleClass('k-filebrowser-dialog', showBrowser).find('.k-dialog-insert').click(apply).end().find('.k-dialog-close').click(close).end().find('.k-edit-field input').keydown(keyDown).end().find(KEDITORFILEURL).val(file ? file.getAttribute('href', 2) : 'http://').end().find(KEDITORFILETEXT).val(file ? file.innerText : '').end().find(KEDITORFILETITLE).val(file ? file.title : '').end().data('kendoWindow');
                var element = dialog.element;
                if (showBrowser) {
                    that._fileBrowser = new kendo.ui.FileBrowser(element.find('.k-filebrowser'), extend({}, fileBrowser));
                    that._fileBrowser.bind('change', function (ev) {
                        if (ev.selected.get('type') === 'f') {
                            element.find(KEDITORFILEURL).val(this.value());
                        }
                    });
                    that._fileBrowser.bind('apply', apply);
                }
                if (isIE) {
                    var dialogHeight = element.closest('.k-window').height();
                    element.css('max-height', dialogHeight);
                }
                dialog.center().open();
                element.find(KEDITORFILEURL).focus().select();
            }
        });
        kendo.ui.editor.FileCommand = FileCommand;
        registerTool('insertFile', new Editor.Tool({
            command: FileCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Insert File'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/tables', [
        'editor/plugins/formatblock',
        'editor/plugins/insert'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, proxy = $.proxy, Editor = kendo.ui.editor, dom = Editor.Dom, EditorUtils = Editor.EditorUtils, RangeUtils = Editor.RangeUtils, Command = Editor.Command, NS = 'kendoEditor', ACTIVESTATE = 'k-state-active', SELECTEDSTATE = 'k-state-selected', Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, InsertHtmlCommand = Editor.InsertHtmlCommand, BlockFormatFinder = Editor.BlockFormatFinder, registerTool = Editor.EditorUtils.registerTool, getTouches = kendo.getTouches;
        var template = kendo.template;
        var columnTemplate = '<td style=\'width:#=width#%;\'>#=content#</td>';
        var tableFormatFinder = new BlockFormatFinder([{ tags: ['table'] }]);
        var TableCommand = InsertHtmlCommand.extend({
            init: function (options) {
                var o = $.extend({
                    postProcess: this.postProcess,
                    skipCleaners: true
                }, options || {});
                InsertHtmlCommand.fn.init.call(this, o);
            },
            _tableHtml: function (rows, columns) {
                rows = rows || 1;
                columns = columns || 1;
                var columnHtml = template(columnTemplate)({
                    width: 100 / columns,
                    content: Editor.emptyTableCellContent
                });
                var rowHeight = 100 / rows;
                return '<table class=\'k-table\' data-last>' + new Array(rows + 1).join('<tr style=\'height:' + rowHeight + '%;\'>' + new Array(columns + 1).join(columnHtml) + '</tr>') + '</table>';
            },
            postProcess: function (editor, range) {
                var insertedTable = $('table[data-last]', editor.document).removeAttr('data-last');
                range.setStart(insertedTable.find('td')[0], 0);
                range.collapse(true);
                editor.selectRange(range);
            },
            exec: function () {
                var options = this.options;
                options.html = this._tableHtml(options.rows, options.columns);
                InsertHtmlCommand.fn.exec.call(this);
            }
        });
        var PopupTool = Tool.extend({
            initialize: function (ui, options) {
                Tool.fn.initialize.call(this, ui, options);
                var popup = $(this.options.popupTemplate).appendTo('body').kendoPopup({
                    anchor: ui,
                    copyAnchorStyles: false,
                    open: proxy(this._open, this),
                    activate: proxy(this._activate, this),
                    close: proxy(this._close, this)
                }).data('kendoPopup');
                ui.click(proxy(this._toggle, this)).keydown(proxy(this._keydown, this));
                var editor = this._editor = options.editor;
                this._popup = popup;
                var tableWizard = new Editor.TableWizardTool({
                    template: new ToolTemplate({
                        template: EditorUtils.buttonTemplate,
                        title: editor.options.messages.tableWizard
                    }),
                    command: Editor.TableWizardCommand,
                    insertNewTable: true
                });
                registerTool('tableWizardInsert', tableWizard);
                var twTool = $('<div class=\'k-editor-toolbar\'>' + tableWizard.options.template.getHtml() + '</div>');
                twTool.appendTo(popup.element);
                if (editor.toolbar) {
                    editor.toolbar.attachToolsEvents(twTool);
                }
            },
            popup: function () {
                return this._popup;
            },
            _activate: $.noop,
            _open: function () {
                this._popup.options.anchor.addClass(ACTIVESTATE);
            },
            _close: function () {
                this._popup.options.anchor.removeClass(ACTIVESTATE);
            },
            _keydown: function (e) {
                var keys = kendo.keys;
                var key = e.keyCode;
                if (key == keys.DOWN && e.altKey) {
                    this._popup.open();
                } else if (key == keys.ESC) {
                    this._popup.close();
                }
            },
            _toggle: function (e) {
                var button = $(e.target).closest('.k-tool');
                if (!button.hasClass('k-state-disabled')) {
                    this.popup().toggle();
                }
            },
            update: function (ui) {
                var popup = this.popup();
                if (popup.wrapper && popup.wrapper.css('display') == 'block') {
                    popup.close();
                }
                ui.removeClass('k-state-hover');
            },
            destroy: function () {
                this._popup.destroy();
            }
        });
        var InsertTableTool = PopupTool.extend({
            init: function (options) {
                this.cols = 8;
                this.rows = 6;
                PopupTool.fn.init.call(this, $.extend(options, {
                    command: TableCommand,
                    popupTemplate: '<div class=\'k-ct-popup\'>' + new Array(this.cols * this.rows + 1).join('<span class=\'k-ct-cell k-state-disabled\' />') + '<div class=\'k-status\'></div>' + '</div>'
                }));
            },
            _activate: function () {
                var that = this, element = that._popup.element, cells = element.find('.k-ct-cell'), firstCell = cells.eq(0), lastCell = cells.eq(cells.length - 1), start = kendo.getOffset(firstCell), end = kendo.getOffset(lastCell), cols = that.cols, rows = that.rows, cellWidth, cellHeight;
                element.find('*').addBack().attr('unselectable', 'on');
                end.left += lastCell[0].offsetWidth;
                end.top += lastCell[0].offsetHeight;
                cellWidth = (end.left - start.left) / cols;
                cellHeight = (end.top - start.top) / rows;
                function tableFromLocation(e) {
                    var w = $(window);
                    return {
                        row: Math.floor((e.clientY + w.scrollTop() - start.top) / cellHeight) + 1,
                        col: Math.floor((e.clientX + w.scrollLeft() - start.left) / cellWidth) + 1
                    };
                }
                element.autoApplyNS(NS).on('mousemove', '.k-ct-cell', function (e) {
                    that._setTableSize(tableFromLocation(e));
                }).on('mouseleave', '.k-ct-cell', function () {
                    that._setTableSize();
                }).on('down', '.k-ct-cell', function (e) {
                    e.preventDefault();
                    var touch = getTouches(e)[0];
                    that._exec(tableFromLocation(touch.location));
                });
            },
            _valid: function (size) {
                return size && size.row > 0 && size.col > 0 && size.row <= this.rows && size.col <= this.cols;
            },
            _exec: function (size) {
                if (this._valid(size)) {
                    this._editor.exec('createTable', {
                        rows: size.row,
                        columns: size.col
                    });
                    this._popup.close();
                }
            },
            _setTableSize: function (size) {
                var element = this._popup.element;
                var status = element.find('.k-status');
                var cells = element.find('.k-ct-cell');
                var cols = this.cols;
                var messages = this._editor.options.messages;
                if (this._valid(size)) {
                    status.text(kendo.format(messages.createTableHint, size.row, size.col));
                    cells.each(function (i) {
                        $(this).toggleClass(SELECTEDSTATE, i % cols < size.col && i / cols < size.row);
                    });
                } else {
                    status.text(messages.createTable);
                    cells.removeClass(SELECTEDSTATE);
                }
            },
            _keydown: function (e) {
                PopupTool.fn._keydown.call(this, e);
                if (!this._popup.visible()) {
                    return;
                }
                var keys = kendo.keys;
                var key = e.keyCode;
                var cells = this._popup.element.find('.k-ct-cell');
                var focus = Math.max(cells.filter('.k-state-selected').last().index(), 0);
                var selectedRows = Math.floor(focus / this.cols);
                var selectedColumns = focus % this.cols;
                var changed = false;
                if (key == keys.DOWN && !e.altKey) {
                    changed = true;
                    selectedRows++;
                } else if (key == keys.UP) {
                    changed = true;
                    selectedRows--;
                } else if (key == keys.RIGHT) {
                    changed = true;
                    selectedColumns++;
                } else if (key == keys.LEFT) {
                    changed = true;
                    selectedColumns--;
                }
                var tableSize = {
                    row: Math.max(1, Math.min(this.rows, selectedRows + 1)),
                    col: Math.max(1, Math.min(this.cols, selectedColumns + 1))
                };
                if (key == keys.ENTER) {
                    this._exec(tableSize);
                } else {
                    this._setTableSize(tableSize);
                }
                if (changed) {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                }
            },
            _open: function () {
                var messages = this._editor.options.messages;
                PopupTool.fn._open.call(this);
                this.popup().element.find('.k-status').text(messages.createTable).end().find('.k-ct-cell').removeClass(SELECTEDSTATE);
            },
            _close: function () {
                PopupTool.fn._close.call(this);
                this.popup().element.off('.' + NS);
            }
        });
        var InsertRowCommand = Command.extend({
            exec: function () {
                var range = this.lockRange(true), td = range.endContainer, cellCount, row, newRow;
                while (dom.name(td) != 'td') {
                    td = td.parentNode;
                }
                if (this.immutables() && Editor.Immutables.immutableParent(td)) {
                    return;
                }
                row = td.parentNode;
                cellCount = row.children.length;
                newRow = row.cloneNode(true);
                for (var i = 0; i < row.cells.length; i++) {
                    newRow.cells[i].innerHTML = Editor.emptyTableCellContent;
                }
                if (this.options.position == 'before') {
                    dom.insertBefore(newRow, row);
                } else {
                    dom.insertAfter(newRow, row);
                }
                this.releaseRange(range);
            }
        });
        var InsertColumnCommand = Command.extend({
            exec: function () {
                var range = this.lockRange(true), td = dom.closest(range.endContainer, 'td'), table = dom.closest(td, 'table'), columnIndex, i, rows = table.rows, cell, newCell, position = this.options.position;
                if (this.immutables() && Editor.Immutables.immutableParent(td)) {
                    return;
                }
                columnIndex = dom.findNodeIndex(td, true);
                for (i = 0; i < rows.length; i++) {
                    cell = rows[i].cells[columnIndex];
                    newCell = cell.cloneNode();
                    newCell.innerHTML = Editor.emptyTableCellContent;
                    if (position == 'before') {
                        dom.insertBefore(newCell, cell);
                    } else {
                        dom.insertAfter(newCell, cell);
                    }
                }
                this.releaseRange(range);
            }
        });
        var DeleteRowCommand = Command.extend({
            exec: function () {
                var range = this.lockRange();
                var rows = RangeUtils.mapAll(range, function (node) {
                    return $(node).closest('tr')[0];
                });
                var row = rows[0];
                if (this.immutables() && Editor.Immutables.immutableParent(row)) {
                    return;
                }
                var table = dom.closest(row, 'table');
                var focusElement;
                if (table.rows.length <= rows.length) {
                    focusElement = dom.next(table);
                    if (!focusElement || dom.insignificant(focusElement)) {
                        focusElement = dom.prev(table);
                    }
                    dom.remove(table);
                } else {
                    for (var i = 0; i < rows.length; i++) {
                        row = rows[i];
                        dom.removeTextSiblings(row);
                        focusElement = dom.next(row) || dom.prev(row);
                        focusElement = focusElement.cells[0];
                        dom.remove(row);
                    }
                }
                if (focusElement) {
                    range.setStart(focusElement, 0);
                    range.collapse(true);
                    this.editor.selectRange(range);
                }
            }
        });
        var DeleteColumnCommand = Command.extend({
            exec: function () {
                var range = this.lockRange(), td = dom.closest(range.endContainer, 'td'), table = dom.closest(td, 'table'), rows = table.rows, columnIndex = dom.findNodeIndex(td, true), columnCount = rows[0].cells.length, focusElement, i;
                if (this.immutables() && Editor.Immutables.immutableParent(td)) {
                    return;
                }
                if (columnCount == 1) {
                    focusElement = dom.next(table);
                    if (!focusElement || dom.insignificant(focusElement)) {
                        focusElement = dom.prev(table);
                    }
                    dom.remove(table);
                } else {
                    dom.removeTextSiblings(td);
                    focusElement = dom.next(td) || dom.prev(td);
                    for (i = 0; i < rows.length; i++) {
                        dom.remove(rows[i].cells[columnIndex]);
                    }
                }
                if (focusElement) {
                    range.setStart(focusElement, 0);
                    range.collapse(true);
                    this.editor.selectRange(range);
                }
            }
        });
        var TableModificationTool = Tool.extend({
            command: function (options) {
                options = extend(options, this.options);
                if (options.action == 'delete') {
                    if (options.type == 'row') {
                        return new DeleteRowCommand(options);
                    } else {
                        return new DeleteColumnCommand(options);
                    }
                } else {
                    if (options.type == 'row') {
                        return new InsertRowCommand(options);
                    } else {
                        return new InsertColumnCommand(options);
                    }
                }
            },
            initialize: function (ui, options) {
                Tool.fn.initialize.call(this, ui, options);
                ui.addClass('k-state-disabled');
            },
            update: function (ui, nodes) {
                var isFormatted = !tableFormatFinder.isFormatted(nodes);
                ui.toggleClass('k-state-disabled', isFormatted);
            }
        });
        extend(kendo.ui.editor, {
            PopupTool: PopupTool,
            TableCommand: TableCommand,
            InsertTableTool: InsertTableTool,
            TableModificationTool: TableModificationTool,
            InsertRowCommand: InsertRowCommand,
            InsertColumnCommand: InsertColumnCommand,
            DeleteRowCommand: DeleteRowCommand,
            DeleteColumnCommand: DeleteColumnCommand
        });
        registerTool('createTable', new InsertTableTool({
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                popup: true,
                title: 'Create table'
            })
        }));
        registerTool('addColumnLeft', new TableModificationTool({
            type: 'column',
            position: 'before',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Add column on the left'
            })
        }));
        registerTool('addColumnRight', new TableModificationTool({
            type: 'column',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Add column on the right'
            })
        }));
        registerTool('addRowAbove', new TableModificationTool({
            type: 'row',
            position: 'before',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Add row above'
            })
        }));
        registerTool('addRowBelow', new TableModificationTool({
            type: 'row',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Add row below'
            })
        }));
        registerTool('deleteRow', new TableModificationTool({
            type: 'row',
            action: 'delete',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Delete row'
            })
        }));
        registerTool('deleteColumn', new TableModificationTool({
            type: 'column',
            action: 'delete',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Delete column'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/clipboard', ['editor/command'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, editorNS = kendo.ui.editor, RangeUtils = editorNS.RangeUtils, dom = editorNS.Dom, RestorePoint = editorNS.RestorePoint, Marker = editorNS.Marker, browser = kendo.support.browser, extend = $.extend;
        var Clipboard = Class.extend({
            init: function (editor) {
                this.editor = editor;
                var pasteCleanup = editor.options.pasteCleanup;
                this.cleaners = [
                    new ScriptCleaner(pasteCleanup),
                    new TabCleaner(pasteCleanup),
                    new MSWordFormatCleaner(pasteCleanup),
                    new WebkitFormatCleaner(pasteCleanup),
                    new HtmlTagsCleaner(pasteCleanup),
                    new HtmlAttrCleaner(pasteCleanup),
                    new HtmlContentCleaner(pasteCleanup),
                    new CustomCleaner(pasteCleanup)
                ];
            },
            htmlToFragment: function (html) {
                var editor = this.editor, doc = editor.document, container = dom.create(doc, 'div'), fragment = doc.createDocumentFragment();
                container.innerHTML = html;
                while (container.firstChild) {
                    fragment.appendChild(container.firstChild);
                }
                return fragment;
            },
            isBlock: function (html) {
                return /<(div|p|ul|ol|table|h[1-6])/i.test(html);
            },
            _startModification: function () {
                var range;
                var restorePoint;
                var editor = this.editor;
                if (this._inProgress) {
                    return;
                }
                this._inProgress = true;
                range = editor.getRange();
                restorePoint = new RestorePoint(range, editor.body);
                dom.persistScrollTop(editor.document);
                return {
                    range: range,
                    restorePoint: restorePoint
                };
            },
            _endModification: function (modificationInfo) {
                editorNS._finishUpdate(this.editor, modificationInfo.restorePoint);
                this.editor._selectionChange();
                this._inProgress = false;
            },
            _contentModification: function (before, after) {
                var that = this;
                var editor = that.editor;
                var modificationInfo = that._startModification();
                if (!modificationInfo) {
                    return;
                }
                before.call(that, editor, modificationInfo.range);
                setTimeout(function () {
                    after.call(that, editor, modificationInfo.range);
                    that._endModification(modificationInfo);
                });
            },
            _removeBomNodes: function (range) {
                var nodes = RangeUtils.textNodes(range);
                for (var i = 0; i < nodes.length; i++) {
                    nodes[i].nodeValue = dom.stripBom(nodes[i].nodeValue) || nodes[i].nodeValue;
                }
            },
            _onBeforeCopy: function (range) {
                var marker = new Marker();
                marker.add(range);
                this._removeBomNodes(range);
                marker.remove(range);
                this.editor.selectRange(range);
            },
            oncopy: function () {
                this._onBeforeCopy(this.editor.getRange());
            },
            oncut: function () {
                this._onBeforeCopy(this.editor.getRange());
                this._contentModification($.noop, $.noop);
            },
            _fileToDataURL: function (blob) {
                var deferred = $.Deferred();
                var reader = new FileReader();
                if (!(blob instanceof window.File) && blob.getAsFile) {
                    blob = blob.getAsFile();
                }
                reader.onload = $.proxy(deferred.resolve, deferred);
                reader.readAsDataURL(blob);
                return deferred.promise();
            },
            _triggerPaste: function (html, options) {
                var args = { html: html || '' };
                args.html = args.html.replace(/\ufeff/g, '');
                this.editor.trigger('paste', args);
                this.paste(args.html, options || {});
            },
            _handleImagePaste: function (e) {
                if (!('FileReader' in window) || browser.msie && browser.version > 10) {
                    return;
                }
                var clipboardData = e.clipboardData || e.originalEvent.clipboardData || window.clipboardData || {};
                var items = clipboardData.items || clipboardData.files;
                return this._insertImages(items);
            },
            _insertImages: function (items) {
                if (!items) {
                    return;
                }
                var images = $.grep(items, function (item) {
                    return /^image\//i.test(item.type);
                });
                var html = $.grep(items, function (item) {
                    return /^text\/html/i.test(item.type);
                });
                if (html.length || !images.length) {
                    return;
                }
                var modificationInfo = this._startModification();
                if (!modificationInfo) {
                    return;
                }
                $.when.apply($, $.map(images, this._fileToDataURL)).done($.proxy(function () {
                    var results = Array.prototype.slice.call(arguments);
                    var html = $.map(results, function (e) {
                        return '<img src="' + e.target.result + '" />';
                    }).join('');
                    this._triggerPaste(html);
                    this._endModification(modificationInfo);
                }, this));
                return true;
            },
            onpaste: function (e) {
                if (this.editor.body.contentEditable === 'false') {
                    return;
                }
                if (this._handleImagePaste(e)) {
                    e.preventDefault();
                    return;
                }
                this.expandImmutablesIn();
                this._contentModification(function beforePaste(editor, range) {
                    var clipboardNode = dom.create(editor.document, 'div', {
                        className: 'k-paste-container',
                        innerHTML: '\uFEFF'
                    });
                    var browser = kendo.support.browser;
                    var body = editor.body;
                    this._decoreateClipboardNode(clipboardNode, body);
                    body.appendChild(clipboardNode);
                    if (browser.webkit) {
                        this._moveToCaretPosition(clipboardNode, range);
                    }
                    if (browser.msie && browser.version < 11) {
                        e.preventDefault();
                        var r = editor.createRange();
                        r.selectNodeContents(clipboardNode);
                        editor.selectRange(r);
                        var textRange = editor.document.body.createTextRange();
                        textRange.moveToElementText(clipboardNode);
                        $(body).unbind('paste');
                        textRange.execCommand('Paste');
                        $(body).bind('paste', $.proxy(this.onpaste, this));
                    } else {
                        var clipboardRange = editor.createRange();
                        clipboardRange.selectNodeContents(clipboardNode);
                        editor.selectRange(clipboardRange);
                    }
                    range.deleteContents();
                }, function afterPaste(editor, range) {
                    var html = '', containers;
                    editor.selectRange(range);
                    containers = $(editor.body).children('.k-paste-container');
                    containers.each(function () {
                        var lastChild = this.lastChild;
                        if (lastChild && dom.is(lastChild, 'br')) {
                            dom.remove(lastChild);
                        }
                        html += this.innerHTML;
                    });
                    containers.remove();
                    this._triggerPaste(html, { clean: true });
                });
            },
            ondragover: function (e) {
                if (browser.msie || browser.edge) {
                    e.stopPropagation();
                    e.preventDefault();
                }
            },
            ondrop: function (e) {
                if (!('FileReader' in window)) {
                    return;
                }
                var dataTransfer = (e.originalEvent || e).dataTransfer || {};
                var items = dataTransfer.items || dataTransfer.files;
                if (this._insertImages(items)) {
                    e.preventDefault();
                }
            },
            _decoreateClipboardNode: function (node, body) {
                if (!browser.msie && !browser.webkit) {
                    return;
                }
                node = $(node);
                node.css({
                    borderWidth: '0px',
                    width: '0px',
                    height: '0px',
                    overflow: 'hidden',
                    margin: '0',
                    padding: '0'
                });
                if (browser.msie) {
                    var documentElement = $(body.ownerDocument.documentElement);
                    node.css({
                        fontVariant: 'normal',
                        fontWeight: 'normal',
                        lineSpacing: 'normal',
                        lineHeight: 'normal',
                        textDecoration: 'none'
                    });
                    var color = documentElement.css('color');
                    if (color) {
                        node.css('color', color);
                    }
                    var fontFamily = documentElement.css('fontFamily');
                    if (fontFamily) {
                        node.css('fontFamily', fontFamily);
                    }
                    var fontSize = documentElement.css('fontSize');
                    if (fontSize) {
                        node.css('fontSize', fontSize);
                    }
                }
            },
            _moveToCaretPosition: function (node, range) {
                var that = this;
                var body = that.editor.body;
                var nodeOffset = dom.offset(node, body);
                var caretOffset = that._caretOffset(range, body);
                var translateX = caretOffset.left - nodeOffset.left;
                var translateY = caretOffset.top - nodeOffset.top;
                var translate = 'translate(' + translateX + 'px,' + translateY + 'px)';
                $(node).css({
                    '-webkit-transform': translate,
                    'transform': translate
                });
            },
            _caretOffset: function (range, body) {
                var editor = this.editor;
                var caret = dom.create(editor.document, 'span', { innerHTML: '\uFEFF' });
                var startContainer = range.startContainer;
                var rangeChanged;
                if (range.collapsed) {
                    var isStartTextNode = dom.isDataNode(startContainer);
                    if (isStartTextNode && (dom.isBom(startContainer) || range.startOffset === 0)) {
                        dom.insertBefore(caret, startContainer);
                    } else if (isStartTextNode && range.startOffset === startContainer.length) {
                        dom.insertAfter(caret, startContainer);
                    } else {
                        range.insertNode(caret);
                        rangeChanged = true;
                    }
                } else {
                    startContainer = startContainer === body ? startContainer.childNodes[range.startOffset] : startContainer;
                    dom.insertBefore(caret, startContainer);
                }
                var offset = dom.offset(caret, body);
                var prev = caret.previousSibling;
                var next = caret.nextSibling;
                dom.remove(caret);
                if (rangeChanged && dom.isDataNode(prev) && dom.isDataNode(next) && !dom.isBom(prev) && !dom.isBom(next)) {
                    var prevLength = prev.length;
                    next.data = prev.data + next.data;
                    range.setStart(next, prevLength);
                    dom.remove(prev);
                    range.collapse(true);
                    editor.selectRange(range);
                }
                return offset;
            },
            expandImmutablesIn: function (range) {
                var editor = this.editor;
                if (editor && editor.options.immutables) {
                    var body = editor.body;
                    range = range || editor.getRange();
                    kendo.ui.editor.Immutables.expandImmutablesIn(range);
                    if (range.startContainer === body && range.startOffset === 0) {
                        var doc = body.ownerDocument;
                        var bomNode = doc.createTextNode('\uFEFF');
                        body.insertBefore(bomNode, body.childNodes[0]);
                        range.setStartBefore(bomNode);
                    }
                    editor.selectRange(range);
                }
            },
            splittableParent: function (block, node) {
                var parentNode, body;
                if (block) {
                    return dom.closestEditableOfType(node, [
                        'p',
                        'ul',
                        'ol'
                    ]) || node.parentNode;
                }
                parentNode = node.parentNode;
                body = node.ownerDocument.body;
                if (dom.isInline(parentNode)) {
                    while (parentNode.parentNode != body && !dom.isBlock(parentNode.parentNode)) {
                        parentNode = parentNode.parentNode;
                    }
                }
                return parentNode;
            },
            paste: function (html, options) {
                var editor = this.editor, i, l, childNodes;
                this.expandImmutablesIn();
                options = extend({
                    clean: false,
                    split: true
                }, options);
                if (!options.skipCleaners) {
                    for (i = 0, l = this.cleaners.length; i < l; i++) {
                        if (this.cleaners[i].applicable(html)) {
                            html = this.cleaners[i].clean(html);
                        }
                    }
                }
                if (options.clean) {
                    html = html.replace(/(<br>(\s|&nbsp;)*)+(<\/?(div|p|li|col|t))/gi, '$3');
                    html = html.replace(/<(a|span)[^>]*><\/\1>/gi, '');
                }
                html = html.replace(/<(a|span|font)([^>]*)> <\/\1>/gi, '<$1$2>&nbsp;</$1>');
                html = html.replace(/^<li/i, '<ul><li').replace(/li>$/g, 'li></ul>');
                var block = this.isBlock(html);
                editor.focus();
                var range = editor.getRange();
                range.deleteContents();
                if (range.startContainer == editor.document) {
                    range.selectNodeContents(editor.body);
                }
                var marker = new Marker();
                var caret = marker.addCaret(range);
                var parent = this.splittableParent(block, caret);
                var unwrap = false;
                var splittable = parent != editor.body && !dom.is(parent, 'td');
                if (options.split && splittable && (block || dom.isInline(parent))) {
                    range.selectNode(caret);
                    RangeUtils.split(range, parent, true);
                    unwrap = true;
                }
                var fragment = this.htmlToFragment(html);
                if (fragment.firstChild && fragment.firstChild.className === 'k-paste-container') {
                    var fragmentsHtml = [];
                    for (i = 0, l = fragment.childNodes.length; i < l; i++) {
                        fragmentsHtml.push(fragment.childNodes[i].innerHTML);
                    }
                    fragment = this.htmlToFragment(fragmentsHtml.join('<br />'));
                }
                childNodes = fragment.childNodes;
                $(childNodes).filter('table').addClass('k-table').end().find('table').addClass('k-table');
                $(childNodes).each(function (index, elm) {
                    if (dom.isBlock(elm) && !dom.isSelfClosing(elm) && elm.innerHTML === '') {
                        elm.appendChild(editor.document.createTextNode('\uFEFF'));
                    }
                });
                range.insertNode(fragment);
                parent = this.splittableParent(block, caret);
                if (unwrap) {
                    while (caret.parentNode != parent) {
                        dom.unwrap(caret.parentNode);
                    }
                    dom.unwrap(caret.parentNode);
                }
                dom.normalize(range.commonAncestorContainer);
                caret.style.display = 'inline';
                dom.restoreScrollTop(editor.document);
                dom.scrollTo(caret);
                marker.removeCaret(range);
                var rangeEnd = range.commonAncestorContainer.parentNode;
                if (range.collapsed && dom.name(rangeEnd) == 'tbody') {
                    range.setStartAfter($(rangeEnd).closest('table')[0]);
                    range.collapse(true);
                }
                var focusedTable = $(range.commonAncestorContainer.parentNode).closest('table');
                if (focusedTable.get(0)) {
                    var siblingNodes = focusedTable.parent().contents();
                    var lastSiblingIndex = siblingNodes.length - 1;
                    var lastSibling = siblingNodes.get(lastSiblingIndex);
                    while (lastSibling.nodeValue !== null && (lastSibling.nodeValue === ' ' || lastSibling.nodeValue === '')) {
                        lastSiblingIndex -= 1;
                        lastSibling = siblingNodes.get(lastSiblingIndex);
                    }
                    if (lastSibling === focusedTable.get(0)) {
                        dom.insertAfter(dom.createEmptyNode(editor.document, 'p'), focusedTable[0]);
                    }
                }
                editor.selectRange(range);
            }
        });
        var Cleaner = Class.extend({
            init: function (options) {
                this.options = options || {};
                this.replacements = [];
            },
            clean: function (html, customReplacements) {
                var that = this, replacements = customReplacements || that.replacements, i, l;
                for (i = 0, l = replacements.length; i < l; i += 2) {
                    html = html.replace(replacements[i], replacements[i + 1]);
                }
                return html;
            }
        });
        var ScriptCleaner = Cleaner.extend({
            init: function (options) {
                Cleaner.fn.init.call(this, options);
                this.replacements = [
                    /<(\/?)script([^>]*)>/i,
                    '<$1telerik:script$2>'
                ];
            },
            applicable: function (html) {
                return !this.options.none && /<script[^>]*>/i.test(html);
            }
        });
        var TabCleaner = Cleaner.extend({
            init: function (options) {
                Cleaner.fn.init.call(this, options);
                var replacement = ' ';
                this.replacements = [
                    /<span\s+class="Apple-tab-span"[^>]*>\s*<\/span>/gi,
                    replacement,
                    /\t/gi,
                    replacement,
                    /&nbsp;&nbsp; &nbsp;/gi,
                    replacement
                ];
            },
            applicable: function (html) {
                return /&nbsp;&nbsp; &nbsp;|class="?Apple-tab-span/i.test(html);
            }
        });
        var MSWordFormatCleaner = Cleaner.extend({
            init: function (options) {
                Cleaner.fn.init.call(this, options);
                this.junkReplacements = [
                    /<\?xml[^>]*>/gi,
                    '',
                    /<!--(.|\n)*?-->/g,
                    '',
                    /&quot;/g,
                    '\'',
                    /<o:p>&nbsp;<\/o:p>/gi,
                    '&nbsp;',
                    /<\/?(meta|link|style|o:|v:|x:)[^>]*>((?:.|\n)*?<\/(meta|link|style|o:|v:|x:)[^>]*>)?/gi,
                    '',
                    /<\/o>/g,
                    ''
                ];
                this.replacements = this.junkReplacements.concat([
                    /(?:<br>&nbsp;[\s\r\n]+|<br>)*(<\/?(h[1-6]|hr|p|div|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|address|pre|form|blockquote|dl|dt|dd|dir|fieldset)[^>]*>)(?:<br>&nbsp;[\s\r\n]+|<br>)*/g,
                    '$1',
                    /<br><br>/g,
                    '<BR><BR>',
                    /<br>(?!\n)/g,
                    ' ',
                    /<table([^>]*)>(\s|&nbsp;)+<t/gi,
                    '<table$1><t',
                    /<tr[^>]*>(\s|&nbsp;)*<\/tr>/gi,
                    '',
                    /<tbody[^>]*>(\s|&nbsp;)*<\/tbody>/gi,
                    '',
                    /<table[^>]*>(\s|&nbsp;)*<\/table>/gi,
                    '',
                    /<BR><BR>/g,
                    '<br>',
                    /^\s*(&nbsp;)+/gi,
                    '',
                    /(&nbsp;|<br[^>]*>)+\s*$/gi,
                    '',
                    /mso-[^;"]*;?/gi,
                    '',
                    /<(\/?)b(\s[^>]*)?>/gi,
                    '<$1strong$2>',
                    /<(\/?)font(\s[^>]*)?>/gi,
                    this.convertFontMatch,
                    /<(\/?)i(\s[^>]*)?>/gi,
                    '<$1em$2>',
                    /style=(["|'])\s*\1/g,
                    '',
                    /(<br[^>]*>)?\n/g,
                    function ($0, $1) {
                        return $1 ? $0 : ' ';
                    }
                ]);
            },
            convertFontMatch: function (match, closing, args) {
                var faceRe = /face=['"]([^'"]+)['"]/i;
                var face = faceRe.exec(args);
                var family = args && face && face[1];
                if (closing) {
                    return '</span>';
                } else if (family) {
                    return '<span style="font-family:' + family + '">';
                } else {
                    return '<span>';
                }
            },
            applicable: function (html) {
                return /class="?Mso/i.test(html) || /style="[^"]*mso-/i.test(html) || /urn:schemas-microsoft-com:office/.test(html);
            },
            stripEmptyAnchors: function (html) {
                return html.replace(/<a([^>]*)>\s*<\/a>/gi, function (a, attributes) {
                    if (!attributes || attributes.indexOf('href') < 0) {
                        return '';
                    }
                    return a;
                });
            },
            listType: function (p, listData) {
                var html = p.innerHTML;
                var text = dom.innerText(p);
                var startingSymbol;
                var matchSymbol = html.match(/^(?:<span [^>]*texhtml[^>]*>)?<span [^>]*(?:Symbol|Wingdings)[^>]*>([^<]+)/i);
                var symbol = matchSymbol && matchSymbol[1];
                var isNumber = /^[a-z\d]/i.test(symbol);
                var trimStartText = function (text) {
                    return text.replace(/^(?:&nbsp;|[\u00a0\n\r\s])+/, '');
                };
                if (matchSymbol) {
                    startingSymbol = true;
                }
                html = html.replace(/<\/?\w+[^>]*>/g, '').replace(/&nbsp;/g, '\xA0');
                if (!startingSymbol && /^[\u2022\u00b7\u00a7\u00d8o]\u00a0+/.test(html) || startingSymbol && /^.\u00a0+/.test(html) || symbol && !isNumber && listData) {
                    return {
                        tag: 'ul',
                        style: this._guessUnorderedListStyle(trimStartText(text))
                    };
                }
                if (/^\s*\w+[\.\)][\u00a0 ]{2,}/.test(html)) {
                    return {
                        tag: 'ol',
                        style: this._guessOrderedListStyle(trimStartText(text))
                    };
                }
            },
            _convertToLi: function (p) {
                var content, name = dom.name(p);
                if (p.childNodes.length == 1) {
                    content = p.firstChild.nodeType === dom.nodeTypes.TEXT_NODE ? dom.innerText(p) : p.firstChild.innerHTML.replace(/^\w+[\.\)](&nbsp;)+ /, '');
                } else {
                    dom.remove(p.firstChild);
                    if (p.firstChild.nodeType == 3) {
                        if (/^[ivxlcdm]+\.$/i.test(p.firstChild.nodeValue)) {
                            dom.remove(p.firstChild);
                        }
                    }
                    if (/^(&nbsp;|\s)+$/i.test(p.firstChild.innerHTML)) {
                        dom.remove(p.firstChild);
                    }
                    if (name != 'p') {
                        content = '<' + name + '>' + p.innerHTML + '</' + name + '>';
                    } else {
                        content = p.innerHTML;
                    }
                }
                dom.remove(p);
                return dom.create(document, 'li', { innerHTML: content });
            },
            _guessUnorderedListStyle: function (symbol) {
                if (/^[\u2022\u00b7\u00FC\u00D8\u002dv-]/.test(symbol)) {
                    return null;
                } else if (/^o/.test(symbol)) {
                    return 'circle';
                } else {
                    return 'square';
                }
            },
            _guessOrderedListStyle: function (symbol) {
                var listType = null;
                if (!/^\d/.test(symbol)) {
                    listType = (/^[a-z]/.test(symbol) ? 'lower-' : 'upper-') + (/^[ivxlcdm]/i.test(symbol) ? 'roman' : 'alpha');
                }
                return listType;
            },
            extractListLevels: function (html) {
                var msoListRegExp = /style=['"]?[^'"]*?mso-list:\s?[a-zA-Z]+(\d+)\s[a-zA-Z]+(\d+)\s(\w+)/gi;
                html = html.replace(msoListRegExp, function (match, list, level) {
                    return kendo.format('data-list="{0}" data-level="{1}" {2}', list, level, match);
                });
                return html;
            },
            _createList: function (type, styleType) {
                return dom.create(document, type, { style: { listStyleType: styleType } });
            },
            lists: function (placeholder) {
                var blockChildren = $(placeholder).find(dom.blockElements.join(',')), lastMargin = -1, name, levels = {}, li, rootMargin, rootIndex, lastRootLi, isLastRootLi, rootList, i, p, type, margin, list, listData, acceptedNameTags = [
                        'p',
                        'h1',
                        'h2',
                        'h3',
                        'h4',
                        'h5',
                        'h6'
                    ];
                for (i = 0; i < blockChildren.length; i++) {
                    p = blockChildren[i];
                    listData = $(p).data();
                    var listIndex = listData.list;
                    name = dom.name(p);
                    if (name == 'td') {
                        continue;
                    }
                    var listType = this.listType(p, listData);
                    type = listType && listType.tag;
                    if (!type || acceptedNameTags.indexOf(name) < 0) {
                        if (!p.innerHTML) {
                            dom.remove(p);
                        } else if (li && !isLastRootLi) {
                            li.appendChild(p);
                        }
                        continue;
                    }
                    if (browser.msie) {
                        continue;
                    }
                    margin = listData.level || parseFloat(p.style.marginLeft || 0);
                    var levelType = type + listIndex;
                    if (!levels[margin]) {
                        levels[margin] = {};
                    }
                    if (!rootMargin || rootMargin < 0) {
                        rootMargin = margin;
                        rootIndex = listIndex;
                        lastRootLi = $(placeholder).find('[data-list=\'' + rootIndex + '\']:last')[0];
                        rootList = this._createList(type, listType.style);
                        dom.insertBefore(rootList, p);
                        lastMargin = margin;
                        levels[margin][levelType] = rootList;
                    }
                    isLastRootLi = lastRootLi === p;
                    list = levels[margin][levelType];
                    if (margin > lastMargin || !list) {
                        list = this._createList(type, listType.style);
                        levels[margin][levelType] = list;
                        li.appendChild(list);
                    }
                    li = this._convertToLi(p);
                    list.appendChild(li);
                    if (isLastRootLi) {
                        rootMargin = lastMargin = -1;
                    } else {
                        lastMargin = margin;
                    }
                }
            },
            removeAttributes: function (element) {
                var attributes = element.attributes, i = attributes.length;
                while (i--) {
                    if (dom.name(attributes[i]) != 'colspan') {
                        element.removeAttributeNode(attributes[i]);
                    }
                }
            },
            createColGroup: function (row) {
                var cells = row.cells;
                var table = $(row).closest('table');
                var colgroup = table.children('colgroup');
                if (cells.length < 2) {
                    return;
                } else if (colgroup.length) {
                    cells = colgroup.children();
                    colgroup[0].parentNode.removeChild(colgroup[0]);
                }
                colgroup = $($.map(cells, function (cell) {
                    var width = cell.width;
                    if (width && parseInt(width, 10) !== 0) {
                        return kendo.format('<col style="width:{0}px;"/>', width);
                    }
                    return '<col />';
                }).join(''));
                if (!colgroup.is('colgroup')) {
                    colgroup = $('<colgroup/>').append(colgroup);
                }
                colgroup.prependTo(table);
            },
            convertHeaders: function (row) {
                var cells = row.cells, i, boldedCells = $.map(cells, function (cell) {
                        var child = $(cell).children('p').children('strong')[0];
                        if (child && dom.name(child) == 'strong') {
                            return child;
                        }
                    });
                if (boldedCells.length == cells.length) {
                    for (i = 0; i < boldedCells.length; i++) {
                        dom.unwrap(boldedCells[i]);
                    }
                    $(row).closest('table').find('colgroup').after('<thead></thead>').end().find('thead').append(row);
                    for (i = 0; i < cells.length; i++) {
                        dom.changeTag(cells[i], 'th');
                    }
                }
            },
            removeParagraphs: function (cells) {
                var i, j, len, cell, paragraphs;
                for (i = 0; i < cells.length; i++) {
                    this.removeAttributes(cells[i]);
                    cell = $(cells[i]);
                    paragraphs = cell.children('p');
                    for (j = 0, len = paragraphs.length; j < len; j++) {
                        if (j < len - 1) {
                            dom.insertAfter(dom.create(document, 'br'), paragraphs[j]);
                        }
                        dom.unwrap(paragraphs[j]);
                    }
                }
            },
            removeDefaultColors: function (spans) {
                for (var i = 0; i < spans.length; i++) {
                    if (/^\s*color:\s*[^;]*;?$/i.test(spans[i].style.cssText)) {
                        dom.unwrap(spans[i]);
                    }
                }
            },
            tables: function (placeholder) {
                var tables = $(placeholder).find('table'), that = this, rows, firstRow, longestRow, i, j;
                for (i = 0; i < tables.length; i++) {
                    rows = tables[i].rows;
                    longestRow = firstRow = rows[0];
                    for (j = 1; j < rows.length; j++) {
                        if (rows[j].cells.length > longestRow.cells.length) {
                            longestRow = rows[j];
                        }
                    }
                    that.createColGroup(longestRow);
                    that.convertHeaders(firstRow);
                    that.removeAttributes(tables[i]);
                    that.removeParagraphs(tables.eq(i).find('td,th'));
                    that.removeDefaultColors(tables.eq(i).find('span'));
                }
            },
            headers: function (placeholder) {
                var titles = $(placeholder).find('p.MsoTitle');
                for (var i = 0; i < titles.length; i++) {
                    dom.changeTag(titles[i], 'h1');
                }
            },
            removeFormatting: function (placeholder) {
                $(placeholder).find('*').each(function () {
                    $(this).css({
                        fontSize: '',
                        fontFamily: ''
                    });
                    if (!this.getAttribute('style') && !this.style.cssText) {
                        this.removeAttribute('style');
                    }
                });
            },
            clean: function (html) {
                var that = this, placeholder;
                var filters = this.options;
                if (filters.none) {
                    html = Cleaner.fn.clean.call(that, html, this.junkReplacements);
                    html = that.stripEmptyAnchors(html);
                } else {
                    html = filters.msConvertLists ? this.extractListLevels(html) : html;
                    html = Cleaner.fn.clean.call(that, html);
                    html = that.stripEmptyAnchors(html);
                    placeholder = dom.create(document, 'div', { innerHTML: html });
                    that.headers(placeholder);
                    if (filters.msConvertLists) {
                        that.lists(placeholder);
                    }
                    that.tables(placeholder);
                    if (filters.msAllFormatting) {
                        that.removeFormatting(placeholder);
                    }
                    html = placeholder.innerHTML.replace(/(<[^>]*)\s+class="?[^"\s>]*"?/gi, '$1');
                }
                return html;
            }
        });
        var WebkitFormatCleaner = Cleaner.extend({
            init: function (options) {
                Cleaner.fn.init.call(this, options);
                this.replacements = [
                    /\s+class="Apple-style-span[^"]*"/gi,
                    '',
                    /<(div|p|h[1-6])\s+style="[^"]*"/gi,
                    '<$1',
                    /^<div>(.*)<\/div>$/,
                    '$1'
                ];
            },
            applicable: function (html) {
                return /class="?Apple-style-span|style="[^"]*-webkit-nbsp-mode/i.test(html);
            }
        });
        var DomCleaner = Cleaner.extend({
            clean: function (html) {
                var container = dom.create(document, 'div', { innerHTML: html });
                container = this.cleanDom(container);
                return container.innerHTML;
            },
            cleanDom: function (container) {
                return container;
            }
        });
        var HtmlTagsCleaner = DomCleaner.extend({
            cleanDom: function (container) {
                var tags = this.collectTags();
                $(container).find(tags).each(function () {
                    dom.unwrap(this);
                });
                return container;
            },
            collectTags: function () {
                if (this.options.span) {
                    return 'span';
                }
            },
            applicable: function () {
                return this.options.span;
            }
        });
        var HtmlAttrCleaner = DomCleaner.extend({
            cleanDom: function (container) {
                var attributes = this.collectAttr();
                var nodes = $(container).find('[' + attributes.join('],[') + ']');
                nodes.removeAttr(attributes.join(' '));
                return container;
            },
            collectAttr: function () {
                if (this.options.css) {
                    return [
                        'class',
                        'style'
                    ];
                }
                return [];
            },
            applicable: function () {
                return this.options.css;
            }
        });
        var TextContainer = function () {
            this.text = '';
            this.add = function (text) {
                this.text += text;
            };
        };
        var HtmlTextLines = Class.extend({
            init: function (separators) {
                this.separators = separators || {
                    text: ' ',
                    line: '<br/>'
                };
                this.lines = [];
                this.inlineBlockText = [];
                this.resetLine();
            },
            appendText: function (text) {
                if (text.nodeType === 3) {
                    text = text.nodeValue;
                }
                this.textContainer.add(text);
            },
            appendInlineBlockText: function (text) {
                this.inlineBlockText.push(text);
            },
            flashInlineBlockText: function () {
                if (this.inlineBlockText.length) {
                    this.appendText(this.inlineBlockText.join(' '));
                    this.inlineBlockText = [];
                }
            },
            endLine: function () {
                this.flashInlineBlockText();
                this.resetLine();
            },
            html: function () {
                var separators = this.separators;
                var result = '';
                var lines = this.lines;
                this.flashInlineBlockText();
                for (var i = 0, il = lines.length, il1 = il - 1; i < il; i++) {
                    var line = lines[i];
                    for (var j = 0, jl = line.length, jl1 = jl - 1; j < jl; j++) {
                        var text = line[j].text;
                        result += text;
                        if (j !== jl1) {
                            result += separators.text;
                        }
                    }
                    if (i !== il1) {
                        result += separators.line;
                    }
                }
                return result;
            },
            resetLine: function () {
                this.textContainer = new TextContainer();
                this.line = [];
                this.line.push(this.textContainer);
                this.lines.push(this.line);
            }
        });
        var DomEnumerator = Class.extend({
            init: function (callback) {
                this.callback = callback;
            },
            enumerate: function (node) {
                if (!node) {
                    return;
                }
                var preventDown = this.callback(node);
                var child = node.firstChild;
                if (!preventDown && child) {
                    this.enumerate(child);
                }
                this.enumerate(node.nextSibling);
            }
        });
        var HtmlContentCleaner = Cleaner.extend({
            init: function (options) {
                Cleaner.fn.init.call(this, options);
                this.hasText = false;
                this.enumerator = new DomEnumerator($.proxy(this.buildText, this));
            },
            clean: function (html) {
                var container = dom.create(document, 'div', { innerHTML: html });
                return this.cleanDom(container);
            },
            cleanDom: function (container) {
                this.separators = this.getDefaultSeparators();
                this.htmlLines = new HtmlTextLines(this.separators);
                this.enumerator.enumerate(container.firstChild);
                this.hasText = false;
                return this.htmlLines.html();
            },
            buildText: function (node) {
                if (dom.isDataNode(node)) {
                    if (dom.isEmptyspace(node)) {
                        return;
                    }
                    this.htmlLines.appendText(node.nodeValue.replace('\n', this.separators.line));
                    this.hasText = true;
                } else if (dom.isBlock(node) && this.hasText) {
                    var action = this.actions[dom.name(node)] || this.actions.block;
                    return action(this, node);
                } else if (dom.isBr(node)) {
                    this.htmlLines.appendText(this.separators.line);
                }
            },
            applicable: function () {
                var o = this.options;
                return o.all || o.keepNewLines;
            },
            getDefaultSeparators: function () {
                if (this.options.all) {
                    return {
                        text: ' ',
                        line: ' '
                    };
                } else {
                    return {
                        text: ' ',
                        line: '<br/>'
                    };
                }
            },
            actions: {
                ul: $.noop,
                ol: $.noop,
                table: $.noop,
                thead: $.noop,
                tbody: $.noop,
                td: function (cleaner, node) {
                    var tdCleaner = new HtmlContentCleaner({ all: true });
                    var cellText = tdCleaner.cleanDom(node);
                    cleaner.htmlLines.appendInlineBlockText(cellText);
                    return true;
                },
                block: function (cleaner) {
                    cleaner.htmlLines.endLine();
                }
            }
        });
        var CustomCleaner = Cleaner.extend({
            clean: function (html) {
                return this.options.custom(html);
            },
            applicable: function () {
                return typeof this.options.custom === 'function';
            }
        });
        extend(editorNS, {
            Clipboard: Clipboard,
            Cleaner: Cleaner,
            ScriptCleaner: ScriptCleaner,
            TabCleaner: TabCleaner,
            MSWordFormatCleaner: MSWordFormatCleaner,
            WebkitFormatCleaner: WebkitFormatCleaner,
            HtmlTagsCleaner: HtmlTagsCleaner,
            HtmlAttrCleaner: HtmlAttrCleaner,
            HtmlContentCleaner: HtmlContentCleaner,
            HtmlTextLines: HtmlTextLines,
            CustomCleaner: CustomCleaner
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/keyboard', ['editor/command'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, editorNS = kendo.ui.editor, RangeUtils = editorNS.RangeUtils, dom = editorNS.Dom, RestorePoint = editorNS.RestorePoint, Marker = editorNS.Marker, browser = kendo.support.browser, br = '<br class="k-br">', extend = $.extend;
        var nodeTypes = dom.nodeTypes;
        var PREVIOUS_SIBLING = 'previousSibling';
        function selected(node, range) {
            return range.startContainer === node && range.endContainer === node && range.startOffset === 0 && range.endOffset == node.childNodes.length;
        }
        function getSibling(node, direction, condition) {
            var sibling = node ? node[direction] : null;
            while (sibling && !condition(sibling)) {
                sibling = sibling[direction];
            }
            return sibling;
        }
        var tableCells = 'td,th,caption';
        var tableCellsWrappers = 'table,tbody,thead,tfoot,tr';
        var tableElements = tableCellsWrappers + ',' + tableCells;
        var inTable = function (range) {
            return !range.collapsed && $(range.commonAncestorContainer).is(tableCellsWrappers);
        };
        var RemoveTableContent = Class.extend({
            remove: function (range) {
                var that = this;
                var marker = new Marker();
                marker.add(range, false);
                var nodes = RangeUtils.getAll(range, function (node) {
                    return $(node).is(tableElements);
                });
                var doc = RangeUtils.documentFromRange(range);
                var start = marker.start;
                var end = marker.end;
                var cellsTypes = tableCells.split(',');
                var startCell = dom.parentOfType(start, cellsTypes);
                var endCell = dom.parentOfType(end, cellsTypes);
                that._removeContent(start, startCell, true);
                that._removeContent(end, endCell, false);
                $(nodes).each(function (i, node) {
                    node = $(node);
                    (node.is(tableCells) ? node : node.find(tableCells)).each(function (j, cell) {
                        cell.innerHTML = '&#65279;';
                    });
                });
                if (startCell && !start.previousSibling) {
                    dom.insertBefore(doc.createTextNode('\uFEFF'), start);
                }
                if (endCell && !end.nextSibling) {
                    dom.insertAfter(doc.createTextNode('\uFEFF'), end);
                }
                if (startCell) {
                    range.setStartBefore(start);
                } else if (nodes[0]) {
                    startCell = $(nodes[0]);
                    startCell = startCell.is(tableCells) ? startCell : startCell.find(tableCells).first();
                    if (startCell.length) {
                        range.setStart(startCell.get(0), 0);
                    }
                }
                range.collapse(true);
                dom.remove(start);
                dom.remove(end);
            },
            _removeContent: function (start, top, forwards) {
                if (top) {
                    var sibling = forwards ? 'nextSibling' : 'previousSibling', next, getNext = function (node) {
                            while (node && !node[sibling]) {
                                node = node.parentNode;
                            }
                            return node && $.contains(top, node) ? node[sibling] : null;
                        };
                    start = getNext(start);
                    while (start) {
                        next = getNext(start);
                        dom.remove(start);
                        start = next;
                    }
                }
            }
        });
        var TypingHandler = Class.extend({
            init: function (editor) {
                this.editor = editor;
            },
            keydown: function (e) {
                var that = this, editor = that.editor, keyboard = editor.keyboard, isTypingKey = keyboard.isTypingKey(e), evt = extend($.Event(), e);
                that.editor.trigger('keydown', evt);
                if (evt.isDefaultPrevented()) {
                    e.preventDefault();
                    return true;
                }
                if (!evt.isDefaultPrevented() && isTypingKey && !keyboard.isTypingInProgress()) {
                    var range = editor.getRange();
                    var body = editor.body;
                    that.startRestorePoint = new RestorePoint(range, body);
                    if (inTable(range)) {
                        var removeTableContent = new RemoveTableContent(editor);
                        removeTableContent.remove(range);
                        editor.selectRange(range);
                    }
                    if (browser.webkit && !range.collapsed && selected(body, range)) {
                        body.innerHTML = '';
                    }
                    if (editor.immutables && editorNS.Immutables.immutablesContext(range)) {
                        var backspaceHandler = new editorNS.BackspaceHandler(editor);
                        backspaceHandler.deleteSelection(range);
                    }
                    keyboard.startTyping(function () {
                        that.endRestorePoint = editorNS._finishUpdate(editor, that.startRestorePoint);
                    });
                    return true;
                }
                return false;
            },
            keyup: function (e) {
                var keyboard = this.editor.keyboard;
                this.editor.trigger('keyup', e);
                if (keyboard.isTypingInProgress()) {
                    keyboard.endTyping();
                    return true;
                }
                return false;
            }
        });
        var BackspaceHandler = Class.extend({
            init: function (editor) {
                this.editor = editor;
            },
            _addCaret: function (container) {
                var caret = dom.create(this.editor.document, 'a');
                if (!kendo.support.browser.chrome && container.firstChild && container.firstChild.nodeType === nodeTypes.ELEMENT_NODE) {
                    container = container.firstChild;
                }
                dom.insertAt(container, caret, 0);
                dom.stripBomNode(caret.previousSibling);
                dom.stripBomNode(caret.nextSibling);
                return caret;
            },
            _restoreCaret: function (caret) {
                var range = this.editor.createRange();
                if (!caret.nextSibling && dom.isDataNode(caret.previousSibling)) {
                    range.setStart(caret.previousSibling, caret.previousSibling.length);
                } else {
                    range.setStartAfter(caret);
                }
                range.collapse(true);
                this.editor.selectRange(range);
                dom.remove(caret);
            },
            _handleDelete: function (range) {
                var node = range.endContainer;
                var block = dom.closestEditableOfType(node, dom.blockElements);
                if (block && editorNS.RangeUtils.isEndOf(range, block)) {
                    var next = dom.next(block);
                    if (!next || dom.name(next) != 'p') {
                        return false;
                    }
                    var caret = this._addCaret(next);
                    this._merge(block, next);
                    this._restoreCaret(caret);
                    return true;
                }
                return false;
            },
            _cleanBomBefore: function (range) {
                var offset = range.startOffset;
                var node = range.startContainer;
                var text = node.nodeValue;
                var count = 0;
                while (offset - count >= 0 && text[offset - count - 1] == '\uFEFF') {
                    count++;
                }
                if (count > 0) {
                    node.deleteData(offset - count, count);
                    range.setStart(node, Math.max(0, offset - count));
                    range.collapse(true);
                    this.editor.selectRange(range);
                }
            },
            _handleBackspace: function (range) {
                var node = range.startContainer;
                var li = dom.closestEditableOfType(node, ['li']);
                var block = dom.closestEditableOfType(node, 'p,h1,h2,h3,h4,h5,h6'.split(','));
                var editor = this.editor;
                var previousSibling;
                if (dom.isDataNode(node)) {
                    if (range.collapsed && /^\s[\ufeff]+$/.test(node.nodeValue)) {
                        range.setStart(node, 0);
                        range.setEnd(node, node.length);
                        editor.selectRange(range);
                        return false;
                    }
                    this._cleanBomBefore(range);
                }
                previousSibling = getSibling(block, PREVIOUS_SIBLING, function (sibling) {
                    return !dom.htmlIndentSpace(sibling);
                });
                if (range.collapsed && range.startOffset !== range.endOffset && range.startOffset < 0) {
                    range.startOffset = 0;
                    range.endOffset = 0;
                    editor.selectRange(range);
                }
                var startAtLi = li && editorNS.RangeUtils.isStartOf(range, li);
                var liIndex = li && $(li).index();
                var startAtNonFirstLi = startAtLi && liIndex > 0;
                if (startAtNonFirstLi) {
                    block = li;
                    previousSibling = dom.prev(li);
                }
                if (block && previousSibling && dom.is(previousSibling, 'table') && editorNS.RangeUtils.isStartOf(range, block)) {
                    if (block.innerText === '') {
                        block.innerHTML = '\uFEFF';
                    }
                    return true;
                }
                if (editorNS.RangeUtils.isStartOf(range, block) && (parseInt(block.style.marginLeft, 10) > 0 || parseInt(block.style.marginRight, 10) > 0)) {
                    editor.exec('outdent');
                    return true;
                }
                if (block && previousSibling && editorNS.RangeUtils.isStartOf(range, block) || startAtNonFirstLi) {
                    var caret = this._addCaret(block);
                    this._merge(previousSibling, block);
                    this._restoreCaret(caret);
                    return true;
                }
                if (startAtLi && liIndex === 0) {
                    var child = li.firstChild;
                    if (!child) {
                        li.innerHTML = editorNS.emptyElementContent;
                        child = li.firstChild;
                    }
                    var formatter = new editorNS.ListFormatter(dom.name(li.parentNode), 'p');
                    range.selectNodeContents(li);
                    formatter.toggle(range);
                    if (dom.insignificant(child)) {
                        range.setStartBefore(child);
                    } else {
                        range.setStart(child, 0);
                    }
                    editor.selectRange(range);
                    return true;
                }
                var rangeStartNode = node.childNodes[range.startOffset - 1];
                var linkRange = range;
                var anchor = rangeStartNode && dom.closestEditableOfType(rangeStartNode, ['a']);
                var previousNode = getSibling(rangeStartNode || node, PREVIOUS_SIBLING, function (sibling) {
                    return !dom.isDataNode(sibling) || !dom.isBom(sibling) && sibling.length > 0;
                });
                if (anchor || (range.startOffset === 0 || rangeStartNode) && dom.is(previousNode, 'a')) {
                    anchor = anchor || previousNode;
                    linkRange = editor.createRange();
                    linkRange.setStart(anchor, anchor.childNodes.length);
                    linkRange.collapse(true);
                }
                anchor = anchor || dom.closestEditableOfType(rangeStartNode || linkRange.startContainer, ['a']);
                var isEndOfLink = anchor && editorNS.RangeUtils.isEndOf(linkRange, anchor);
                if (isEndOfLink) {
                    var command = new editorNS.UnlinkCommand({
                        range: linkRange,
                        body: editor.body,
                        immutables: !!editor.immutables
                    });
                    editor.execCommand(command);
                    editor._selectionChange();
                }
                return false;
            },
            _handleSelection: function (range) {
                var ancestor = range.commonAncestorContainer;
                var table = dom.closest(ancestor, 'table');
                var emptyParagraphContent = editorNS.emptyElementContent;
                var editor = this.editor;
                if (inTable(range)) {
                    var removeTableContent = new RemoveTableContent(editor);
                    removeTableContent.remove(range);
                    editor.selectRange(range);
                    return true;
                }
                var marker = new Marker();
                marker.add(range, false);
                if (range.commonAncestorContainer === editor.body) {
                    this._surroundFullyContent(marker, range);
                }
                if (editor.immutables) {
                    this._handleImmutables(marker);
                }
                this._surroundFullySelectedAnchor(marker, range);
                range.setStartAfter(marker.start);
                range.setEndBefore(marker.end);
                var start = range.startContainer;
                var end = range.endContainer;
                range.deleteContents();
                if (end.tagName.toLocaleLowerCase() === 'li' && dom.emptyNode(end)) {
                    range.selectNode(end);
                    range.deleteContents();
                }
                if (table && $(table).text() === '') {
                    range.selectNode(table);
                    range.deleteContents();
                }
                ancestor = range.commonAncestorContainer;
                if (dom.name(ancestor) === 'p' && ancestor.innerHTML === '') {
                    ancestor.innerHTML = emptyParagraphContent;
                    range.setStart(ancestor, 0);
                }
                this._join(start, end);
                dom.insertAfter(editor.document.createTextNode('\uFEFF'), marker.start);
                marker.remove(range);
                start = range.startContainer;
                if (dom.name(start) == 'tr') {
                    start = start.childNodes[Math.max(0, range.startOffset - 1)];
                    range.setStart(start, dom.getNodeLength(start));
                }
                range.collapse(true);
                editor.selectRange(range);
                return true;
            },
            _handleImmutables: function (marker) {
                var immutableParent = editorNS.Immutables.immutableParent;
                var startImmutable = immutableParent(marker.start);
                var endImmutable = immutableParent(marker.start);
                if (startImmutable) {
                    dom.insertBefore(marker.start, startImmutable);
                }
                if (endImmutable) {
                    dom.insertAfter(marker.end, endImmutable);
                }
                if (startImmutable) {
                    dom.remove(startImmutable);
                }
                if (endImmutable && endImmutable.parentNode) {
                    dom.remove(endImmutable);
                }
            },
            _surroundFullyContent: function (marker, range) {
                var children = range.commonAncestorContainer.children, startParent = children[0], endParent = children[children.length - 1];
                this._moveMarker(marker, range, startParent, endParent);
            },
            _surroundFullySelectedAnchor: function (marker, range) {
                var start = marker.start, startParent = $(start).closest('a').get(0), end = marker.end, endParent = $(end).closest('a').get(0);
                this._moveMarker(marker, range, startParent, endParent);
            },
            _moveMarker: function (marker, range, startParent, endParent) {
                var start = marker.start, end = marker.end;
                if (startParent && RangeUtils.isStartOf(range, startParent)) {
                    dom.insertBefore(start, startParent);
                }
                if (endParent && RangeUtils.isEndOf(range, endParent)) {
                    dom.insertAfter(end, endParent);
                }
            },
            _root: function (node) {
                while (node && dom.name(node) != 'body' && node.parentNode && dom.name(node.parentNode) != 'body') {
                    node = node.parentNode;
                }
                return node;
            },
            _join: function (start, end) {
                start = this._root(start);
                end = this._root(end);
                if (start != end && dom.is(end, 'p')) {
                    this._merge(start, end);
                }
            },
            _merge: function (dest, src) {
                dom.removeTrailingBreak(dest);
                while (dest && src.firstChild) {
                    if (dest.nodeType == 1) {
                        dest = dom.list(dest) ? dest.children[dest.children.length - 1] : dest;
                        if (dest) {
                            dest.appendChild(src.firstChild);
                        }
                    } else if (dest.nodeType === nodeTypes.TEXT_NODE) {
                        this._mergeWithTextNode(dest, src.firstChild);
                    } else {
                        dest.parentNode.appendChild(src.firstChild);
                    }
                }
                dom.remove(src);
            },
            _mergeWithTextNode: function (textNode, appendedNode) {
                if (textNode && textNode.nodeType === nodeTypes.TEXT_NODE) {
                    if (textNode.nextSibling && this._isCaret(textNode.nextSibling)) {
                        dom.insertAfter(appendedNode, textNode.nextSibling);
                    } else {
                        dom.insertAfter(appendedNode, textNode);
                    }
                }
            },
            _isCaret: function (element) {
                return $(element).is('a');
            },
            keydown: function (e) {
                var method, startRestorePoint;
                var editor = this.editor;
                var range = editor.getRange();
                var keyCode = e.keyCode;
                var keys = kendo.keys;
                var backspace = keyCode === keys.BACKSPACE;
                var del = keyCode == keys.DELETE;
                if (editor.immutables && editor.immutables.keydown(e, range)) {
                    return;
                }
                if ((backspace || del) && !range.collapsed) {
                    method = '_handleSelection';
                } else if (backspace) {
                    method = '_handleBackspace';
                } else if (del) {
                    method = '_handleDelete';
                }
                if (!method) {
                    return;
                }
                startRestorePoint = new RestorePoint(range, editor.body);
                if (this[method](range)) {
                    e.preventDefault();
                    editorNS._finishUpdate(editor, startRestorePoint);
                }
            },
            deleteSelection: function (range) {
                this._handleSelection(range);
            },
            keyup: $.noop
        });
        var SystemHandler = Class.extend({
            init: function (editor) {
                this.editor = editor;
                this.systemCommandIsInProgress = false;
            },
            createUndoCommand: function () {
                this.startRestorePoint = this.endRestorePoint = editorNS._finishUpdate(this.editor, this.startRestorePoint);
            },
            changed: function () {
                if (this.startRestorePoint) {
                    return this.startRestorePoint.html != this.editor.body.innerHTML;
                }
                return false;
            },
            keydown: function (e) {
                var that = this, editor = that.editor, keyboard = editor.keyboard;
                if (keyboard.isModifierKey(e)) {
                    if (keyboard.isTypingInProgress()) {
                        keyboard.endTyping(true);
                    }
                    that.startRestorePoint = new RestorePoint(editor.getRange(), editor.body);
                    return true;
                }
                if (keyboard.isSystem(e)) {
                    that.systemCommandIsInProgress = true;
                    if (that.changed()) {
                        that.systemCommandIsInProgress = false;
                        that.createUndoCommand();
                    }
                    return true;
                }
                return false;
            },
            keyup: function () {
                var that = this;
                if (that.systemCommandIsInProgress && that.changed()) {
                    that.systemCommandIsInProgress = false;
                    that.createUndoCommand();
                    return true;
                }
                return false;
            }
        });
        var SelectAllHandler = Class.extend({
            init: function (editor) {
                this.editor = editor;
            },
            keydown: function (e) {
                if (!browser.webkit || e.isDefaultPrevented() || !(e.ctrlKey && e.keyCode == 65 && !e.altKey && !e.shiftKey)) {
                    return;
                }
                if (this.editor.options.immutables) {
                    this._toSelectableImmutables();
                }
                this._selectEditorBody();
            },
            _selectEditorBody: function () {
                var editor = this.editor;
                var range = editor.getRange();
                range.selectNodeContents(editor.body);
                editor.selectRange(range);
            },
            _toSelectableImmutables: function () {
                var editor = this.editor, body = editor.body, immutable = editorNS.Immutables.immutable, emptyTextNode = dom.emptyTextNode, first = body.firstChild, last = body.lastChild;
                while (emptyTextNode(first)) {
                    first = first.nextSibling;
                }
                while (emptyTextNode(last)) {
                    last = last.previousSibling;
                }
                if (first && immutable(first)) {
                    $(br).prependTo(body);
                }
                if (last && immutable(last)) {
                    $(br).appendTo(body);
                }
            },
            keyup: $.noop
        });
        var Keyboard = Class.extend({
            init: function (handlers) {
                this.handlers = handlers;
                this.typingInProgress = false;
            },
            isCharacter: function (keyCode) {
                return keyCode >= 48 && keyCode <= 90 || keyCode >= 96 && keyCode <= 111 || keyCode >= 186 && keyCode <= 192 || keyCode >= 219 && keyCode <= 222 || keyCode == 229;
            },
            toolFromShortcut: function (tools, e) {
                var key = String.fromCharCode(e.keyCode), toolName, toolOptions, modifier = this._getShortcutModifier(e, navigator.platform);
                for (toolName in tools) {
                    toolOptions = $.extend({
                        ctrl: false,
                        alt: false,
                        shift: false
                    }, tools[toolName].options);
                    if ((toolOptions.key == key || toolOptions.key == e.keyCode) && toolOptions.ctrl == modifier && toolOptions.alt == e.altKey && toolOptions.shift == e.shiftKey) {
                        return toolName;
                    }
                }
            },
            _getShortcutModifier: function (e, platform) {
                var mac = platform.toUpperCase().indexOf('MAC') >= 0;
                return mac ? e.metaKey : e.ctrlKey;
            },
            toolsFromShortcut: function (tools, e) {
                var key = String.fromCharCode(e.keyCode), toolName, o, matchesKey, found = [];
                var matchKey = function (toolKey) {
                    return toolKey == key || toolKey == e.keyCode || toolKey == e.charCode;
                };
                for (toolName in tools) {
                    o = $.extend({
                        ctrl: false,
                        alt: false,
                        shift: false
                    }, tools[toolName].options);
                    matchesKey = $.isArray(o.key) ? $.grep(o.key, matchKey).length > 0 : matchKey(o.key);
                    if (matchesKey && o.ctrl == e.ctrlKey && o.alt == e.altKey && o.shift == e.shiftKey) {
                        found.push(tools[toolName]);
                    }
                }
                return found;
            },
            isTypingKey: function (e) {
                var keyCode = e.keyCode;
                return this.isCharacter(keyCode) && !e.ctrlKey && !e.altKey || keyCode == 32 || keyCode == 13 || keyCode == 8 || keyCode == 46 && !e.shiftKey && !e.ctrlKey && !e.altKey;
            },
            isModifierKey: function (e) {
                var keyCode = e.keyCode;
                return keyCode == 17 && !e.shiftKey && !e.altKey || keyCode == 16 && !e.ctrlKey && !e.altKey || keyCode == 18 && !e.ctrlKey && !e.shiftKey;
            },
            isSystem: function (e) {
                return e.keyCode == 46 && e.ctrlKey && !e.altKey && !e.shiftKey;
            },
            startTyping: function (callback) {
                this.onEndTyping = callback;
                this.typingInProgress = true;
            },
            stopTyping: function () {
                if (this.typingInProgress && this.onEndTyping) {
                    this.onEndTyping();
                }
                this.typingInProgress = false;
            },
            endTyping: function (force) {
                var that = this;
                that.clearTimeout();
                if (force) {
                    that.stopTyping();
                } else {
                    that.timeout = window.setTimeout($.proxy(that.stopTyping, that), 1000);
                }
            },
            isTypingInProgress: function () {
                return this.typingInProgress;
            },
            clearTimeout: function () {
                window.clearTimeout(this.timeout);
            },
            notify: function (e, what) {
                var i, handlers = this.handlers;
                for (i = 0; i < handlers.length; i++) {
                    if (handlers[i][what](e)) {
                        break;
                    }
                }
            },
            keydown: function (e) {
                this.notify(e, 'keydown');
            },
            keyup: function (e) {
                this.notify(e, 'keyup');
            }
        });
        extend(editorNS, {
            TypingHandler: TypingHandler,
            SystemHandler: SystemHandler,
            BackspaceHandler: BackspaceHandler,
            SelectAllHandler: SelectAllHandler,
            Keyboard: Keyboard
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/exportpdf', ['editor/command'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, editorNS = kendo.ui.editor, Command = editorNS.Command, EditorUtils = editorNS.EditorUtils, registerTool = EditorUtils.registerTool, Tool = editorNS.Tool, ToolTemplate = editorNS.ToolTemplate, extend = $.extend;
        var ExportPdfCommand = Command.extend({
            init: function (options) {
                this.async = true;
                Command.fn.init.call(this, options);
            },
            exec: function () {
                var that = this;
                var range = that.lockRange(true);
                var editor = that.editor;
                editor._destroyResizings();
                editor.saveAsPDF().then(function () {
                    that.releaseRange(range);
                    editor._initializeColumnResizing();
                    editor._initializeRowResizing();
                    editor._initializeTableResizing();
                });
            }
        });
        extend(editorNS, { ExportPdfCommand: ExportPdfCommand });
        registerTool('pdf', new Tool({
            command: ExportPdfCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Export PDF'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/plugins/print', ['editor/command'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, editorNS = kendo.ui.editor, Command = editorNS.Command, EditorUtils = editorNS.EditorUtils, registerTool = EditorUtils.registerTool, Tool = editorNS.Tool, ToolTemplate = editorNS.ToolTemplate, extend = $.extend;
        var PrintCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this.managesUndoRedo = true;
            },
            exec: function () {
                var editor = this.editor;
                if (kendo.support.browser.msie) {
                    editor.document.execCommand('print', false, null);
                } else if (editor.window.print) {
                    editor.window.print();
                }
            }
        });
        extend(editorNS, { PrintCommand: PrintCommand });
        registerTool('print', new Tool({
            command: PrintCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Print'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/resizing-utils', ['editor/main'], f);
}(function () {
    (function (kendo, undefined) {
        var global = window;
        var math = global.Math;
        var min = math.min;
        var max = math.max;
        var parseFloat = global.parseFloat;
        var $ = kendo.jQuery;
        var extend = $.extend;
        var Editor = kendo.ui.editor;
        var PERCENTAGE = '%';
        var PIXEL = 'px';
        var REGEX_NUMBER_IN_PERCENTAGES = /(\d+)(\.?)(\d*)%/;
        var REGEX_NUMBER_IN_PIXELS = /(\d+)(\.?)(\d*)px/;
        var STRING = 'string';
        function constrain(options) {
            var value = options.value;
            var lowerBound = options.min;
            var upperBound = options.max;
            return max(min(parseFloat(value), parseFloat(upperBound)), parseFloat(lowerBound));
        }
        function getScrollBarWidth(element) {
            if (element && !$(element).is('body') && element.scrollHeight > element.clientHeight) {
                return kendo.support.scrollbar();
            }
            return 0;
        }
        function calculatePercentageRatio(value, total) {
            if (inPercentages(value)) {
                return parseFloat(value);
            } else {
                return parseFloat(value) / total * 100;
            }
        }
        function inPercentages(value) {
            return typeof value === STRING && REGEX_NUMBER_IN_PERCENTAGES.test(value);
        }
        function inPixels(value) {
            return typeof value === STRING && REGEX_NUMBER_IN_PIXELS.test(value);
        }
        function toPercentages(value) {
            return parseFloat(value) + PERCENTAGE;
        }
        function toPixels(value) {
            return parseFloat(value) + PIXEL;
        }
        var ResizingUtils = {
            constrain: constrain,
            getScrollBarWidth: getScrollBarWidth,
            calculatePercentageRatio: calculatePercentageRatio,
            inPercentages: inPercentages,
            inPixels: inPixels,
            toPercentages: toPercentages,
            toPixels: toPixels
        };
        extend(Editor, { ResizingUtils: ResizingUtils });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/table-element-resizing', [
        'editor/main',
        'kendo.resizable',
        'editor/resizing/resizing-utils'
    ], f);
}(function () {
    (function (kendo, undefined) {
        var $ = kendo.jQuery;
        var extend = $.extend;
        var noop = $.noop;
        var proxy = $.proxy;
        var Editor = kendo.ui.editor;
        var Class = kendo.Class;
        var KEY_DOWN = 'keydown';
        var MOUSE_DOWN = 'mousedown';
        var MOUSE_ENTER = 'mouseenter';
        var MOUSE_LEAVE = 'mouseleave';
        var MOUSE_MOVE = 'mousemove';
        var MOUSE_UP = 'mouseup';
        var COMMA = ',';
        var DOT = '.';
        var LAST_CHILD = ':last-child';
        var TABLE = 'table';
        var TableElementResizing = Class.extend({
            init: function (element, options) {
                var that = this;
                that.options = extend({}, that.options, options);
                that.options.tags = $.isArray(that.options.tags) ? that.options.tags : [that.options.tags];
                if ($(element).is(TABLE)) {
                    that.element = element;
                    that._attachEventHandlers();
                }
            },
            destroy: function () {
                var that = this;
                var eventNamespace = that.options.eventNamespace;
                if (that.element) {
                    $(that.element).off(eventNamespace);
                    that.element = null;
                }
                $(that.options.rootElement).off(KEY_DOWN + eventNamespace);
                that._destroyResizeHandle();
            },
            options: {
                tags: [],
                min: 0,
                rootElement: null,
                eventNamespace: '',
                rtl: false,
                handle: {
                    dataAttribute: '',
                    height: 0,
                    width: 0,
                    classNames: {},
                    template: ''
                }
            },
            _attachEventHandlers: function () {
                var that = this;
                var options = that.options;
                $(that.element).on(MOUSE_MOVE + options.eventNamespace, options.tags.join(COMMA), proxy(that.detectElementBorderHovering, that));
            },
            resizingInProgress: function () {
                var that = this;
                var resizable = that._resizable;
                if (resizable) {
                    return !!resizable.resizing;
                }
                return false;
            },
            resize: noop,
            detectElementBorderHovering: function (e) {
                var that = this;
                var options = that.options;
                var handleOptions = options.handle;
                var tableElement = $(e.currentTarget);
                var resizeHandle = that.resizeHandle;
                var dataAttribute = handleOptions.dataAttribute;
                if (!that.resizingInProgress()) {
                    if (!tableElement.is(LAST_CHILD) && that.elementBorderHovered(tableElement, e)) {
                        if (resizeHandle) {
                            if (resizeHandle.data(dataAttribute) && resizeHandle.data(dataAttribute) !== tableElement[0]) {
                                that.showResizeHandle(tableElement, e);
                            }
                        } else {
                            that.showResizeHandle(tableElement, e);
                        }
                    } else {
                        if (resizeHandle) {
                            that._destroyResizeHandle();
                        }
                    }
                }
            },
            elementBorderHovered: noop,
            showResizeHandle: function (tableElement, e) {
                var that = this;
                if (e.buttons !== 0) {
                    return;
                }
                that._initResizeHandle();
                that.setResizeHandlePosition(tableElement);
                that.setResizeHandleDimensions();
                that.setResizeHandleDataAttributes(tableElement[0]);
                that._attachResizeHandleEventHandlers();
                that._initResizable(tableElement);
                that._hideResizeMarker();
                that.resizeHandle.show();
            },
            _initResizeHandle: function () {
                var that = this;
                var options = that.options;
                that._destroyResizeHandle();
                that.resizeHandle = $(options.handle.template).appendTo(options.rootElement);
            },
            setResizeHandlePosition: noop,
            setResizeHandleDimensions: noop,
            setResizeHandleDataAttributes: function (tableElement) {
                var that = this;
                that.resizeHandle.data(that.options.handle.dataAttribute, tableElement);
            },
            _attachResizeHandleEventHandlers: function () {
                var that = this;
                var options = that.options;
                var eventNamespace = options.eventNamespace;
                var markerClass = options.handle.classNames.marker;
                var resizeHandle = that.resizeHandle;
                that.resizeHandle.on(MOUSE_DOWN + eventNamespace, function () {
                    resizeHandle.find(DOT + markerClass).show();
                }).on(MOUSE_UP + eventNamespace, function () {
                    resizeHandle.find(DOT + markerClass).hide();
                });
            },
            _hideResizeMarker: function () {
                var that = this;
                that.resizeHandle.find(DOT + that.options.handle.classNames.marker).hide();
            },
            _destroyResizeHandle: function () {
                var that = this;
                if (that.resizeHandle) {
                    that._destroyResizable();
                    that.resizeHandle.off(that.options.eventNamespace).remove();
                    that.resizeHandle = null;
                }
            },
            _initResizable: function (tableElement) {
                var that = this;
                if (!that.resizeHandle) {
                    return;
                }
                that._destroyResizable();
                that._resizable = new kendo.ui.Resizable(tableElement, {
                    draggableElement: that.resizeHandle[0],
                    start: proxy(that.onResizeStart, that),
                    resize: proxy(that.onResize, that),
                    resizeend: proxy(that.onResizeEnd, that)
                });
            },
            _destroyResizable: function () {
                var that = this;
                if (that._resizable) {
                    that._resizable.destroy();
                    that._resizable = null;
                }
            },
            onResizeStart: function () {
                this._disableKeyboard();
            },
            onResize: function (e) {
                this.setResizeHandleDragPosition(e);
            },
            setResizeHandleDragPosition: noop,
            onResizeEnd: function (e) {
                var that = this;
                that.resize(e);
                that._destroyResizeHandle();
                that._enableKeyboard();
            },
            _enableKeyboard: function () {
                var options = this.options;
                $(options.rootElement).off(KEY_DOWN + options.eventNamespace);
            },
            _disableKeyboard: function () {
                var options = this.options;
                $(options.rootElement).on(KEY_DOWN + options.eventNamespace, function (e) {
                    e.preventDefault();
                });
            },
            _forceResizing: function (e) {
                var resizable = this._resizable;
                if (resizable && resizable.userEvents) {
                    resizable.userEvents._end(e);
                }
            }
        });
        var ResizingFactory = Class.extend({
            create: function (editor, options) {
                var that = this;
                var resizingName = options.name;
                var NS = options.eventNamespace;
                $(editor.body).on(MOUSE_ENTER + NS, TABLE, function (e) {
                    var table = e.currentTarget;
                    var resizing = editor[resizingName];
                    e.stopPropagation();
                    if (resizing) {
                        if (resizing.element !== table && !resizing.resizingInProgress()) {
                            that._destroyResizing(editor, options);
                            that._initResizing(editor, table, options);
                        }
                    } else {
                        that._initResizing(editor, table, options);
                    }
                }).on(MOUSE_LEAVE + NS, TABLE, function (e) {
                    var parentTable;
                    var resizing = editor[resizingName];
                    e.stopPropagation();
                    if (resizing && !resizing.resizingInProgress() && !resizing.resizeHandle) {
                        parentTable = $(resizing.element).parents(TABLE)[0];
                        if (parentTable) {
                            that._destroyResizing(editor, options);
                            that._initResizing(editor, parentTable, options);
                        }
                    }
                }).on(MOUSE_LEAVE + NS, function () {
                    var resizing = editor[resizingName];
                    if (resizing && !resizing.resizingInProgress()) {
                        that._destroyResizing(editor, options);
                    }
                }).on(MOUSE_UP + NS, function (e) {
                    var resizing = editor[resizingName];
                    var parentTable;
                    if (resizing && resizing.resizingInProgress()) {
                        parentTable = $(e.target).parents(TABLE)[0];
                        if (parentTable) {
                            resizing._forceResizing(e);
                            that._destroyResizing(editor, options);
                            that._initResizing(editor, parentTable, options);
                        }
                    }
                });
            },
            dispose: function (editor, options) {
                $(editor.body).off(options.eventNamespace);
            },
            _initResizing: function (editor, tableElement, options) {
                var resizingName = options.name;
                var resizingType = options.type;
                editor[resizingName] = new resizingType(tableElement, {
                    rtl: kendo.support.isRtl(editor.element),
                    rootElement: editor.body
                });
            },
            _destroyResizing: function (editor, options) {
                var resizingName = options.name;
                if (editor[resizingName]) {
                    editor[resizingName].destroy();
                    editor[resizingName] = null;
                }
            }
        });
        ResizingFactory.current = new ResizingFactory();
        TableElementResizing.create = function (editor, options) {
            ResizingFactory.current.create(editor, options);
        };
        TableElementResizing.dispose = function (editor, options) {
            ResizingFactory.current.dispose(editor, options);
        };
        extend(Editor, { TableElementResizing: TableElementResizing });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/column-resizing', [
        'editor/main',
        'editor/resizing/resizing-utils',
        'editor/resizing/table-element-resizing'
    ], f);
}(function () {
    (function (kendo, undefined) {
        var global = window;
        var math = global.Math;
        var abs = math.abs;
        var $ = kendo.jQuery;
        var extend = $.extend;
        var Editor = kendo.ui.editor;
        var TableElementResizing = Editor.TableElementResizing;
        var ResizingUtils = Editor.ResizingUtils;
        var constrain = ResizingUtils.constrain;
        var calculatePercentageRatio = ResizingUtils.calculatePercentageRatio;
        var getScrollBarWidth = ResizingUtils.getScrollBarWidth;
        var inPercentages = ResizingUtils.inPercentages;
        var toPercentages = ResizingUtils.toPercentages;
        var toPixels = ResizingUtils.toPixels;
        var outerWidth = kendo._outerWidth;
        var NS = '.kendoEditorColumnResizing';
        var RESIZE_HANDLE_CLASS = 'k-column-resize-handle';
        var RESIZE_MARKER_CLASS = 'k-column-resize-marker';
        var BODY = 'body';
        var TBODY = 'tbody';
        var TD = 'td';
        var TH = 'th';
        var TR = 'tr';
        var COMMA = ',';
        var WIDTH = 'width';
        var ColumnResizing = TableElementResizing.extend({
            options: {
                tags: [
                    TD,
                    TH
                ],
                min: 20,
                rootElement: null,
                eventNamespace: NS,
                rtl: false,
                handle: {
                    dataAttribute: 'column',
                    width: 10,
                    height: 0,
                    classNames: {
                        handle: RESIZE_HANDLE_CLASS,
                        marker: RESIZE_MARKER_CLASS
                    },
                    template: '<div class="k-column-resize-handle-wrapper" unselectable="on" contenteditable="false">' + '<div class="' + RESIZE_HANDLE_CLASS + '">' + '<div class="' + RESIZE_MARKER_CLASS + '"></div>' + '</div>' + '</div>'
                }
            },
            elementBorderHovered: function (column, e) {
                var that = this;
                var options = that.options;
                var handleWidth = options.handle.width;
                var borderOffset = column.offset().left + (options.rtl ? 0 : outerWidth(column));
                var mousePosition = e.clientX + $(column[0].ownerDocument).scrollLeft();
                if (mousePosition > borderOffset - handleWidth && mousePosition < borderOffset + handleWidth) {
                    return true;
                } else {
                    return false;
                }
            },
            setResizeHandlePosition: function (column) {
                var that = this;
                var tableBody = $(that.element).children(TBODY);
                var options = that.options;
                var rtl = options.rtl;
                var handleWidth = options.handle.width;
                var rootElement = $(options.rootElement);
                var scrollTopOffset = rootElement.is(BODY) ? 0 : rootElement.scrollTop();
                var scrollLeftOffset = rootElement.is(BODY) ? 0 : rootElement.scrollLeft();
                var columnWidthOffset = rtl ? 0 : outerWidth(column);
                var scrollBarWidth = rtl ? getScrollBarWidth(rootElement[0]) : 0;
                var columnOffsetLeft = column.offset().left - (rootElement.offset().left + parseFloat(rootElement.css('borderLeftWidth'))) - parseFloat(column.css('marginLeft'));
                var tBodyOffsetTop = tableBody.offset().top - (rootElement.offset().top + parseFloat(rootElement.css('borderTopWidth'))) - parseFloat(tableBody.css('marginTop'));
                that.resizeHandle.css({
                    top: tBodyOffsetTop + scrollTopOffset,
                    left: columnOffsetLeft + columnWidthOffset + (scrollLeftOffset - scrollBarWidth) - handleWidth / 2,
                    position: 'absolute'
                });
            },
            setResizeHandleDimensions: function () {
                var that = this;
                var tableBody = $(that.element).children(TBODY);
                that.resizeHandle.css({
                    width: that.options.handle.width,
                    height: tableBody.height()
                });
            },
            setResizeHandleDragPosition: function (e) {
                var that = this;
                var column = $($(e.currentTarget).data(that.options.handle.dataAttribute));
                var options = that.options;
                var rootElement = $(options.rootElement);
                var handleWidth = options.handle ? options.handle.width : 0;
                var min = options.min;
                var rtl = options.rtl;
                var columnWidth = outerWidth(column);
                var columnLeftOffset = column.offset().left - (rootElement.offset().left + parseFloat(rootElement.css('borderLeftWidth'))) - parseFloat(column.css('marginLeft'));
                var adjacentColumnWidth = outerWidth(column.next());
                var resizeHandle = $(that.resizeHandle);
                var scrollLeftOffset = rootElement.is(BODY) ? 0 : rootElement.scrollLeft();
                var scrollBarWidth = rtl ? getScrollBarWidth(rootElement[0]) : 0;
                var resizeHandleOffsetLeft = resizeHandle.offset().left - (rootElement.offset().left + parseFloat(rootElement.css('borderLeftWidth'))) - parseFloat(resizeHandle.css('marginLeft'));
                var handleOffset = constrain({
                    value: resizeHandleOffsetLeft + (scrollLeftOffset - scrollBarWidth) + e.x.delta,
                    min: columnLeftOffset + (scrollLeftOffset - scrollBarWidth) - (rtl ? adjacentColumnWidth : 0) + min,
                    max: columnLeftOffset + columnWidth + (scrollLeftOffset - scrollBarWidth) + (rtl ? 0 : adjacentColumnWidth) - handleWidth - min
                });
                resizeHandle.css({ left: handleOffset });
            },
            resize: function (e) {
                var that = this;
                var column = $($(e.currentTarget).data(that.options.handle.dataAttribute));
                var options = that.options;
                var rtlModifier = options.rtl ? -1 : 1;
                var min = options.min;
                var initialDeltaX = rtlModifier * e.x.initialDelta;
                var newWidth;
                var initialAdjacentColumnWidth;
                var initialColumnWidth;
                that._setTableComputedWidth();
                that._setColumnsComputedWidth();
                initialColumnWidth = outerWidth(column);
                initialAdjacentColumnWidth = outerWidth(column.next());
                newWidth = constrain({
                    value: initialColumnWidth + initialDeltaX,
                    min: min,
                    max: initialColumnWidth + initialAdjacentColumnWidth - min
                });
                that._resizeColumn(column[0], newWidth);
                that._resizeTopAndBottomColumns(column[0], newWidth);
                that._resizeAdjacentColumns(column.index(), initialAdjacentColumnWidth, initialColumnWidth, initialColumnWidth - newWidth);
            },
            _setTableComputedWidth: function () {
                var element = this.element;
                if (element.style[WIDTH] === '') {
                    element.style[WIDTH] = toPixels(outerWidth($(element)));
                }
            },
            _setColumnsComputedWidth: function () {
                var that = this;
                var tableBody = $(that.element).children(TBODY);
                var tableBodyWidth = outerWidth(tableBody);
                var columns = tableBody.children(TR).children(TD);
                var length = columns.length;
                var currentColumnsWidths = columns.map(function () {
                    return outerWidth($(this));
                });
                var i;
                for (i = 0; i < length; i++) {
                    if (inPercentages(columns[i].style[WIDTH])) {
                        columns[i].style[WIDTH] = toPercentages(calculatePercentageRatio(currentColumnsWidths[i], tableBodyWidth));
                    } else {
                        columns[i].style[WIDTH] = toPixels(currentColumnsWidths[i]);
                    }
                }
            },
            _resizeTopAndBottomColumns: function (column, newWidth) {
                var that = this;
                var columnIndex = $(column).index();
                var topAndBottomColumns = $(that.element).children(TBODY).children(TR).children(that.options.tags.join(COMMA)).filter(function () {
                    var cell = this;
                    return $(cell).index() === columnIndex && cell !== column;
                });
                var length = topAndBottomColumns.length;
                var i;
                for (i = 0; i < length; i++) {
                    that._resizeColumn(topAndBottomColumns[i], newWidth);
                }
            },
            _resizeColumn: function (column, newWidth) {
                if (inPercentages(column.style[WIDTH])) {
                    column.style[WIDTH] = toPercentages(calculatePercentageRatio(newWidth, outerWidth($(this.element).children(TBODY))));
                } else {
                    column.style[WIDTH] = toPixels(newWidth);
                }
            },
            _resizeAdjacentColumns: function (columnIndex, initialAdjacentColumnWidth, initialColumnWidth, deltaWidth) {
                var that = this;
                var adjacentColumns = $(that.element).children(TBODY).children(TR).children(that.options.tags.join(COMMA)).filter(function () {
                    return $(this).index() === columnIndex + 1;
                });
                var length = adjacentColumns.length;
                var i;
                for (i = 0; i < length; i++) {
                    that._resizeAdjacentColumn(adjacentColumns[i], initialAdjacentColumnWidth, initialColumnWidth, deltaWidth);
                }
            },
            _resizeAdjacentColumn: function (adjacentColumn, initialAdjacentColumnWidth, initialColumnWidth, deltaWidth) {
                var that = this;
                var min = that.options.min;
                var newWidth;
                newWidth = constrain({
                    value: initialAdjacentColumnWidth + deltaWidth,
                    min: min,
                    max: abs(initialColumnWidth + initialAdjacentColumnWidth - min)
                });
                that._resizeColumn(adjacentColumn, newWidth);
            }
        });
        ColumnResizing.create = function (editor) {
            TableElementResizing.create(editor, {
                name: 'columnResizing',
                type: ColumnResizing,
                eventNamespace: NS
            });
        };
        ColumnResizing.dispose = function (editor) {
            TableElementResizing.dispose(editor, { eventNamespace: NS });
        };
        extend(Editor, { ColumnResizing: ColumnResizing });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/row-resizing', [
        'editor/main',
        'editor/resizing/resizing-utils',
        'editor/resizing/table-element-resizing'
    ], f);
}(function () {
    (function (kendo, undefined) {
        var math = window.Math;
        var abs = math.abs;
        var $ = kendo.jQuery;
        var extend = $.extend;
        var Editor = kendo.ui.editor;
        var TableElementResizing = Editor.TableElementResizing;
        var ResizingUtils = Editor.ResizingUtils;
        var getScrollBarWidth = ResizingUtils.getScrollBarWidth;
        var constrain = ResizingUtils.constrain;
        var calculatePercentageRatio = ResizingUtils.calculatePercentageRatio;
        var inPercentages = ResizingUtils.inPercentages;
        var toPercentages = ResizingUtils.toPercentages;
        var toPixels = ResizingUtils.toPixels;
        var outerHeight = kendo._outerHeight;
        var NS = '.kendoEditorRowResizing';
        var RESIZE_HANDLE_CLASS = 'k-row-resize-handle';
        var RESIZE_HANDLE_MARKER_WRAPPER_CLASS = 'k-row-resize-marker-wrapper';
        var RESIZE_MARKER_CLASS = 'k-row-resize-marker';
        var BODY = 'body';
        var TR = 'tr';
        var TBODY = 'tbody';
        var HEIGHT = 'height';
        var RowResizing = TableElementResizing.extend({
            options: {
                tags: [TR],
                min: 20,
                rootElement: null,
                eventNamespace: NS,
                rtl: false,
                handle: {
                    dataAttribute: 'row',
                    width: 0,
                    height: 10,
                    classNames: {
                        handle: RESIZE_HANDLE_CLASS,
                        marker: RESIZE_MARKER_CLASS
                    },
                    template: '<div class="k-row-resize-handle-wrapper" unselectable="on" contenteditable="false">' + '<div class="' + RESIZE_HANDLE_CLASS + '">' + '<div class="' + RESIZE_HANDLE_MARKER_WRAPPER_CLASS + '">' + '<div class="' + RESIZE_MARKER_CLASS + '"></div>' + '</div>' + '</div>' + '</div>'
                }
            },
            elementBorderHovered: function (tableElement, e) {
                var that = this;
                var handleHeight = that.options.handle[HEIGHT];
                var borderOffset = tableElement.offset().top + outerHeight(tableElement);
                var mousePosition = e.clientY + $(tableElement[0].ownerDocument).scrollTop();
                if (mousePosition > borderOffset - handleHeight && mousePosition < borderOffset + handleHeight) {
                    return true;
                } else {
                    return false;
                }
            },
            setResizeHandlePosition: function (row) {
                var that = this;
                var options = that.options;
                var handleHeight = options.handle[HEIGHT];
                var rootElement = $(options.rootElement);
                var scrollTopOffset = rootElement.is(BODY) ? 0 : rootElement.scrollTop();
                var scrollLeftOffset = rootElement.is(BODY) ? 0 : rootElement.scrollLeft();
                var scrollBarWidth = options.rtl ? getScrollBarWidth(rootElement[0]) : 0;
                var rowOffsetLeft = row.offset().left - (rootElement.offset().left + parseFloat(rootElement.css('borderLeftWidth'))) - parseFloat(row.css('marginLeft'));
                var rowOffsetTop = row.offset().top - (rootElement.offset().top + parseFloat(rootElement.css('borderTopWidth'))) - parseFloat(row.css('marginTop'));
                that.resizeHandle.css({
                    top: rowOffsetTop + outerHeight(row) + scrollTopOffset - handleHeight / 2,
                    left: rowOffsetLeft + (scrollLeftOffset - scrollBarWidth),
                    position: 'absolute'
                });
            },
            setResizeHandleDimensions: function () {
                var that = this;
                that.resizeHandle.css({
                    width: $(that.element).children(TBODY).width(),
                    height: that.options.handle[HEIGHT]
                });
            },
            setResizeHandleDragPosition: function (e) {
                var that = this;
                var options = that.options;
                var min = options.min;
                var tableBody = $(that.element).children(TBODY);
                var resizeHandle = $(that.resizeHandle);
                var row = $(e.currentTarget).data(options.handle.dataAttribute);
                var $row = $(row);
                var rootElement = $(options.rootElement);
                var scrollTopOffset = rootElement.is(BODY) ? 0 : rootElement.scrollTop();
                var tableBodyTopOffset = tableBody.offset().top - (rootElement.offset().top + parseFloat(rootElement.css('borderTopWidth'))) - parseFloat(tableBody.css('marginTop'));
                var rowOffsetTop = $row.offset().top - (rootElement.offset().top + parseFloat(rootElement.css('borderTopWidth'))) - parseFloat($row.css('marginTop'));
                var resizeHandleOffsetTop = resizeHandle.offset().top - (rootElement.offset().top + parseFloat(rootElement.css('borderTopWidth'))) - parseFloat(resizeHandle.css('marginTop'));
                var handleOffset = constrain({
                    value: resizeHandleOffsetTop + scrollTopOffset + e.y.delta,
                    min: rowOffsetTop + scrollTopOffset + min,
                    max: tableBodyTopOffset + outerHeight(tableBody) + scrollTopOffset - options.handle[HEIGHT] - min
                });
                resizeHandle.css({ top: handleOffset });
            },
            resize: function (e) {
                var that = this;
                var options = that.options;
                var row = $(e.currentTarget).data(options.handle.dataAttribute);
                var currentRowHeight = outerHeight($(row));
                var element = $(that.element);
                var initialTableHeight = outerHeight(element);
                var tableBody = element.children(TBODY);
                var tableBodyHeight = tableBody.height();
                var initialStyleHeight = row.style[HEIGHT];
                var newRowHeight = constrain({
                    value: currentRowHeight + e.y.initialDelta,
                    min: options.min,
                    max: abs(tableBodyHeight - options.min)
                });
                that._setRowsHeightInPixels();
                row.style[HEIGHT] = toPixels(newRowHeight);
                that._setTableHeight(initialTableHeight + (newRowHeight - currentRowHeight));
                if (inPercentages(initialStyleHeight)) {
                    that._setRowsHeightInPercentages();
                }
            },
            _setRowsHeightInPixels: function () {
                var that = this;
                var rows = $(that.element).children(TBODY).children(TR);
                var length = rows.length;
                var currentRowsHeights = rows.map(function () {
                    return outerHeight($(this));
                });
                var i;
                for (i = 0; i < length; i++) {
                    rows[i].style[HEIGHT] = toPixels(currentRowsHeights[i]);
                }
            },
            _setRowsHeightInPercentages: function () {
                var that = this;
                var tableBody = $(that.element).children(TBODY);
                var tableBodyHeight = tableBody.height();
                var rows = tableBody.children(TR);
                var length = rows.length;
                var currentRowsHeights = rows.map(function () {
                    return outerHeight($(this));
                });
                var i;
                for (i = 0; i < length; i++) {
                    rows[i].style[HEIGHT] = toPercentages(calculatePercentageRatio(currentRowsHeights[i], tableBodyHeight));
                }
            },
            _setTableHeight: function (newHeight) {
                var element = this.element;
                if (inPercentages(element.style[HEIGHT])) {
                    element.style[HEIGHT] = toPercentages(calculatePercentageRatio(newHeight, $(element).parent().height()));
                } else {
                    element.style[HEIGHT] = toPixels(newHeight);
                }
            }
        });
        RowResizing.create = function (editor) {
            TableElementResizing.create(editor, {
                name: 'rowResizing',
                type: RowResizing,
                eventNamespace: NS
            });
        };
        RowResizing.dispose = function (editor) {
            TableElementResizing.dispose(editor, { eventNamespace: NS });
        };
        extend(Editor, { RowResizing: RowResizing });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/table-resize-handle', [
        'editor/main',
        'kendo.draganddrop',
        'editor/resizing/resizing-utils'
    ], f);
}(function () {
    (function (kendo, undefined) {
        var $ = kendo.jQuery;
        var extend = $.extend;
        var noop = $.noop;
        var proxy = $.proxy;
        var Editor = kendo.ui.editor;
        var Class = kendo.Class;
        var Draggable = kendo.ui.Draggable;
        var Observable = kendo.Observable;
        var getScrollBarWidth = Editor.ResizingUtils.getScrollBarWidth;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var NS = '.kendoEditorTableResizeHandle';
        var RESIZE_HANDLE_CLASS = 'k-table-resize-handle';
        var DRAG_START = 'dragStart';
        var DRAG = 'drag';
        var DRAG_END = 'dragEnd';
        var HALF_INSIDE = 'halfInside';
        var MOUSE_OVER = 'mouseover';
        var MOUSE_OUT = 'mouseout';
        var BODY = 'body';
        var TABLE = 'table';
        var EAST = 'east';
        var NORTH = 'north';
        var NORTHEAST = 'northeast';
        var NORTHWEST = 'northwest';
        var SOUTH = 'south';
        var SOUTHEAST = 'southeast';
        var SOUTHWEST = 'southwest';
        var WEST = 'west';
        var DOT = '.';
        var TableResizeHandle = Observable.extend({
            init: function (options) {
                var that = this;
                Observable.fn.init.call(that);
                that.options = extend({}, that.options, options);
                that.element = $(that.options.template).appendTo(that.options.appendTo)[0];
                that._attachEventHandlers();
                that._addStyles();
                that._initDraggable();
                that._initPositioningStrategy();
                that._initDraggingStrategy();
                $(that.element).data(TABLE, that.options.resizableElement);
            },
            destroy: function () {
                var that = this;
                $(that.element).off(NS).remove();
                that.element = null;
                that._destroyDraggable();
                that.unbind();
            },
            options: {
                appendTo: null,
                direction: SOUTHEAST,
                resizableElement: null,
                rtl: false,
                template: '<div class=\'k-table-resize-handle-wrapper\' unselectable=\'on\' contenteditable=\'false\'>' + '<div class=\'' + RESIZE_HANDLE_CLASS + '\'></div>' + '</div>'
            },
            events: [
                DRAG_START,
                DRAG,
                DRAG_END,
                MOUSE_OVER,
                MOUSE_OUT
            ],
            show: function () {
                this._setPosition();
            },
            _setPosition: function () {
                var that = this;
                var position = that._positioningStrategy.getPosition();
                $(that.element).css({
                    top: position.top,
                    left: position.left,
                    position: 'absolute'
                });
            },
            _attachEventHandlers: function () {
                var that = this;
                $(that.element).on(MOUSE_OVER + NS, proxy(that._onMouseOver, that)).on(MOUSE_OUT + NS, proxy(that._onMouseOut, that));
            },
            _onMouseOver: function () {
                this.trigger(MOUSE_OVER);
            },
            _onMouseOut: function () {
                this.trigger(MOUSE_OUT);
            },
            _addStyles: function () {
                var that = this;
                $(that.element).children(DOT + RESIZE_HANDLE_CLASS).addClass('k-resize-' + that.options.direction);
            },
            _initPositioningStrategy: function () {
                var that = this;
                var options = that.options;
                that._positioningStrategy = HandlePositioningStrategy.create({
                    name: options.direction,
                    handle: that.element,
                    resizableElement: options.resizableElement,
                    rootElement: options.rootElement,
                    rtl: options.rtl
                });
            },
            _initDraggable: function () {
                var that = this;
                var element = that.element;
                if (that._draggable || !element) {
                    return;
                }
                that._draggable = new Draggable(element, {
                    dragstart: proxy(that._onDragStart, that),
                    drag: proxy(that._onDrag, that),
                    dragend: proxy(that._onDragEnd, that)
                });
            },
            _onDragStart: function () {
                this.trigger(DRAG_START);
            },
            _onDrag: function (e) {
                var that = this;
                that.trigger(DRAG, that._draggingStrategy.adjustDragDelta({
                    deltaX: e.x.delta,
                    deltaY: e.y.delta,
                    initialDeltaX: e.x.initialDelta,
                    initialDeltaY: e.y.initialDelta
                }));
            },
            _onDragEnd: function () {
                this.trigger(DRAG_END);
            },
            _destroyDraggable: function () {
                var that = this;
                if (that._draggable) {
                    that._draggable.destroy();
                    that._draggable = null;
                }
            },
            _initDraggingStrategy: function () {
                var that = this;
                that._draggingStrategy = HandleDraggingStrategy.create({ name: that.options.direction });
            }
        });
        var StrategyFactory = Class.extend({
            init: function () {
                this._items = [];
            },
            register: function (name, type) {
                this._items.push({
                    name: name,
                    type: type
                });
            },
            create: function (options) {
                var items = this._items;
                var itemsLength = items.length;
                var name = options.name ? options.name.toLowerCase() : '';
                var match;
                var item;
                var i;
                for (i = 0; i < itemsLength; i++) {
                    item = items[i];
                    if (item.name.toLowerCase() === name) {
                        match = item;
                        break;
                    }
                }
                if (match) {
                    return new match.type(options);
                }
            }
        });
        var PositioningStrategyFactory = StrategyFactory.extend({});
        PositioningStrategyFactory.current = new PositioningStrategyFactory();
        var HandlePositioningStrategy = Class.extend({
            init: function (options) {
                var that = this;
                that.options = extend({}, that.options, options);
            },
            options: {
                handle: null,
                offset: HALF_INSIDE,
                resizableElement: null,
                rootElement: null,
                rtl: false
            },
            getPosition: function () {
                var that = this;
                var position = that.calculatePosition();
                var handleOffsetPosition = that.applyHandleOffset(position);
                var scrollOffsetPosition = that.applyScrollOffset(handleOffsetPosition);
                return scrollOffsetPosition;
            },
            calculatePosition: noop,
            applyHandleOffset: function (position) {
                var options = this.options;
                var handle = $(options.handle);
                if (options.offset === HALF_INSIDE) {
                    return {
                        top: position.top - outerHeight(handle) / 2,
                        left: position.left - outerWidth(handle) / 2
                    };
                }
                return position;
            },
            applyScrollOffset: function (position) {
                var options = this.options;
                var rootElement = $(options.rootElement);
                var scrollBarWidth = options.rtl ? getScrollBarWidth(rootElement[0]) : 0;
                if (!rootElement.is(BODY)) {
                    return {
                        top: position.top + (rootElement.scrollTop() || 0),
                        left: position.left + (rootElement.scrollLeft() || 0) - scrollBarWidth
                    };
                }
                return position;
            }
        });
        HandlePositioningStrategy.create = function (options) {
            return PositioningStrategyFactory.current.create(options);
        };
        var EastPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top + outerHeight(resizableElement) / 2,
                    left: offset.left + outerWidth(resizableElement)
                };
            }
        });
        PositioningStrategyFactory.current.register(EAST, EastPositioningStrategy);
        var NorthPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top,
                    left: offset.left + outerWidth(resizableElement) / 2
                };
            }
        });
        PositioningStrategyFactory.current.register(NORTH, NorthPositioningStrategy);
        var NortheastPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top,
                    left: offset.left + outerWidth(resizableElement)
                };
            }
        });
        PositioningStrategyFactory.current.register(NORTHEAST, NortheastPositioningStrategy);
        var NorthwestPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top,
                    left: offset.left
                };
            }
        });
        PositioningStrategyFactory.current.register(NORTHWEST, NorthwestPositioningStrategy);
        var SouthPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top + outerHeight(resizableElement),
                    left: offset.left + outerWidth(resizableElement) / 2
                };
            }
        });
        PositioningStrategyFactory.current.register(SOUTH, SouthPositioningStrategy);
        var SoutheastPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top + outerHeight(resizableElement),
                    left: offset.left + outerWidth(resizableElement)
                };
            }
        });
        PositioningStrategyFactory.current.register(SOUTHEAST, SoutheastPositioningStrategy);
        var SouthwestPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top + outerHeight(resizableElement),
                    left: offset.left
                };
            }
        });
        PositioningStrategyFactory.current.register(SOUTHWEST, SouthwestPositioningStrategy);
        var WestPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top + outerHeight(resizableElement) / 2,
                    left: offset.left
                };
            }
        });
        PositioningStrategyFactory.current.register(WEST, WestPositioningStrategy);
        var DraggingStrategyFactory = StrategyFactory.extend({});
        DraggingStrategyFactory.current = new DraggingStrategyFactory();
        var HandleDraggingStrategy = Class.extend({
            init: function (options) {
                var that = this;
                that.options = extend({}, that.options, options);
            },
            options: {
                deltaX: {
                    adjustment: null,
                    modifier: null
                },
                deltaY: {
                    adjustment: null,
                    modifier: null
                }
            },
            adjustDragDelta: function (deltas) {
                var options = this.options;
                var xAxisAdjustment = options.deltaX.adjustment * options.deltaX.modifier;
                var yAxisAdjustment = options.deltaY.adjustment * options.deltaY.modifier;
                return {
                    deltaX: deltas.deltaX * xAxisAdjustment,
                    deltaY: deltas.deltaY * yAxisAdjustment,
                    initialDeltaX: deltas.initialDeltaX * xAxisAdjustment,
                    initialDeltaY: deltas.initialDeltaY * yAxisAdjustment
                };
            }
        });
        HandleDraggingStrategy.create = function (options) {
            return DraggingStrategyFactory.current.create(options);
        };
        var HorizontalDraggingStrategy = HandleDraggingStrategy.extend({
            options: {
                deltaX: {
                    adjustment: 1,
                    modifier: 1
                },
                deltaY: {
                    adjustment: 0,
                    modifier: 0
                }
            }
        });
        var EastDraggingStrategy = HorizontalDraggingStrategy.extend({ options: { deltaX: { modifier: 1 } } });
        DraggingStrategyFactory.current.register(EAST, EastDraggingStrategy);
        var WestDraggingStrategy = HorizontalDraggingStrategy.extend({ options: { deltaX: { modifier: -1 } } });
        DraggingStrategyFactory.current.register(WEST, WestDraggingStrategy);
        var VerticalDraggingStrategy = HandleDraggingStrategy.extend({
            options: {
                deltaX: {
                    adjustment: 0,
                    modifier: 0
                },
                deltaY: {
                    adjustment: 1,
                    modifier: 1
                }
            }
        });
        var NorthDraggingStrategy = VerticalDraggingStrategy.extend({ options: { deltaY: { modifier: -1 } } });
        DraggingStrategyFactory.current.register(NORTH, NorthDraggingStrategy);
        var SouthDraggingStrategy = VerticalDraggingStrategy.extend({ options: { deltaY: { modifier: 1 } } });
        DraggingStrategyFactory.current.register(SOUTH, SouthDraggingStrategy);
        var HorizontalAndVerticalDraggingStrategy = HandleDraggingStrategy.extend({
            options: {
                deltaX: {
                    adjustment: 1,
                    modifier: 1
                },
                deltaY: {
                    adjustment: 1,
                    modifier: 1
                }
            }
        });
        var NorthEastDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({
            options: {
                deltaX: { modifier: 1 },
                deltaY: { modifier: -1 }
            }
        });
        DraggingStrategyFactory.current.register(NORTHEAST, NorthEastDraggingStrategy);
        var NorthWestDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({
            options: {
                deltaX: { modifier: -1 },
                deltaY: { modifier: -1 }
            }
        });
        DraggingStrategyFactory.current.register(NORTHWEST, NorthWestDraggingStrategy);
        var SouthEastDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({
            options: {
                deltaX: { modifier: 1 },
                deltaY: { modifier: 1 }
            }
        });
        DraggingStrategyFactory.current.register(SOUTHEAST, SouthEastDraggingStrategy);
        var SouthWestDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({
            options: {
                deltaX: { modifier: -1 },
                deltaY: { modifier: 1 }
            }
        });
        DraggingStrategyFactory.current.register(SOUTHWEST, SouthWestDraggingStrategy);
        extend(Editor, { TableResizeHandle: TableResizeHandle });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/table-resizing', [
        'editor/main',
        'editor/resizing/table-resize-handle',
        'editor/resizing/resizing-utils'
    ], f);
}(function () {
    (function (kendo, undefined) {
        var global = window;
        var math = global.Math;
        var min = math.min;
        var max = math.max;
        var $ = kendo.jQuery;
        var contains = $.contains;
        var extend = $.extend;
        var proxy = $.proxy;
        var browser = kendo.support.browser;
        var Editor = kendo.ui.editor;
        var Class = kendo.Class;
        var TableResizeHandle = Editor.TableResizeHandle;
        var ResizingUtils = Editor.ResizingUtils;
        var calculatePercentageRatio = ResizingUtils.calculatePercentageRatio;
        var constrain = ResizingUtils.constrain;
        var inPercentages = ResizingUtils.inPercentages;
        var inPixels = ResizingUtils.inPixels;
        var toPercentages = ResizingUtils.toPercentages;
        var toPixels = ResizingUtils.toPixels;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var NS = '.kendoEditorTableResizing';
        var RESIZE_HANDLE_WRAPPER_CLASS = 'k-table-resize-handle-wrapper';
        var TABLE_CLASS = 'k-table';
        var TABLE_RESIZING_CLASS = 'k-table-resizing';
        var DRAG_START = 'dragStart';
        var DRAG = 'drag';
        var DRAG_END = 'dragEnd';
        var KEY_DOWN = 'keydown';
        var MOUSE_DOWN = 'mousedown';
        var MOUSE_OVER = 'mouseover';
        var MOUSE_OUT = 'mouseout';
        var COLUMN = 'td';
        var ROW = 'tr';
        var TBODY = 'tbody';
        var TABLE = 'table';
        var WIDTH = 'width';
        var HEIGHT = 'height';
        var EAST = 'east';
        var NORTH = 'north';
        var NORTHEAST = 'northeast';
        var NORTHWEST = 'northwest';
        var SOUTH = 'south';
        var SOUTHEAST = 'southeast';
        var SOUTHWEST = 'southwest';
        var WEST = 'west';
        var DOT = '.';
        function isUndefined(value) {
            return typeof value === 'undefined';
        }
        var TableResizing = Class.extend({
            init: function (element, options) {
                var that = this;
                that.options = extend({}, that.options, options);
                that.handles = [];
                if ($(element).is(TABLE)) {
                    that.element = element;
                }
            },
            destroy: function () {
                var that = this;
                $(that.element).off(NS);
                that.element = null;
                $(that.options.rootElement).off(KEY_DOWN + NS);
                that._destroyResizeHandles();
            },
            options: {
                appendHandlesTo: null,
                rtl: false,
                rootElement: null,
                minWidth: 10,
                minHeight: 10,
                handles: [
                    { direction: NORTHWEST },
                    { direction: NORTH },
                    { direction: NORTHEAST },
                    { direction: EAST },
                    { direction: SOUTHEAST },
                    { direction: SOUTH },
                    { direction: SOUTHWEST },
                    { direction: WEST }
                ]
            },
            resize: function (args) {
                var that = this;
                var deltas = extend({}, {
                    deltaX: 0,
                    deltaY: 0,
                    initialDeltaX: 0,
                    initialDeltaY: 0
                }, args);
                that._resizeWidth(deltas.deltaX, deltas.initialDeltaX);
                that._resizeHeight(deltas.deltaY, deltas.initialDeltaY);
                that.showResizeHandles();
            },
            _resizeWidth: function (delta, initialDelta) {
                var that = this;
                var element = $(that.element);
                var styleWidth = element[0].style[WIDTH];
                var currentWidth = outerWidth(element);
                var parentWidth = element.parent().width();
                var maxWidth = that._getMaxDimensionValue(WIDTH);
                var newWidth;
                var ratioValue;
                var ratioTotalValue;
                var constrainedWidth;
                if (delta === 0) {
                    return;
                }
                if (isUndefined(that._initialElementWidth)) {
                    that._initialElementWidth = currentWidth;
                }
                constrainedWidth = constrain({
                    value: that._initialElementWidth + initialDelta,
                    min: that.options.minWidth,
                    max: maxWidth
                });
                if (inPercentages(styleWidth)) {
                    if (currentWidth + delta > parentWidth) {
                        ratioValue = max(constrainedWidth, parentWidth);
                        ratioTotalValue = min(constrainedWidth, parentWidth);
                    } else {
                        ratioValue = min(constrainedWidth, parentWidth);
                        ratioTotalValue = max(constrainedWidth, parentWidth);
                    }
                    newWidth = toPercentages(calculatePercentageRatio(ratioValue, ratioTotalValue));
                } else {
                    newWidth = toPixels(constrainedWidth);
                }
                that._setColumnsWidth();
                element[0].style[WIDTH] = newWidth;
            },
            _resizeHeight: function (delta, initialDelta) {
                var that = this;
                var element = $(that.element);
                var styleHeight = element[0].style[HEIGHT];
                var currentHeight = outerHeight(element);
                var parent = element.parent();
                var parentHeight = parent.height();
                var maxHeight = that._getMaxDimensionValue(HEIGHT);
                var newHeight;
                var ratioValue;
                var ratioTotalValue;
                var constrainedHeight;
                var minHeight = that.options.minHeight;
                var hasRowsInPixels = that._hasRowsInPixels();
                if (delta === 0) {
                    return;
                }
                if (isUndefined(that._initialElementHeight)) {
                    that._initialElementHeight = currentHeight;
                }
                constrainedHeight = constrain({
                    value: that._initialElementHeight + initialDelta,
                    min: minHeight,
                    max: maxHeight
                });
                if (hasRowsInPixels && delta < 0) {
                    that._setRowsHeightInPercentages();
                }
                if (inPercentages(styleHeight)) {
                    if (currentHeight + delta > parentHeight) {
                        ratioValue = max(constrainedHeight, parentHeight);
                        ratioTotalValue = min(constrainedHeight, parentHeight);
                    } else {
                        ratioValue = min(constrainedHeight, parentHeight);
                        ratioTotalValue = max(constrainedHeight, parentHeight);
                    }
                    newHeight = toPercentages(calculatePercentageRatio(ratioValue, ratioTotalValue));
                } else {
                    newHeight = toPixels(constrainedHeight);
                }
                element[0].style[HEIGHT] = newHeight;
                if (hasRowsInPixels && delta < 0) {
                    that._setRowsHeightInPixels();
                }
            },
            _getMaxDimensionValue: function (dimension) {
                var that = this;
                var element = $(that.element);
                var dimensionLowercase = dimension.toLowerCase();
                var rtlModifier = that.options.rtl ? -1 : 1;
                var parent = $(that.element).parent();
                var parentElement = parent[0];
                var parentDimension = parent[dimensionLowercase]();
                var parentScrollOffset = rtlModifier * (dimension === WIDTH ? parent.scrollLeft() : parent.scrollTop());
                if (parentElement === element.closest(COLUMN)[0]) {
                    if (parentElement.style[dimensionLowercase] === '' && !inPercentages(that.element.style[dimensionLowercase])) {
                        return Infinity;
                    } else {
                        return parentDimension + parentScrollOffset;
                    }
                } else {
                    return parentDimension + parentScrollOffset;
                }
            },
            _setColumnsWidth: function () {
                var that = this;
                var element = $(that.element);
                var parentElement = element.parent()[0];
                var parentColumn = element.closest(COLUMN);
                var columns = parentColumn.closest(ROW).children();
                var columnsLength = columns.length;
                var i;
                function isWidthInPercentages(element) {
                    var styleWidth = element.style.width;
                    if (styleWidth !== '') {
                        return inPercentages(styleWidth) ? true : false;
                    } else {
                        return $(element).hasClass(TABLE_CLASS) ? true : false;
                    }
                }
                if (isWidthInPercentages(element[0]) && parentElement === parentColumn[0] && parentElement.style[WIDTH] === '') {
                    for (i = 0; i < columnsLength; i++) {
                        columns[i].style[WIDTH] = toPixels($(columns[i]).width());
                    }
                }
            },
            _hasRowsInPixels: function () {
                var that = this;
                var rows = $(that.element).children(TBODY).children(ROW);
                for (var i = 0; i < rows.length; i++) {
                    if (rows[i].style.height === '' || inPixels(rows[i].style.height)) {
                        return true;
                    }
                }
                return false;
            },
            _setRowsHeightInPercentages: function () {
                var that = this;
                var tableBody = $(that.element).children(TBODY);
                var tableBodyHeight = tableBody.height();
                var rows = tableBody.children(ROW);
                var length = rows.length;
                var currentRowsHeights = rows.map(function () {
                    return outerHeight($(this));
                });
                var i;
                for (i = 0; i < length; i++) {
                    rows[i].style[HEIGHT] = toPercentages(calculatePercentageRatio(currentRowsHeights[i], tableBodyHeight));
                }
            },
            _setRowsHeightInPixels: function () {
                var that = this;
                var rows = $(that.element).children(TBODY).children(ROW);
                var length = rows.length;
                var currentRowsHeights = rows.map(function () {
                    return outerHeight($(this));
                });
                var i;
                for (i = 0; i < length; i++) {
                    rows[i].style[HEIGHT] = toPixels(currentRowsHeights[i]);
                }
            },
            showResizeHandles: function () {
                var that = this;
                that._initResizeHandles();
                that._showResizeHandles();
            },
            _initResizeHandles: function () {
                var that = this;
                var handles = that.handles;
                var options = that.options;
                var handleOptions = that.options.handles;
                var length = handleOptions.length;
                var i;
                if (handles && handles.length > 0) {
                    return;
                }
                for (i = 0; i < length; i++) {
                    that.handles.push(new TableResizeHandle(extend({
                        appendTo: options.appendHandlesTo,
                        resizableElement: that.element,
                        rootElement: options.rootElement,
                        rtl: options.rtl
                    }, handleOptions[i])));
                }
                that._bindToResizeHandlesEvents();
            },
            _destroyResizeHandles: function () {
                var that = this;
                var length = that.handles ? that.handles.length : 0;
                for (var i = 0; i < length; i++) {
                    that.handles[i].destroy();
                }
            },
            _showResizeHandles: function () {
                var that = this;
                var handles = that.handles || [];
                var length = handles.length;
                var i;
                for (i = 0; i < length; i++) {
                    that.handles[i].show();
                }
            },
            _bindToResizeHandlesEvents: function () {
                var that = this;
                var handles = that.handles || [];
                var length = handles.length;
                var i;
                var handle;
                for (i = 0; i < length; i++) {
                    handle = handles[i];
                    handle.bind(DRAG_START, proxy(that._onResizeHandleDragStart, that));
                    handle.bind(DRAG, proxy(that._onResizeHandleDrag, that));
                    handle.bind(DRAG_END, proxy(that._onResizeHandleDragEnd, that));
                    handle.bind(MOUSE_OVER, proxy(that._onResizeHandleMouseOver, that));
                    handle.bind(MOUSE_OUT, proxy(that._onResizeHandleMouseOut, that));
                }
            },
            _onResizeHandleDragStart: function () {
                var that = this;
                var element = $(that.element);
                element.addClass(TABLE_RESIZING_CLASS);
                that._initialElementHeight = outerHeight(element);
                that._initialElementWidth = outerWidth(element);
                that._disableKeyboard();
            },
            _onResizeHandleDrag: function (e) {
                this.resize(e);
            },
            _onResizeHandleDragEnd: function () {
                var that = this;
                $(that.element).removeClass(TABLE_RESIZING_CLASS);
                that._enableKeyboard();
            },
            _enableKeyboard: function () {
                $(this.options.rootElement).off(KEY_DOWN + NS);
            },
            _disableKeyboard: function () {
                $(this.options.rootElement).on(KEY_DOWN + NS, function (e) {
                    e.preventDefault();
                });
            }
        });
        var TableResizingFactory = Class.extend({
            create: function (editor) {
                var factory = this;
                $(editor.body).on(MOUSE_DOWN + NS, TABLE, function (e) {
                    var eventTarget = e.target;
                    var eventCurrentTarget = e.currentTarget;
                    var tableResizing = editor.tableResizing;
                    var element = tableResizing ? tableResizing.element : null;
                    if (tableResizing) {
                        if (element && eventCurrentTarget !== element) {
                            if (contains(eventCurrentTarget, element) && element !== eventTarget && contains(element, eventTarget)) {
                                return;
                            } else {
                                if (element !== eventTarget) {
                                    editor._destroyTableResizing();
                                    factory._initResizing(editor, eventCurrentTarget);
                                }
                            }
                        }
                    } else {
                        factory._initResizing(editor, eventCurrentTarget);
                    }
                    editor._showTableResizeHandles();
                }).on(MOUSE_DOWN + NS, function (e) {
                    var tableResizing = editor.tableResizing;
                    var element = tableResizing ? tableResizing.element : null;
                    var target = e.target;
                    var isResizeHandleOrChild = $(target).hasClass(RESIZE_HANDLE_WRAPPER_CLASS) || $(target).parents(DOT + RESIZE_HANDLE_WRAPPER_CLASS).length > 0;
                    if (tableResizing && element !== target && !contains(element, target) && !isResizeHandleOrChild) {
                        editor._destroyTableResizing();
                    }
                });
            },
            dispose: function (editor) {
                $(editor.body).off(NS);
            },
            _initResizing: function (editor, table) {
                if (!browser.msie && !browser.mozilla) {
                    editor.tableResizing = new TableResizing(table, {
                        appendHandlesTo: editor.body,
                        rtl: kendo.support.isRtl(editor.element),
                        rootElement: editor.body
                    });
                }
            }
        });
        TableResizingFactory.current = new TableResizingFactory();
        TableResizing.create = function (editor) {
            TableResizingFactory.current.create(editor);
        };
        TableResizing.dispose = function (editor) {
            TableResizingFactory.current.dispose(editor);
        };
        extend(Editor, { TableResizing: TableResizing });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/table-wizard/table-wizard-command', ['editor/plugins/tables'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, RangeUtils = Editor.RangeUtils, dom = Editor.Dom, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, Command = Editor.Command;
        var tableFormatFinder = new Editor.BlockFormatFinder([{ tags: ['table'] }]);
        var cellsFormatFinder = new Editor.BlockFormatFinder([{
                tags: [
                    'td',
                    'th'
                ]
            }]);
        var reUnit = /([a-z]+|%)$/i;
        var TableWizardCommand = Command.extend({
            exec: function () {
                var cmd = this;
                var editor = cmd.editor;
                var range = cmd.range = cmd.lockRange();
                var selectedTable = cmd._sourceTable = !cmd.options.insertNewTable ? cmd._selectedTable(range) : undefined;
                var selectedCells = cmd._selectedTableCells = selectedTable ? cmd._selectedCells(range) : undefined;
                var options = {
                    visible: false,
                    messages: editor.options.messages,
                    closeCallback: $.proxy(cmd.onDialogClose, cmd),
                    table: cmd.parseTable(selectedTable, selectedCells),
                    dialogOptions: editor.options.dialogOptions,
                    isRtl: kendo.support.isRtl(editor.wrapper)
                };
                var dialog = new Editor.TableWizardDialog(options);
                dialog.open();
            },
            onDialogClose: function (data) {
                var cmd = this;
                cmd.releaseRange(cmd.range);
                if (data) {
                    if (cmd.options.insertNewTable) {
                        cmd.insertTable(cmd.createNewTable(data));
                    } else {
                        cmd.updateTable(data, cmd._sourceTable, cmd._selectedTableCells);
                    }
                }
            },
            releaseRange: function (range) {
                var cmd = this;
                var doc = cmd.editor.document;
                dom.windowFromDocument(doc).focus();
                Command.fn.releaseRange.call(cmd, range);
            },
            insertTable: function (table) {
                var range = this.range;
                range.insertNode(table);
                range.collapse(true);
                this.editor.selectRange(range);
                this._ensureFocusableAfterTable(table);
            },
            _ensureFocusableAfterTable: function (table) {
                var siblingNodes = $(table).parent().contents();
                var lastSiblingIndex = siblingNodes.length - 1;
                var lastSibling = siblingNodes.get(lastSiblingIndex);
                while (lastSibling.nodeValue !== null && (lastSibling.nodeValue === ' ' || lastSibling.nodeValue === '')) {
                    lastSiblingIndex -= 1;
                    lastSibling = siblingNodes.get(lastSiblingIndex);
                }
                if (lastSibling === table) {
                    dom.insertAfter(dom.createEmptyNode(this.editor.document, 'p'), table);
                }
            },
            updateTable: function (data, table, selectedCells) {
                var cmd = this;
                var tableRows = $(table.rows).toArray();
                var tableProp = data.tableProperties;
                var rows = tableProp.rows;
                var columns = tableProp.columns;
                var last = function (collection) {
                    return collection[collection.length - 1];
                };
                while (selectedCells.length > 1) {
                    selectedCells.pop();
                }
                var lastSelectedRow = selectedCells.length ? last(selectedCells).parentNode : last(tableRows);
                var row, parent;
                cmd._deleteTableRows(tableRows, tableRows.length - rows);
                if (tableRows.length < rows) {
                    var rowIndex = $(lastSelectedRow).index();
                    var cellsLength = lastSelectedRow.cells.length;
                    var newRowsCount = rows - tableRows.length;
                    parent = lastSelectedRow.parentNode;
                    while (newRowsCount) {
                        row = parent.insertRow(rowIndex + 1);
                        cmd._insertCells(cellsLength - row.cells.length, row);
                        newRowsCount--;
                    }
                }
                if (tableRows[0].cells.length > columns) {
                    $(tableRows).each(function (i, row) {
                        while (row.cells.length > columns) {
                            row.deleteCell(-1);
                        }
                    });
                }
                if (tableRows[0].cells.length < columns) {
                    var cellIndex = $(last(selectedCells) || last(lastSelectedRow.cells)).index();
                    $(tableRows).each(function (i, row) {
                        cmd._insertCells(columns - row.cells.length, row, cellIndex + 1);
                    });
                }
                cmd._updateTableProperties(table, tableProp);
                var cellProp = data.cellProperties;
                if (selectedCells[0]) {
                    dom.attr(selectedCells[0], { id: cellProp.id || null });
                }
                (cellProp.selectAllCells ? $(tableRows).children() : $(selectedCells)).each(function (i, cell) {
                    cmd._updateCellProperties(cell, cellProp);
                });
                cmd._updateCaption(table, tableProp);
                tableProp.cellsWithHeaders = tableProp.cellsWithHeaders || false;
                if (cmd.cellsWithHeadersAssociated(table) != tableProp.cellsWithHeaders) {
                    cmd.associateCellsWithHeader(table, tableProp.cellsWithHeaders);
                }
            },
            _isHeadingRow: function (row) {
                return dom.is(row.parentNode, 'thead') || dom.is(row.cells[0], 'th');
            },
            associateCellsWithHeader: function (table, associate) {
                var timestamp = new Date().getTime();
                var ids = [];
                var columns = table.rows[0].cells.length;
                var index, nextRow, isDataRow;
                var generateIds = function () {
                    for (var i = 0; i < columns; i++) {
                        ids[i] = 'table' + ++timestamp;
                    }
                };
                var modifySellsIds = function (c, cell) {
                    $(cell)[associate ? 'attr' : 'removeAttr']('id', ids[c]);
                };
                var modifyCellsHeadings = function (c, cell) {
                    $(cell)[associate ? 'attr' : 'removeAttr']('headers', ids[c]);
                };
                var isHeadingRow = this._isHeadingRow;
                $(table.rows).each(function (r, row) {
                    if (isHeadingRow(row)) {
                        index = r;
                        nextRow = table.rows[++index];
                        isDataRow = nextRow && !isHeadingRow(nextRow);
                        if (isDataRow) {
                            generateIds();
                            $(row.cells).each(modifySellsIds);
                        }
                        while (isDataRow) {
                            $(nextRow.cells).each(modifyCellsHeadings);
                            nextRow = table.rows[++index];
                            isDataRow = nextRow && !isHeadingRow(nextRow);
                        }
                    }
                });
            },
            cellsWithHeadersAssociated: function (table) {
                var cells = $(table.rows).children();
                var isHeadingRow = this._isHeadingRow;
                var headingIds = [];
                cells.each(function (c, cell) {
                    if (cell.id && isHeadingRow(cell.parentNode)) {
                        headingIds.push(cell.id);
                    }
                });
                var associatedCells = cells.filter(function (c, cell) {
                    var headersAttr = cell.getAttribute('headers');
                    return headersAttr && !isHeadingRow(cell.parentNode) && $.inArray(headersAttr, headingIds) > -1;
                });
                return !!associatedCells.length;
            },
            _insertCells: function (count, row, index) {
                index = isNaN(index) ? -1 : index;
                for (var i = 0, cell; i < count; i++) {
                    cell = row.insertCell(index);
                    cell.innerHTML = '&nbsp;';
                }
            },
            _deleteTableRows: function (rows, count) {
                for (var i = 0, row, rowParent; i < count; i++) {
                    row = rows.pop();
                    rowParent = row.parentNode;
                    rowParent.removeChild(row);
                    if (!rowParent.rows.length) {
                        dom.remove(rowParent);
                    }
                }
            },
            createNewTable: function (data) {
                var cmd = this;
                var doc = cmd.editor.document;
                var tableProp = data.tableProperties;
                var cellProp = data.cellProperties;
                var cellPropToAll = cellProp.selectAllCells;
                var table = dom.create(doc, 'table');
                cmd._updateTableProperties(table, tableProp);
                cmd._updateCaption(table, tableProp);
                var tbody = table.createTBody();
                for (var r = 0, row; r < tableProp.rows; r++) {
                    row = tbody.insertRow();
                    for (var c = 0, cell; c < tableProp.columns; c++) {
                        cell = row.insertCell();
                        cell.innerHTML = '&nbsp;';
                        if (r === 0 && c === 0 && cellProp.id) {
                            cell.id = cellProp.id;
                        }
                        cmd._updateCellProperties(cell, cellPropToAll || r === 0 && c === 0 ? cellProp : {});
                    }
                }
                if (tableProp.cellsWithHeaders) {
                    cmd.associateCellsWithHeader(table, tableProp.cellsWithHeaders);
                }
                return table;
            },
            _updateTableProperties: function (table, data) {
                var style = this._getStylesData(data);
                dom.attr(table, {
                    cellSpacing: data.cellSpacing || null,
                    cellPadding: data.cellPadding || null,
                    className: data.className || null,
                    id: data.id || null,
                    summary: data.summary || null,
                    style: style || null
                });
                $(table).addClass('k-table');
            },
            _updateCellProperties: function (cell, data) {
                var style = this._getStylesData(data);
                style.padding = data.cellPadding || null;
                style.margin = data.cellMargin || null;
                dom.attr(cell, {
                    style: style || null,
                    className: data.className || null
                });
            },
            _updateCaption: function (table, data) {
                if (table.caption && !data.captionContent) {
                    table.deleteCaption();
                } else if (data.captionContent) {
                    var caption = table.createCaption();
                    caption.innerHTML = data.captionContent;
                    var alignment = this._getAlignmentData(data.captionAlignment);
                    dom.attr(caption, {
                        style: {
                            textAlign: alignment.textAlign,
                            verticalAlign: alignment.verticalAlign
                        }
                    });
                }
            },
            _getStylesData: function (data) {
                var alignment = this._getAlignmentData(data.alignment);
                var whiteSpace = 'wrapText' in data ? data.wrapText ? '' : 'nowrap' : null;
                return {
                    width: data.width ? data.width + data.widthUnit : null,
                    height: data.height ? data.height + data.heightUnit : null,
                    textAlign: alignment.textAlign,
                    verticalAlign: alignment.verticalAlign,
                    backgroundColor: data.bgColor || '',
                    borderWidth: data.borderWidth,
                    borderStyle: data.borderStyle,
                    borderColor: data.borderColor || '',
                    borderCollapse: data.collapseBorders ? 'collapse' : null,
                    whiteSpace: whiteSpace
                };
            },
            _getAlignmentData: function (alignment) {
                var textAlign = '';
                var verticalAlign = textAlign;
                if (alignment) {
                    if (alignment.indexOf(' ') != -1) {
                        var align = alignment.split(' ');
                        textAlign = align[0];
                        verticalAlign = align[1];
                    } else {
                        textAlign = alignment;
                    }
                }
                return {
                    textAlign: textAlign,
                    verticalAlign: verticalAlign
                };
            },
            parseTable: function (table, selectedCells) {
                if (!table) {
                    return {
                        tableProperties: {},
                        selectedCells: []
                    };
                }
                var cmd = this;
                var tStyle = table.style;
                var rows = table.rows;
                var caption = table.caption;
                var captionClone = $(caption ? caption.cloneNode(true) : undefined);
                captionClone.find('.k-marker').remove();
                var cssClass = table.className;
                cssClass = cssClass.replace(/^k-table\s|\sk-table$/, '');
                cssClass = cssClass.replace(/\sk-table\s/, ' ');
                cssClass = cssClass.replace(/^k-table$/, '');
                var tableAlignment = cmd._getAlignment(table, true);
                var captionAlignment = caption ? cmd._getAlignment(caption) : undefined;
                var cellsWithHeaders = cmd.cellsWithHeadersAssociated(table);
                var tableJson = {
                    tableProperties: {
                        width: tStyle.width || table.width ? parseFloat(tStyle.width || table.width) : null,
                        height: tStyle.height || table.height ? parseFloat(tStyle.height || table.height) : null,
                        columns: rows[0] ? rows[0].children.length : 0,
                        rows: rows.length,
                        widthUnit: cmd._getUnit(tStyle.width),
                        heightUnit: cmd._getUnit(tStyle.height),
                        cellSpacing: table.cellSpacing,
                        cellPadding: table.cellPadding,
                        alignment: tableAlignment.textAlign,
                        bgColor: tStyle.backgroundColor || table.bgColor,
                        className: cssClass,
                        id: table.id,
                        borderWidth: tStyle.borderWidth || table.border,
                        borderColor: tStyle.borderColor,
                        borderStyle: tStyle.borderStyle || '',
                        collapseBorders: !!tStyle.borderCollapse,
                        summary: table.summary,
                        captionContent: caption ? captionClone.html() : '',
                        captionAlignment: caption && captionAlignment.textAlign ? captionAlignment.textAlign + ' ' + captionAlignment.verticalAlign : '',
                        cellsWithHeaders: cellsWithHeaders
                    },
                    selectedCells: []
                };
                tableJson.rows = cmd.parseTableRows(rows, selectedCells, tableJson);
                return tableJson;
            },
            parseTableRows: function (rows, selectedCells, tableJson) {
                var cmd = this;
                var data = [], row, rowData, cells, cell, cellData;
                for (var i = 0; i < rows.length; i++) {
                    row = rows[i];
                    rowData = { cells: [] };
                    cells = row.cells;
                    data.push(rowData);
                    for (var j = 0; j < cells.length; j++) {
                        cell = cells[j];
                        cellData = cmd.parseCell(cell);
                        if ($.inArray(cell, selectedCells) != -1) {
                            tableJson.selectedCells.push(cellData);
                        }
                        rowData.cells.push(cellData);
                    }
                }
                return data;
            },
            parseCell: function (cell) {
                var cmd = this;
                var cStyle = cell.style;
                var alignment = cmd._getAlignment(cell);
                alignment = alignment.textAlign ? alignment.textAlign + ' ' + alignment.verticalAlign : '';
                var data = {
                    width: cStyle.width || cell.width ? parseFloat(cStyle.width || cell.width) : null,
                    height: cStyle.height || cell.height ? parseFloat(cStyle.height || cell.height) : null,
                    widthUnit: cmd._getUnit(cStyle.width),
                    heightUnit: cmd._getUnit(cStyle.height),
                    cellMargin: cStyle.margin,
                    cellPadding: cStyle.padding,
                    alignment: alignment,
                    bgColor: cStyle.backgroundColor || cell.bgColor,
                    className: cell.className,
                    id: cell.id,
                    borderWidth: cStyle.borderWidth || cell.border,
                    borderColor: cStyle.borderColor,
                    borderStyle: cStyle.borderStyle,
                    wrapText: cStyle.whiteSpace != 'nowrap'
                };
                return data;
            },
            _getAlignment: function (element, horizontalOnly) {
                var style = element.style;
                var hAlign = style.textAlign || element.align || '';
                if (horizontalOnly) {
                    return { textAlign: hAlign };
                }
                var vAlign = style.verticalAlign || element.vAlign || '';
                if (hAlign && vAlign) {
                    return {
                        textAlign: hAlign,
                        verticalAlign: vAlign
                    };
                }
                if (!hAlign && vAlign) {
                    return {
                        textAlign: 'left',
                        verticalAlign: vAlign
                    };
                }
                if (hAlign && !vAlign) {
                    return {
                        textAlign: hAlign,
                        verticalAlign: 'top'
                    };
                }
                return {
                    textAlign: '',
                    verticalAlign: ''
                };
            },
            _getUnit: function (value) {
                var unit = (value || '').match(reUnit);
                return unit ? unit[0] : 'px';
            },
            _selectedTable: function (range) {
                var nodes = dom.filterBy(RangeUtils.nodes(range), dom.htmlIndentSpace, true);
                return tableFormatFinder.findSuitable(nodes)[0];
            },
            _selectedCells: function (range) {
                var nodes = dom.filterBy(RangeUtils.nodes(range), dom.htmlIndentSpace, true);
                return cellsFormatFinder.findSuitable(nodes);
            }
        });
        var TableWizardTool = Editor.Tool.extend({
            command: function (options) {
                options.insertNewTable = this.options.insertNewTable;
                return new TableWizardCommand(options);
            }
        });
        var TableWizardEditTool = TableWizardTool.extend({
            update: function (ui, nodes) {
                var isFormatted = !tableFormatFinder.isFormatted(nodes);
                ui.toggleClass('k-state-disabled', isFormatted);
            }
        });
        kendo.ui.editor.TableWizardTool = TableWizardTool;
        kendo.ui.editor.TableWizardCommand = TableWizardCommand;
        registerTool('tableWizard', new TableWizardEditTool({
            command: TableWizardCommand,
            insertNewTable: false,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Table Wizard'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.tabstrip', ['kendo.data'], f);
}(function () {
    var __meta__ = {
        id: 'tabstrip',
        name: 'TabStrip',
        category: 'web',
        description: 'The TabStrip widget displays a collection of tabs with associated tab content.',
        depends: ['data'],
        features: [{
                id: 'tabstrip-fx',
                name: 'Animation',
                description: 'Support for animation',
                depends: ['fx']
            }]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, keys = kendo.keys, map = $.map, each = $.each, trim = $.trim, extend = $.extend, isFunction = kendo.isFunction, template = kendo.template, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, Widget = ui.Widget, excludedNodesRegExp = /^(a|div)$/i, NS = '.kendoTabStrip', IMG = 'img', HREF = 'href', PREV = 'prev', NEXT = 'next', SHOW = 'show', LINK = 'k-link', LAST = 'k-last', CLICK = 'click', ERROR = 'error', EMPTY = ':empty', IMAGE = 'k-image', FIRST = 'k-first', SELECT = 'select', ACTIVATE = 'activate', CONTENT = 'k-content', CONTENTURL = 'contentUrl', MOUSEENTER = 'mouseenter', MOUSELEAVE = 'mouseleave', CONTENTLOAD = 'contentLoad', DISABLEDSTATE = 'k-state-disabled', DEFAULTSTATE = 'k-state-default', ACTIVESTATE = 'k-state-active', FOCUSEDSTATE = 'k-state-focused', HOVERSTATE = 'k-state-hover', TABONTOP = 'k-tab-on-top', NAVIGATABLEITEMS = '.k-item:not(.' + DISABLEDSTATE + ')', KEYBOARDNAVIGATABLEITEMS = '.k-item', HOVERABLEITEMS = '.k-tabstrip-items > ' + NAVIGATABLEITEMS + ':not(.' + ACTIVESTATE + ')', DEFAULTDISTANCE = 200, templates = {
                content: template('<div class=\'k-content\'#= contentAttributes(data) # role=\'tabpanel\'>#= content(item) #</div>'),
                itemWrapper: template('<#= tag(item) # class=\'k-link\'#= contentUrl(item) ##= textAttributes(item) #>' + '#= image(item) ##= sprite(item) ##= text(item) #' + '</#= tag(item) #>'),
                item: template('<li class=\'#= wrapperCssClass(group, item) #\' role=\'tab\' #=item.active ? "aria-selected=\'true\'" : \'\'#>' + '#= itemWrapper(data) #' + '</li>'),
                image: template('<img class=\'k-image\' alt=\'\' src=\'#= imageUrl #\' />'),
                sprite: template('<span class=\'k-sprite #= spriteCssClass #\'></span>'),
                empty: template('')
            }, rendering = {
                wrapperCssClass: function (group, item) {
                    var result = 'k-item', index = item.index;
                    if (item.enabled === false) {
                        result += ' k-state-disabled';
                    } else {
                        result += ' k-state-default';
                    }
                    if (index === 0) {
                        result += ' k-first';
                    }
                    if (index == group.length - 1) {
                        result += ' k-last';
                    }
                    return result;
                },
                textAttributes: function (item) {
                    return item.url ? ' href=\'' + item.url + '\'' : '';
                },
                text: function (item) {
                    return item.encoded === false ? item.text : kendo.htmlEncode(item.text);
                },
                tag: function (item) {
                    return item.url ? 'a' : 'span';
                },
                contentAttributes: function (content) {
                    return content.active !== true ? ' style=\'display:none\' aria-hidden=\'true\' aria-expanded=\'false\'' : '';
                },
                content: function (item) {
                    return item.content ? item.content : item.contentUrl ? '' : '&nbsp;';
                },
                contentUrl: function (item) {
                    return item.contentUrl ? kendo.attr('content-url') + '="' + item.contentUrl + '"' : '';
                }
            };
        function updateTabClasses(tabs) {
            tabs.children(IMG).addClass(IMAGE);
            tabs.children('a').addClass(LINK).children(IMG).addClass(IMAGE);
            tabs.filter(':not([disabled]):not([class*=k-state-disabled])').addClass(DEFAULTSTATE);
            tabs.filter('li[disabled]').addClass(DISABLEDSTATE).attr('aria-disabled', 'true').removeAttr('disabled');
            tabs.filter(':not([class*=k-state])').children('a').filter(':focus').parent().addClass(ACTIVESTATE + ' ' + TABONTOP);
            tabs.attr('role', 'tab');
            tabs.filter('.' + ACTIVESTATE).attr('aria-selected', true);
            tabs.each(function () {
                var item = $(this);
                if (!item.children('.' + LINK).length) {
                    item.contents().filter(function () {
                        return !this.nodeName.match(excludedNodesRegExp) && !(this.nodeType == 3 && !trim(this.nodeValue));
                    }).wrapAll('<span UNSELECTABLE=\'on\' class=\'' + LINK + '\'/>');
                }
            });
        }
        function updateFirstLast(tabGroup) {
            var tabs = tabGroup.children('.k-item');
            tabs.filter('.k-first:not(:first-child)').removeClass(FIRST);
            tabs.filter('.k-last:not(:last-child)').removeClass(LAST);
            tabs.filter(':first-child').addClass(FIRST);
            tabs.filter(':last-child').addClass(LAST);
        }
        function scrollButtonHtml(buttonClass, iconClass) {
            return '<span class=\'k-button k-button-icon k-bare k-tabstrip-' + buttonClass + '\' unselectable=\'on\'><span class=\'k-icon ' + iconClass + '\'></span></span>';
        }
        var TabStrip = Widget.extend({
            init: function (element, options) {
                var that = this, value;
                Widget.fn.init.call(that, element, options);
                that._animations(that.options);
                options = that.options;
                that._contentUrls = options.contentUrls || [];
                that._wrapper();
                that._isRtl = kendo.support.isRtl(that.wrapper);
                that._tabindex();
                that._updateClasses();
                that._dataSource();
                if (options.dataSource) {
                    that.dataSource.fetch();
                }
                that._tabPosition();
                that._scrollable();
                if (that._contentUrls.length) {
                    that.wrapper.find('.k-tabstrip-items > .k-item').each(function (index, item) {
                        var url = that._contentUrls[index];
                        if (typeof url === 'string') {
                            $(item).find('>.' + LINK).data(CONTENTURL, url);
                        }
                    });
                } else {
                    that._contentUrls.length = that.tabGroup.find('li.k-item').length;
                }
                that.wrapper.on(MOUSEENTER + NS + ' ' + MOUSELEAVE + NS, HOVERABLEITEMS, that._toggleHover).on('focus' + NS, $.proxy(that._active, that)).on('blur' + NS, function () {
                    that._current(null);
                });
                that._keyDownProxy = $.proxy(that._keydown, that);
                if (options.navigatable) {
                    that.wrapper.on('keydown' + NS, that._keyDownProxy);
                }
                if (that.options.value) {
                    value = that.options.value;
                }
                that.wrapper.children('.k-tabstrip-items').on(CLICK + NS, '.k-state-disabled .k-link', false).on(CLICK + NS, ' > ' + NAVIGATABLEITEMS, function (e) {
                    var wr = that.wrapper[0];
                    if (wr !== document.activeElement) {
                        var msie = kendo.support.browser.msie;
                        if (msie) {
                            try {
                                wr.setActive();
                            } catch (j) {
                                wr.focus();
                            }
                        } else {
                            wr.focus();
                        }
                    }
                    if (that._click($(e.currentTarget))) {
                        e.preventDefault();
                    }
                });
                var selectedItems = that.tabGroup.children('li.' + ACTIVESTATE), content = that.contentHolder(selectedItems.index());
                if (selectedItems[0] && content.length > 0 && content[0].childNodes.length === 0) {
                    that.activateTab(selectedItems.eq(0));
                }
                that.element.attr('role', 'tablist');
                if (that.element[0].id) {
                    that._ariaId = that.element[0].id + '_ts_active';
                }
                that.value(value);
                kendo.notify(that);
            },
            _active: function () {
                var item = this.tabGroup.children().filter('.' + ACTIVESTATE);
                item = item[0] ? item : this._endItem('first');
                if (item[0]) {
                    this._current(item);
                }
            },
            _endItem: function (action) {
                return this.tabGroup.children(NAVIGATABLEITEMS)[action]();
            },
            _getItem: function (action) {
                return this.tabGroup.children(KEYBOARDNAVIGATABLEITEMS)[action]();
            },
            _item: function (item, action) {
                var endItem;
                if (action === PREV) {
                    endItem = 'last';
                } else {
                    endItem = 'first';
                }
                if (!item) {
                    return this._endItem(endItem);
                }
                item = item[action]();
                if (!item[0]) {
                    item = this.tabGroup.children(KEYBOARDNAVIGATABLEITEMS)[endItem]();
                }
                if (item.hasClass(DISABLEDSTATE)) {
                    item.addClass(FOCUSEDSTATE);
                }
                if (item.hasClass(DISABLEDSTATE) || item.hasClass(ACTIVESTATE)) {
                    this._focused = item;
                }
                return item;
            },
            _current: function (candidate) {
                var that = this, focused = that._focused, id = that._ariaId;
                if (candidate === undefined) {
                    return focused;
                }
                if (focused) {
                    that.tabGroup.children('#' + id).removeAttr('id');
                    focused.removeClass(FOCUSEDSTATE);
                }
                if (candidate) {
                    if (!candidate.hasClass(ACTIVESTATE)) {
                        candidate.addClass(FOCUSEDSTATE);
                    }
                    that.element.removeAttr('aria-activedescendant');
                    id = candidate[0].id || id;
                    if (id) {
                        candidate.attr('id', id);
                        that.element.attr('aria-activedescendant', id);
                    }
                }
                that._focused = candidate;
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, current = that._current(), rtl = that._isRtl, isHorizontal = /top|bottom/.test(that.options.tabPosition), action;
                if (e.target != e.currentTarget) {
                    return;
                }
                if (key === keys.DOWN && !isHorizontal) {
                    action = NEXT;
                } else if (key === keys.UP && !isHorizontal) {
                    action = PREV;
                } else if (key === keys.RIGHT && isHorizontal) {
                    action = rtl ? PREV : NEXT;
                } else if (key === keys.LEFT && isHorizontal) {
                    action = rtl ? NEXT : PREV;
                } else if (key == keys.ENTER || key == keys.SPACEBAR) {
                    that._click(current);
                    e.preventDefault();
                } else if (key == keys.HOME) {
                    that._click(that._getItem('first'));
                    e.preventDefault();
                    return;
                } else if (key == keys.END) {
                    that._click(that._getItem('last'));
                    e.preventDefault();
                    return;
                }
                if (action) {
                    that._click(that._item(current, action));
                    e.preventDefault();
                }
            },
            _dataSource: function () {
                var that = this;
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind('change', that._refreshHandler);
                } else {
                    that._refreshHandler = $.proxy(that.refresh, that);
                }
                that.dataSource = kendo.data.DataSource.create(that.options.dataSource).bind('change', that._refreshHandler);
            },
            setDataSource: function (dataSource) {
                var that = this;
                that.options.dataSource = dataSource;
                that._dataSource();
                that.dataSource.fetch();
            },
            _animations: function (options) {
                if (options && 'animation' in options && !options.animation) {
                    options.animation = {
                        open: { effects: {} },
                        close: { effects: {} }
                    };
                }
            },
            refresh: function (e) {
                var that = this, options = that.options, encoded = kendo.getter(options.dataEncodedField), text = kendo.getter(options.dataTextField), content = kendo.getter(options.dataContentField), contentUrl = kendo.getter(options.dataContentUrlField), image = kendo.getter(options.dataImageUrlField), url = kendo.getter(options.dataUrlField), sprite = kendo.getter(options.dataSpriteCssClass), idx, tabs = [], tab, action, view = that.dataSource.view(), length;
                e = e || {};
                action = e.action;
                if (action) {
                    view = e.items;
                }
                for (idx = 0, length = view.length; idx < length; idx++) {
                    tab = { text: text(view[idx]) };
                    if (options.dataEncodedField) {
                        tab.encoded = encoded(view[idx]);
                    }
                    if (options.dataContentField) {
                        tab.content = content(view[idx]);
                    }
                    if (options.dataContentUrlField) {
                        tab.contentUrl = contentUrl(view[idx]);
                    }
                    if (options.dataUrlField) {
                        tab.url = url(view[idx]);
                    }
                    if (options.dataImageUrlField) {
                        tab.imageUrl = image(view[idx]);
                    }
                    if (options.dataSpriteCssClass) {
                        tab.spriteCssClass = sprite(view[idx]);
                    }
                    tabs[idx] = tab;
                }
                if (e.action == 'add') {
                    if (e.index < that.tabGroup.children().length) {
                        that.insertBefore(tabs, that.tabGroup.children().eq(e.index));
                    } else {
                        that.append(tabs);
                    }
                } else if (e.action == 'remove') {
                    for (idx = 0; idx < view.length; idx++) {
                        that.remove(e.index);
                    }
                } else if (e.action == 'itemchange') {
                    idx = that.dataSource.view().indexOf(view[0]);
                    if (e.field === options.dataTextField) {
                        that.tabGroup.children().eq(idx).find('.k-link').text(view[0].get(e.field));
                    }
                    if (e.field === options.dataUrlField) {
                        that._contentUrls[idx] = view[0].get(e.field);
                    }
                } else {
                    that.trigger('dataBinding');
                    that.remove('li');
                    that._contentUrls = [];
                    that.append(tabs);
                    that.trigger('dataBound');
                }
            },
            value: function (value) {
                var that = this;
                if (value !== undefined) {
                    if (value != that.value()) {
                        that.tabGroup.children().each(function () {
                            if ($.trim($(this).text()) == value) {
                                that.select(this);
                            }
                        });
                    }
                } else {
                    return that.select().text();
                }
            },
            items: function () {
                return this.tabGroup[0].children;
            },
            setOptions: function (options) {
                var that = this, animation = that.options.animation;
                that._animations(options);
                if (options.contentUrls) {
                    that._contentUrls = options.contentUrls;
                }
                options.animation = extend(true, animation, options.animation);
                if (options.navigatable) {
                    that.wrapper.on('keydown' + NS, that._keyDownProxy);
                } else {
                    that.wrapper.off('keydown' + NS, that._keyDownProxy);
                }
                Widget.fn.setOptions.call(that, options);
            },
            events: [
                SELECT,
                ACTIVATE,
                SHOW,
                ERROR,
                CONTENTLOAD,
                'change',
                'dataBinding',
                'dataBound'
            ],
            options: {
                name: 'TabStrip',
                dataEncodedField: '',
                dataTextField: '',
                dataContentField: '',
                dataImageUrlField: '',
                dataUrlField: '',
                dataSpriteCssClass: '',
                dataContentUrlField: '',
                tabPosition: 'top',
                animation: {
                    open: {
                        effects: 'expand:vertical fadeIn',
                        duration: 200
                    },
                    close: { duration: 200 }
                },
                collapsible: false,
                navigatable: true,
                contentUrls: false,
                scrollable: { distance: DEFAULTDISTANCE }
            },
            destroy: function () {
                var that = this, scrollWrap = that.scrollWrap;
                Widget.fn.destroy.call(that);
                if (that._refreshHandler) {
                    that.dataSource.unbind('change', that._refreshHandler);
                }
                that.wrapper.off(NS);
                that.wrapper.children('.k-tabstrip-items').off(NS);
                if (that._scrollableModeActive) {
                    that._scrollPrevButton.off().remove();
                    that._scrollNextButton.off().remove();
                }
                kendo.destroy(that.wrapper);
                scrollWrap.children('.k-tabstrip').unwrap();
            },
            select: function (element) {
                var that = this;
                if (arguments.length === 0) {
                    return that.tabGroup.children('li.' + ACTIVESTATE);
                }
                if (!isNaN(element)) {
                    element = that.tabGroup.children().get(element);
                }
                element = that.tabGroup.find(element);
                $(element).each(function (index, item) {
                    item = $(item);
                    if (!item.hasClass(ACTIVESTATE) && !that.trigger(SELECT, {
                            item: item[0],
                            contentElement: that.contentHolder(item.index())[0]
                        })) {
                        that.activateTab(item);
                    }
                });
                return that;
            },
            enable: function (element, state) {
                this._toggleDisabled(element, state !== false);
                return this;
            },
            disable: function (element) {
                this._toggleDisabled(element, false);
                return this;
            },
            reload: function (element) {
                element = this.tabGroup.find(element);
                var that = this;
                var contentUrls = that._contentUrls;
                element.each(function () {
                    var item = $(this), contentUrl = item.find('.' + LINK).data(CONTENTURL) || contentUrls[item.index()], content = that.contentHolder(item.index());
                    if (contentUrl) {
                        that.ajaxRequest(item, content, null, contentUrl);
                    }
                });
                return that;
            },
            append: function (tab) {
                var that = this, inserted = that._create(tab);
                each(inserted.tabs, function (idx) {
                    var contents = inserted.contents[idx];
                    that.tabGroup.append(this);
                    if (that.options.tabPosition == 'bottom') {
                        that.tabGroup.before(contents);
                    } else if (that._scrollableModeActive) {
                        that._scrollPrevButton.before(contents);
                    } else {
                        that.wrapper.append(contents);
                    }
                    that.angular('compile', function () {
                        return { elements: [contents] };
                    });
                });
                updateFirstLast(that.tabGroup);
                that._updateContentElements();
                that.resize(true);
                return that;
            },
            _appendUrlItem: function (url) {
                this._contentUrls.push(url);
            },
            _moveUrlItem: function (from, to) {
                this._contentUrls.splice(to, 0, this._contentUrls.splice(from, 1)[0]);
            },
            _removeUrlItem: function (index) {
                this._contentUrls.splice(index, 1);
            },
            insertBefore: function (tab, referenceTab) {
                if ($(tab).is($(referenceTab))) {
                    referenceTab = this.tabGroup.find(referenceTab).next();
                } else {
                    referenceTab = this.tabGroup.find(referenceTab);
                }
                var that = this, inserted = that._create(tab), referenceContent = that.element.find('[id=\'' + referenceTab.attr('aria-controls') + '\']');
                each(inserted.tabs, function (idx) {
                    var contents = inserted.contents[idx];
                    var fromIndex = inserted.newTabsCreated ? that._contentUrls.length - (inserted.tabs.length - idx) : $(contents).index() - 1;
                    referenceTab.before(this);
                    referenceContent.before(contents);
                    that._moveUrlItem(fromIndex, $(this).index());
                    that.angular('compile', function () {
                        return { elements: [contents] };
                    });
                });
                updateFirstLast(that.tabGroup);
                that._updateContentElements(inserted.newTabsCreated);
                that.resize(true);
                return that;
            },
            insertAfter: function (tab, referenceTab) {
                if ($(tab).is($(referenceTab))) {
                    referenceTab = this.tabGroup.find(referenceTab).prev();
                } else {
                    referenceTab = this.tabGroup.find(referenceTab);
                }
                var that = this, inserted = that._create(tab), referenceContent = that.element.find('[id=\'' + referenceTab.attr('aria-controls') + '\']');
                each(inserted.tabs, function (idx) {
                    var contents = inserted.contents[idx];
                    var fromIndex = inserted.newTabsCreated ? that._contentUrls.length - (inserted.tabs.length - idx) : $(contents).index() - 1;
                    referenceTab.after(this);
                    referenceContent.after(contents);
                    that._moveUrlItem(fromIndex, $(this).index());
                    that.angular('compile', function () {
                        return { elements: [contents] };
                    });
                });
                updateFirstLast(that.tabGroup);
                that._updateContentElements(inserted.newTabsCreated);
                that.resize(true);
                return that;
            },
            remove: function (elements) {
                var that = this;
                var type = typeof elements;
                var contents;
                if (type === 'string') {
                    elements = that.tabGroup.find(elements);
                } else if (type === 'number') {
                    elements = that.tabGroup.children().eq(elements);
                }
                contents = elements.map(function () {
                    var idx = $(this).index();
                    var content = that.contentElement(idx);
                    kendo.destroy(content);
                    that._removeUrlItem(idx);
                    return content;
                });
                elements.remove();
                contents.empty();
                contents.remove();
                that._updateContentElements();
                that.resize(true);
                return that;
            },
            _create: function (tab) {
                var that = this, tabs, contents, content, newTabsCreated = false;
                tab = tab instanceof kendo.data.ObservableArray ? tab.toJSON() : tab;
                if ($.isPlainObject(tab) || $.isArray(tab)) {
                    tab = $.isArray(tab) ? tab : [tab];
                    newTabsCreated = true;
                    tabs = map(tab, function (value, idx) {
                        that._appendUrlItem(tab[idx].contentUrl || null);
                        return $(TabStrip.renderItem({
                            group: that.tabGroup,
                            item: extend(value, { index: idx })
                        }));
                    });
                    contents = map(tab, function (value, idx) {
                        if (typeof value.content == 'string' || value.contentUrl) {
                            return $(TabStrip.renderContent({ item: extend(value, { index: idx }) }));
                        }
                    });
                } else {
                    if (typeof tab == 'string' && tab[0] != '<') {
                        tabs = that.element.find(tab);
                    } else {
                        tabs = $(tab);
                    }
                    contents = $();
                    tabs.each(function () {
                        if (/k-tabstrip-items/.test(this.parentNode.className)) {
                            var element = that.element.find('[id=\'' + this.getAttribute('aria-controls') + '\']');
                            content = element;
                        } else {
                            content = $('<div class=\'' + CONTENT + '\'/>');
                        }
                        contents = contents.add(content);
                    });
                    updateTabClasses(tabs);
                }
                return {
                    tabs: tabs,
                    contents: contents,
                    newTabsCreated: newTabsCreated
                };
            },
            _toggleDisabled: function (element, enable) {
                element = this.tabGroup.find(element);
                element.each(function () {
                    $(this).toggleClass(DEFAULTSTATE, enable).toggleClass(DISABLEDSTATE, !enable).attr('aria-disabled', !enable);
                });
            },
            _updateClasses: function () {
                var that = this, tabs, activeItem, activeTab;
                that.wrapper.addClass('k-widget k-header k-tabstrip');
                that.tabGroup = that.wrapper.children('ul').addClass('k-tabstrip-items k-reset');
                if (!that.tabGroup[0]) {
                    that.tabGroup = $('<ul class=\'k-tabstrip-items k-reset\'/>').appendTo(that.wrapper);
                }
                tabs = that.tabGroup.find('li').addClass('k-item');
                if (tabs.length) {
                    activeItem = tabs.filter('.' + ACTIVESTATE).index();
                    activeTab = activeItem >= 0 ? activeItem : undefined;
                    that.tabGroup.contents().filter(function () {
                        return this.nodeType == 3 && !trim(this.nodeValue);
                    }).remove();
                }
                if (activeItem >= 0) {
                    tabs.eq(activeItem).addClass(TABONTOP);
                }
                that.contentElements = that.wrapper.children('div');
                that.contentElements.addClass(CONTENT).eq(activeTab).addClass(ACTIVESTATE).css({ display: 'block' });
                if (tabs.length) {
                    updateTabClasses(tabs);
                    updateFirstLast(that.tabGroup);
                    that._updateContentElements(true);
                }
            },
            _elementId: function (element, idx) {
                var elementId = element.attr('id');
                var wrapperId = this.element.attr('id');
                if (!elementId || elementId.indexOf(wrapperId + '-') > -1) {
                    var tabStripID = (wrapperId || kendo.guid()) + '-';
                    return tabStripID + (idx + 1);
                }
                return elementId;
            },
            _updateContentElements: function (isInitialUpdate) {
                var that = this, contentUrls = that._contentUrls, items = that.tabGroup.children('.k-item'), contentElements = that.wrapper.children('div'), _elementId = that._elementId.bind(that);
                if (contentElements.length && items.length > contentElements.length) {
                    contentElements.each(function (idx) {
                        var id = _elementId($(this), idx);
                        var item = items.filter('[aria-controls=' + (this.id || 0) + ']')[0];
                        if (!item && isInitialUpdate) {
                            item = items[idx];
                        }
                        if (item) {
                            item.setAttribute('aria-controls', id);
                        }
                        this.setAttribute('id', id);
                    });
                } else {
                    items.each(function (idx) {
                        var currentContent = contentElements.eq(idx);
                        var id = _elementId(currentContent, idx);
                        this.setAttribute('aria-controls', id);
                        if (!currentContent.length && contentUrls[idx]) {
                            $('<div class=\'' + CONTENT + '\'/>').appendTo(that.wrapper).attr('id', id);
                        } else {
                            currentContent.attr('id', id);
                            if (!$(this).children('.k-loading')[0] && !contentUrls[idx]) {
                                $('<span class=\'k-loading k-complete\'/>').prependTo(this);
                            }
                        }
                        currentContent.attr('role', 'tabpanel');
                        currentContent.filter(':not(.' + ACTIVESTATE + ')').attr('aria-hidden', true).attr('aria-expanded', false);
                        currentContent.filter('.' + ACTIVESTATE).attr('aria-expanded', true);
                    });
                }
                that.contentElements = that.contentAnimators = that.wrapper.children('div');
                that.tabsHeight = outerHeight(that.tabGroup) + parseInt(that.wrapper.css('border-top-width'), 10) + parseInt(that.wrapper.css('border-bottom-width'), 10);
                if (kendo.kineticScrollNeeded && kendo.mobile.ui.Scroller) {
                    kendo.touchScroller(that.contentElements);
                    that.contentElements = that.contentElements.children('.km-scroll-container');
                }
            },
            _wrapper: function () {
                var that = this;
                if (that.element.is('ul')) {
                    that.wrapper = that.element.wrapAll('<div />').parent();
                } else {
                    that.wrapper = that.element;
                }
                that.scrollWrap = that.wrapper.parent('.k-tabstrip-wrapper');
                if (!that.scrollWrap[0]) {
                    that.scrollWrap = that.wrapper.wrapAll('<div class=\'k-tabstrip-wrapper\' />').parent();
                }
            },
            _tabPosition: function () {
                var that = this, tabPosition = that.options.tabPosition;
                that.wrapper.addClass('k-floatwrap k-tabstrip-' + tabPosition);
                if (tabPosition == 'bottom') {
                    that.tabGroup.appendTo(that.wrapper);
                }
                that.resize(true);
            },
            _setContentElementsDimensions: function () {
                var that = this, tabPosition = that.options.tabPosition;
                if (tabPosition == 'left' || tabPosition == 'right') {
                    var contentDivs = that.wrapper.children('.k-content'), activeDiv = contentDivs.filter(':visible'), marginStyleProperty = 'margin-' + tabPosition, tabGroup = that.tabGroup, margin = outerWidth(tabGroup);
                    var minHeight = Math.ceil(tabGroup.height()) - parseInt(activeDiv.css('padding-top'), 10) - parseInt(activeDiv.css('padding-bottom'), 10) - parseInt(activeDiv.css('border-top-width'), 10) - parseInt(activeDiv.css('border-bottom-width'), 10);
                    setTimeout(function () {
                        contentDivs.css(marginStyleProperty, margin).css('min-height', minHeight);
                    });
                }
            },
            _resize: function () {
                this._setContentElementsDimensions();
                this._scrollable();
            },
            _sizeScrollWrap: function (element) {
                if (element.is(':visible')) {
                    var tabPosition = this.options.tabPosition;
                    var h = Math.floor(outerHeight(element, true)) + (tabPosition === 'left' || tabPosition === 'right' ? 2 : this.tabsHeight);
                    this.scrollWrap.css('height', h).css('height');
                }
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVERSTATE, e.type == MOUSEENTER);
            },
            _click: function (item) {
                var that = this, link = item.find('.' + LINK), href = link.attr(HREF), collapse = that.options.collapsible, index = item.index(), contentHolder = that.contentHolder(index), prevent, isAnchor, neighbours = item.parent().children(), oldFocusedTab = neighbours.filter('.' + FOCUSEDSTATE);
                if (item.closest('.k-widget')[0] != that.wrapper[0]) {
                    return;
                }
                if (item.is('.' + DISABLEDSTATE + (!collapse ? ',.' + ACTIVESTATE : ''))) {
                    oldFocusedTab.removeClass(FOCUSEDSTATE);
                    that._focused = item;
                    item.addClass(FOCUSEDSTATE);
                    that._current(item);
                    if (that._scrollableModeActive) {
                        that._scrollTabsToItem(item);
                    }
                    return true;
                }
                isAnchor = link.data(CONTENTURL) || that._contentUrls[index] || href && (href.charAt(href.length - 1) == '#' || href.indexOf('#' + that.element[0].id + '-') != -1);
                prevent = !href || isAnchor;
                if (that.tabGroup.children('[data-animating]').length) {
                    return prevent;
                }
                if (that.trigger(SELECT, {
                        item: item[0],
                        contentElement: contentHolder[0]
                    })) {
                    return true;
                }
                if (prevent === false) {
                    return;
                }
                if (collapse && item.is('.' + ACTIVESTATE)) {
                    that.deactivateTab(item);
                    return true;
                }
                if (that.activateTab(item)) {
                    prevent = true;
                }
                return prevent;
            },
            _scrollable: function () {
                var that = this, options = that.options, wrapperOffsetWidth, tabGroupScrollWidth, scrollPrevButton, scrollNextButton;
                if (that._scrollableAllowed()) {
                    that.wrapper.addClass('k-tabstrip-scrollable');
                    wrapperOffsetWidth = that.wrapper[0].offsetWidth;
                    tabGroupScrollWidth = that.tabGroup[0].scrollWidth;
                    if (tabGroupScrollWidth > wrapperOffsetWidth && !that._scrollableModeActive) {
                        that._nowScrollingTabs = false;
                        that._isRtl = kendo.support.isRtl(that.element);
                        var mouseDown = kendo.support.mobileOS ? 'touchstart' : 'mousedown';
                        var mouseUp = kendo.support.mobileOS ? 'touchend' : 'mouseup';
                        var browser = kendo.support.browser;
                        var isRtlScrollDirection = that._isRtl && !browser.msie && !browser.edge;
                        that.wrapper.append(scrollButtonHtml('prev', 'k-i-arrow-60-left') + scrollButtonHtml('next', 'k-i-arrow-60-right'));
                        scrollPrevButton = that._scrollPrevButton = that.wrapper.children('.k-tabstrip-prev');
                        scrollNextButton = that._scrollNextButton = that.wrapper.children('.k-tabstrip-next');
                        that.tabGroup.css({
                            marginLeft: outerWidth(scrollPrevButton) + 9,
                            marginRight: outerWidth(scrollNextButton) + 12
                        });
                        scrollPrevButton.on(mouseDown + NS, function () {
                            that._nowScrollingTabs = true;
                            that._scrollTabsByDelta(options.scrollable.distance * (isRtlScrollDirection ? 1 : -1));
                        });
                        scrollNextButton.on(mouseDown + NS, function () {
                            that._nowScrollingTabs = true;
                            that._scrollTabsByDelta(options.scrollable.distance * (isRtlScrollDirection ? -1 : 1));
                        });
                        scrollPrevButton.add(scrollNextButton).on(mouseUp + NS, function () {
                            that._nowScrollingTabs = false;
                        });
                        that._scrollableModeActive = true;
                        that._toggleScrollButtons();
                    } else if (that._scrollableModeActive && tabGroupScrollWidth <= wrapperOffsetWidth) {
                        that._scrollableModeActive = false;
                        that.wrapper.removeClass('k-tabstrip-scrollable');
                        that._scrollPrevButton.off().remove();
                        that._scrollNextButton.off().remove();
                        that.tabGroup.css({
                            marginLeft: '',
                            marginRight: ''
                        });
                    } else if (!that._scrollableModeActive) {
                        that.wrapper.removeClass('k-tabstrip-scrollable');
                    } else {
                        that._toggleScrollButtons();
                    }
                }
            },
            _scrollableAllowed: function () {
                var options = this.options;
                if (options.scrollable && !options.scrollable.distance) {
                    options.scrollable = { distance: DEFAULTDISTANCE };
                }
                return options.scrollable && !isNaN(options.scrollable.distance) && (options.tabPosition == 'top' || options.tabPosition == 'bottom');
            },
            _scrollTabsToItem: function (item) {
                var that = this, tabGroup = that.tabGroup, currentScrollOffset = tabGroup.scrollLeft(), itemWidth = outerWidth(item), itemOffset = that._isRtl ? item.position().left : item.position().left - tabGroup.children().first().position().left, tabGroupWidth = tabGroup[0].offsetWidth, tabGroupPadding = Math.ceil(parseFloat(tabGroup.css('padding-left'))), itemPosition;
                if (that._isRtl) {
                    if (itemOffset < 0) {
                        itemPosition = currentScrollOffset + itemOffset - (tabGroupWidth - currentScrollOffset) - tabGroupPadding;
                    } else if (itemOffset + itemWidth > tabGroupWidth) {
                        itemPosition = currentScrollOffset + itemOffset - itemWidth + tabGroupPadding * 2;
                    }
                } else {
                    if (currentScrollOffset + tabGroupWidth < itemOffset + itemWidth) {
                        itemPosition = itemOffset + itemWidth - tabGroupWidth + tabGroupPadding * 2;
                    } else if (currentScrollOffset > itemOffset) {
                        itemPosition = itemOffset - tabGroupPadding;
                    }
                }
                tabGroup.finish().animate({ 'scrollLeft': itemPosition }, 'fast', 'linear', function () {
                    that._toggleScrollButtons();
                });
            },
            _scrollTabsByDelta: function (delta) {
                var that = this;
                var tabGroup = that.tabGroup;
                var scrLeft = tabGroup.scrollLeft();
                tabGroup.finish().animate({ 'scrollLeft': scrLeft + delta }, 'fast', 'linear', function () {
                    if (that._nowScrollingTabs && !jQuery.fx.off) {
                        that._scrollTabsByDelta(delta);
                    } else {
                        that._toggleScrollButtons();
                    }
                });
            },
            _toggleScrollButtons: function () {
                var that = this, ul = that.tabGroup, scrollLeft = kendo.scrollLeft(ul);
                that._scrollPrevButton.toggle(scrollLeft !== 0);
                that._scrollNextButton.toggle(scrollLeft < ul[0].scrollWidth - ul[0].offsetWidth - 1);
            },
            deactivateTab: function (item) {
                var that = this, animationSettings = that.options.animation, animation = animationSettings.open, close = extend({}, animationSettings.close), hasCloseAnimation = close && 'effects' in close;
                item = that.tabGroup.find(item);
                close = extend(hasCloseAnimation ? close : extend({ reverse: true }, animation), { hide: true });
                if (kendo.size(animation.effects)) {
                    item.kendoAddClass(DEFAULTSTATE, { duration: animation.duration });
                    item.kendoRemoveClass(ACTIVESTATE, { duration: animation.duration });
                } else {
                    item.addClass(DEFAULTSTATE);
                    item.removeClass(ACTIVESTATE);
                }
                item.removeAttr('aria-selected');
                that.contentAnimators.filter('.' + ACTIVESTATE).kendoStop(true, true).kendoAnimate(close).removeClass(ACTIVESTATE).attr('aria-hidden', true);
            },
            activateTab: function (item) {
                if (this.tabGroup.children('[data-animating]').length) {
                    return;
                }
                item = this.tabGroup.find(item);
                var that = this, animationSettings = that.options.animation, animation = animationSettings.open, close = extend({}, animationSettings.close), hasCloseAnimation = close && 'effects' in close, neighbours = item.parent().children(), oldTab = neighbours.filter('.' + ACTIVESTATE), itemIndex = neighbours.index(item), isAnimationEnabled = animation && 'duration' in animation && 'effects' in animation;
                close = extend(hasCloseAnimation ? close : extend({ reverse: true }, animation), { hide: true });
                if (kendo.size(animation.effects)) {
                    oldTab.kendoRemoveClass(ACTIVESTATE, { duration: close.duration });
                    item.kendoRemoveClass(HOVERSTATE, { duration: close.duration });
                } else {
                    oldTab.removeClass(ACTIVESTATE);
                    item.removeClass(HOVERSTATE);
                }
                var contentAnimators = that.contentAnimators;
                if (that.inRequest) {
                    that.xhr.abort();
                    that.inRequest = false;
                }
                if (contentAnimators.length === 0) {
                    that.tabGroup.find('.' + TABONTOP).removeClass(TABONTOP);
                    item.addClass(TABONTOP).css('z-index');
                    item.addClass(ACTIVESTATE);
                    that._current(item);
                    that.trigger('change');
                    if (that._scrollableModeActive) {
                        that._scrollTabsToItem(item);
                    }
                    return false;
                }
                var visibleContents = contentAnimators.filter('.' + ACTIVESTATE), contentHolder = that.contentHolder(itemIndex), contentElement = contentHolder.closest('.k-content');
                that.tabsHeight = outerHeight(that.tabGroup) + parseInt(that.wrapper.css('border-top-width'), 10) + parseInt(that.wrapper.css('border-bottom-width'), 10);
                that._sizeScrollWrap(visibleContents);
                if (contentHolder.length === 0) {
                    visibleContents.removeClass(ACTIVESTATE).attr('aria-hidden', true).kendoStop(true, true).kendoAnimate(close);
                    return false;
                }
                item.attr('data-animating', true);
                var isAjaxContent = (item.children('.' + LINK).data(CONTENTURL) || that._contentUrls[itemIndex] || false) && contentHolder.is(EMPTY), showContentElement = function () {
                        oldTab.removeAttr('aria-selected');
                        item.attr('aria-selected', true);
                        that._current(item);
                        that._sizeScrollWrap(contentElement);
                        contentElement.addClass(ACTIVESTATE).removeAttr('aria-hidden').kendoStop(true, true).attr('aria-expanded', true).kendoAnimate(extend({
                            init: function () {
                                that.trigger(SHOW, {
                                    item: item[0],
                                    contentElement: contentHolder[0]
                                });
                                kendo.resize(contentHolder);
                            }
                        }, animation, {
                            complete: function () {
                                item.removeAttr('data-animating');
                                that.trigger(ACTIVATE, {
                                    item: item[0],
                                    contentElement: contentHolder[0]
                                });
                                kendo.resize(contentHolder);
                                that.scrollWrap.css('height', '').css('height');
                                if (isAnimationEnabled && (kendo.support.browser.msie || kendo.support.browser.edge)) {
                                    contentHolder.finish().animate({ opacity: 0.9 }, 'fast', 'linear', function () {
                                        contentHolder.finish().animate({ opacity: 1 }, 'fast', 'linear');
                                    });
                                }
                            }
                        }));
                    }, showContent = function () {
                        if (!isAjaxContent) {
                            showContentElement();
                            that.trigger('change');
                        } else {
                            item.removeAttr('data-animating');
                            that.ajaxRequest(item, contentHolder, function () {
                                item.attr('data-animating', true);
                                showContentElement();
                                that.trigger('change');
                            });
                        }
                        if (that._scrollableModeActive) {
                            that._scrollTabsToItem(item);
                        }
                    };
                visibleContents.removeClass(ACTIVESTATE);
                that.tabGroup.find('.' + TABONTOP).removeClass(TABONTOP);
                item.addClass(TABONTOP).css('z-index');
                if (kendo.size(animation.effects)) {
                    oldTab.kendoAddClass(DEFAULTSTATE, { duration: animation.duration });
                    item.kendoAddClass(ACTIVESTATE, { duration: animation.duration });
                } else {
                    oldTab.addClass(DEFAULTSTATE);
                    item.addClass(ACTIVESTATE);
                }
                visibleContents.attr('aria-hidden', true);
                visibleContents.attr('aria-expanded', false);
                if (visibleContents.length) {
                    visibleContents.kendoStop(true, true).kendoAnimate(extend({ complete: showContent }, close));
                } else {
                    showContent();
                }
                return true;
            },
            contentElement: function (itemIndex) {
                if (isNaN(itemIndex - 0)) {
                    return undefined;
                }
                var contentElements = this.contentElements && this.contentElements[0] && !kendo.kineticScrollNeeded ? this.contentElements : this.contentAnimators;
                var id = $(this.tabGroup.children()[itemIndex]).attr('aria-controls');
                if (contentElements) {
                    for (var i = 0, len = contentElements.length; i < len; i++) {
                        if (contentElements.eq(i).closest('.k-content')[0].id == id) {
                            return contentElements[i];
                        }
                    }
                }
                return undefined;
            },
            contentHolder: function (itemIndex) {
                var contentElement = $(this.contentElement(itemIndex)), scrollContainer = contentElement.children('.km-scroll-container');
                return kendo.support.touch && scrollContainer[0] ? scrollContainer : contentElement;
            },
            ajaxRequest: function (element, content, complete, url) {
                element = this.tabGroup.find(element);
                var that = this, xhr = $.ajaxSettings.xhr, link = element.find('.' + LINK), data = {}, halfWidth = element.width() / 2, fakeProgress = false, statusIcon = element.find('.k-loading').removeClass('k-complete');
                if (!statusIcon[0]) {
                    statusIcon = $('<span class=\'k-loading\'/>').prependTo(element);
                }
                var endState = halfWidth * 2 - statusIcon.width();
                var oldProgressAnimation = function () {
                    statusIcon.animate({ marginLeft: (parseInt(statusIcon.css('marginLeft'), 10) || 0) < halfWidth ? endState : 0 }, 500, oldProgressAnimation);
                };
                if (kendo.support.browser.msie && kendo.support.browser.version < 10) {
                    setTimeout(oldProgressAnimation, 40);
                }
                url = url || link.data(CONTENTURL) || that._contentUrls[element.index()] || link.attr(HREF);
                that.inRequest = true;
                var ajaxOptions = {
                    type: 'GET',
                    cache: false,
                    url: url,
                    dataType: 'html',
                    data: data,
                    xhr: function () {
                        var current = this, request = xhr(), event = current.progressUpload ? 'progressUpload' : current.progress ? 'progress' : false;
                        if (request) {
                            $.each([
                                request,
                                request.upload
                            ], function () {
                                if (this.addEventListener) {
                                    this.addEventListener('progress', function (evt) {
                                        if (event) {
                                            current[event](evt);
                                        }
                                    }, false);
                                }
                            });
                        }
                        current.noProgress = !(window.XMLHttpRequest && 'upload' in new XMLHttpRequest());
                        return request;
                    },
                    progress: function (evt) {
                        if (evt.lengthComputable) {
                            var percent = parseInt(evt.loaded / evt.total * 100, 10) + '%';
                            statusIcon.stop(true).addClass('k-progress').css({
                                'width': percent,
                                'marginLeft': 0
                            });
                        }
                    },
                    error: function (xhr, status) {
                        if (that.trigger('error', {
                                xhr: xhr,
                                status: status
                            })) {
                            this.complete();
                        }
                    },
                    stopProgress: function () {
                        clearInterval(fakeProgress);
                        statusIcon.stop(true).addClass('k-progress')[0].style.cssText = '';
                    },
                    complete: function (xhr) {
                        that.inRequest = false;
                        if (this.noProgress) {
                            setTimeout(this.stopProgress, 500);
                        } else {
                            this.stopProgress();
                        }
                        if (xhr.statusText == 'abort') {
                            statusIcon.remove();
                        }
                    },
                    success: function (data) {
                        statusIcon.addClass('k-complete');
                        try {
                            var current = this, loaded = 10;
                            if (current.noProgress) {
                                statusIcon.width(loaded + '%');
                                fakeProgress = setInterval(function () {
                                    current.progress({
                                        lengthComputable: true,
                                        loaded: Math.min(loaded, 100),
                                        total: 100
                                    });
                                    loaded += 10;
                                }, 40);
                            }
                            that.angular('cleanup', function () {
                                return { elements: content.get() };
                            });
                            kendo.destroy(content);
                            content.html(data);
                        } catch (e) {
                            var console = window.console;
                            if (console && console.error) {
                                console.error(e.name + ': ' + e.message + ' in ' + url);
                            }
                            this.error(this.xhr, 'error');
                        }
                        if (complete) {
                            complete.call(that, content);
                        }
                        that.angular('compile', function () {
                            return { elements: content.get() };
                        });
                        that.trigger(CONTENTLOAD, {
                            item: element[0],
                            contentElement: content[0]
                        });
                    }
                };
                if (typeof url === 'object') {
                    ajaxOptions = $.extend(true, {}, ajaxOptions, url);
                    if (isFunction(ajaxOptions.url)) {
                        ajaxOptions.url = ajaxOptions.url();
                    }
                }
                that.xhr = $.ajax(ajaxOptions);
            }
        });
        extend(TabStrip, {
            renderItem: function (options) {
                options = extend({
                    tabStrip: {},
                    group: {}
                }, options);
                var empty = templates.empty, item = options.item;
                return templates.item(extend(options, {
                    image: item.imageUrl ? templates.image : empty,
                    sprite: item.spriteCssClass ? templates.sprite : empty,
                    itemWrapper: templates.itemWrapper
                }, rendering));
            },
            renderContent: function (options) {
                return templates.content(extend(options, rendering));
            }
        });
        kendo.ui.plugin(TabStrip);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/table-wizard/table-wizard-dialog', [
        'editor/table-wizard/table-wizard-command',
        'kendo.tabstrip'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, numericTextBoxSettings = {
                format: '0',
                min: 0
            }, units = [
                'px',
                'em'
            ], borderStyles = [
                'solid',
                'dotted',
                'dashed',
                'double',
                'groove',
                'ridge',
                'inset',
                'outset',
                'initial',
                'inherit',
                'none',
                'hidden'
            ];
        var tableAlignmentDropDownSettings = {
            dataSource: [
                {
                    className: 'k-icon k-i-table-align-middle-left',
                    value: 'left'
                },
                {
                    className: 'k-icon k-i-table-align-middle-center',
                    value: 'center'
                },
                {
                    className: 'k-icon k-i-table-align-middle-right',
                    value: 'right'
                },
                {
                    className: 'k-icon k-i-align-remove',
                    value: ''
                }
            ],
            dataTextField: 'className',
            dataValueField: 'value',
            template: '<span class=\'#: className #\' title=\'#: tooltip #\'></span>',
            valueTemplate: '<span class=\'k-align-group #: className #\' title=\'#: tooltip #\'></span>'
        };
        var cellAlignmentDropDownSettings = {
            dataSource: [
                {
                    className: 'k-icon k-i-table-align-top-left',
                    value: 'left top'
                },
                {
                    className: 'k-icon k-i-table-align-top-center',
                    value: 'center top'
                },
                {
                    className: 'k-icon k-i-table-align-top-right',
                    value: 'right top'
                },
                {
                    className: 'k-icon k-i-table-align-middle-left',
                    value: 'left middle'
                },
                {
                    className: 'k-icon k-i-table-align-middle-center',
                    value: 'center middle'
                },
                {
                    className: 'k-icon k-i-table-align-middle-right',
                    value: 'right middle'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-left',
                    value: 'left bottom'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-center',
                    value: 'center bottom'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-right',
                    value: 'right bottom'
                },
                {
                    className: 'k-icon k-i-align-remove',
                    value: ''
                }
            ],
            dataTextField: 'className',
            dataValueField: 'value',
            template: '<span class=\'#: className #\' title=\'#: tooltip #\'></span>',
            valueTemplate: '<span class=\'k-align-group #: className #\' title=\'#: tooltip #\'></span>'
        };
        var accessibilityAlignmentDropDownSettings = {
            dataSource: [
                {
                    className: 'k-icon k-i-table-align-top-left',
                    value: 'left top'
                },
                {
                    className: 'k-icon k-i-table-align-top-center',
                    value: 'center top'
                },
                {
                    className: 'k-icon k-i-table-align-top-right',
                    value: 'right top'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-left',
                    value: 'left bottom'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-center',
                    value: 'center bottom'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-right',
                    value: 'right bottom'
                },
                {
                    className: 'k-icon k-i-align-remove',
                    value: ''
                }
            ],
            dataTextField: 'className',
            dataValueField: 'value',
            template: '<span class=\'#: className #\' title=\'#: tooltip #\'></span>',
            valueTemplate: '<span class=\'k-align-group #: className #\' title=\'#: tooltip #\'></span>'
        };
        var dialogTemplate = '<div class="k-editor-dialog k-editor-table-wizard-dialog k-action-window k-popup-edit-form">' + '<div class="k-edit-form-container">' + '<div id="k-table-wizard-tabs" class="k-root-tabs">' + '<ul>' + '<li class="k-state-active">#= messages.tableTab #</li>' + '<li>#= messages.cellTab #</li>' + '<li>#= messages.accessibilityTab #</li>' + '</ul>' + '<div id="k-table-properties">' + '<div class="k-edit-label">' + '<label for="k-editor-table-width">#= messages.width #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-width" />' + '<input id="k-editor-table-width-type" aria-label="#= messages.units #" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-height">#= messages.height #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-height" />' + '<input id="k-editor-table-height-type" aria-label="#= messages.units #" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-columns">#= messages.columns #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-columns" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-rows">#= messages.rows #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-rows" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-cell-spacing">#= messages.cellSpacing #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-cell-spacing" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-cell-padding">#= messages.cellPadding #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-cell-padding" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-alignment">#= messages.alignment #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-table-alignment" class="k-align" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-bg">#= messages.background #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-table-bg" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-css-class">#= messages.cssClass #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-css-class" class="k-textbox" type="text" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-id">#= messages.id #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-id" class="k-textbox" type="text" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-border-width">#= messages.border #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-border-width" />' + '<input id="k-editor-border-color" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-border-style">#= messages.borderStyle #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-border-style" />' + '</div>' + '<div class="k-edit-label">&nbsp;</div>' + '<div class="k-edit-field">' + '<input id="k-editor-collapse-borders" type="checkbox" class="k-checkbox" />' + '<label for="k-editor-collapse-borders" class="k-checkbox-label">#= messages.collapseBorders #</label>' + '</div>' + '</div>' + '<div id="k-cell-properties">' + '<div class="k-edit-field">' + '<input id="k-editor-selectAllCells" type="checkbox" class="k-checkbox" />' + '<label for="k-editor-selectAllCells" class="k-checkbox-label">#= messages.selectAllCells #</label>' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-width">#= messages.width #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-cell-width" />' + '<input id="k-editor-cell-width-type" aria-label="#= messages.units #" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-height">#= messages.height #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-cell-height" />' + '<input id="k-editor-cell-height-type" aria-label="#= messages.units #" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-cell-margin">#= messages.cellMargin #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-cell-margin" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-cells-padding">#= messages.cellPadding #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-cells-padding" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-alignment">#= messages.alignment #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cell-alignment" class="k-align" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-bg">#= messages.background #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cell-bg" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-css-class">#= messages.cssClass #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cell-css-class" class="k-textbox" type="text" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-id">#= messages.id #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cell-id" class="k-textbox" type="text" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-border-width">#= messages.border #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-cell-border-width" />' + '<input id="k-editor-cell-border-color" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-border-style">#= messages.borderStyle #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cell-border-style" />' + '</div>' + '<div class="k-edit-label">&nbsp;</div>' + '<div class="k-edit-field">' + '<input id="k-editor-wrap-text" type="checkbox" class="k-checkbox" />' + '<label for="k-editor-wrap-text" class="k-checkbox-label">#= messages.wrapText #</label>' + '</div>' + '</div>' + '<div id="k-accessibility-properties">' + '<div class="k-edit-label">' + '<label for="k-editor-table-caption">#= messages.caption #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-table-caption" class="k-textbox" type="text" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-accessibility-alignment">#= messages.alignment #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-accessibility-alignment" class="k-align" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-accessibility-summary">#= messages.summary #</label>' + '</div>' + '<div class="k-edit-field">' + '<textarea id="k-editor-accessibility-summary" class="k-textbox"></textarea>' + '</div>' + '<div class="k-edit-label">&nbsp;</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cells-headers" type="checkbox" class="k-checkbox" />' + '<label for="k-editor-cells-headers" class="k-checkbox-label">#= messages.associateCellsWithHeaders #</label>' + '</div>' + '</div>' + '</div>' + '<div class="k-edit-buttons k-state-default">' + '<button class="k-button k-primary k-dialog-ok">#= messages.dialogOk #</button>' + '<button class="k-button k-dialog-close">#= messages.dialogCancel #</button>' + '</div>' + '</div>' + '</div>';
        var TableWizardDialog = kendo.Class.extend({
            init: function (options) {
                this.options = options;
            },
            open: function () {
                var that = this, options = that.options, dialogOptions = options.dialogOptions, tableData = options.table, dialog, messages = options.messages, isIE = kendo.support.browser.msie;
                function close(e) {
                    e.preventDefault();
                    that.destroy();
                    dialog.destroy();
                }
                function okHandler(e) {
                    that.collectDialogValues(tableData);
                    close(e);
                    if (that.change) {
                        that.change();
                    }
                    options.closeCallback(tableData);
                }
                function closeHandler(e) {
                    close(e);
                    options.closeCallback();
                }
                dialogOptions.close = closeHandler;
                dialogOptions.title = messages.tableWizard;
                dialogOptions.visible = options.visible;
                dialog = $(that._dialogTemplate(messages)).appendTo(document.body).kendoWindow(dialogOptions).closest('.k-window').toggleClass('k-rtl', options.isRtl).end().find('.k-dialog-ok').click(okHandler).end().find('.k-dialog-close').click(closeHandler).end().data('kendoWindow');
                var element = dialog.element;
                that._initTabStripComponent(element);
                that._initTableViewComponents(element, tableData);
                that._initCellViewComponents(element, tableData);
                that._initAccessibilityViewComponents(element, tableData);
                dialog.center();
                dialog.open();
                if (isIE) {
                    var dialogHeight = element.closest('.k-window').height();
                    element.css('max-height', dialogHeight);
                }
            },
            _initTabStripComponent: function (element) {
                var components = this.components = {};
                components.tabStrip = element.find('#k-table-wizard-tabs').kendoTabStrip({ animation: false }).data('kendoTabStrip');
            },
            collectDialogValues: function () {
                var that = this;
                var data = that.options.table;
                that._collectTableViewValues(data);
                that._collectCellViewValues(data);
                that._collectAccessibilityViewValues(data);
            },
            _collectTableViewValues: function (tableData) {
                var tableView = this.components.tableView;
                var tableProperties = tableData.tableProperties;
                tableProperties.width = tableView.width.value();
                tableProperties.widthUnit = tableView.widthUnit.value();
                tableProperties.height = tableView.height.value();
                tableProperties.columns = tableView.columns.value();
                tableProperties.rows = tableView.rows.value();
                tableProperties.heightUnit = tableView.heightUnit.value();
                tableProperties.cellSpacing = tableView.cellSpacing.value();
                tableProperties.cellPadding = tableView.cellPadding.value();
                tableProperties.alignment = tableView.alignment.value();
                tableProperties.bgColor = tableView.bgColor.value();
                tableProperties.className = tableView.className.value;
                tableProperties.id = tableView.id.value;
                tableProperties.borderWidth = tableView.borderWidth.value();
                tableProperties.borderColor = tableView.borderColor.value();
                tableProperties.borderStyle = tableView.borderStyle.value();
                tableProperties.collapseBorders = tableView.collapseBorders.checked;
            },
            _collectCellViewValues: function (table) {
                var cellData = table.cellProperties = {};
                var cellView = this.components.cellView;
                cellData.selectAllCells = cellView.selectAllCells.checked;
                cellData.width = cellView.width.value();
                cellData.widthUnit = cellView.widthUnit.value();
                cellData.height = cellView.height.value();
                cellData.heightUnit = cellView.heightUnit.value();
                cellData.cellMargin = cellView.cellMargin.value();
                cellData.cellPadding = cellView.cellPadding.value();
                cellData.alignment = cellView.alignment.value();
                cellData.bgColor = cellView.bgColor.value();
                cellData.className = cellView.className.value;
                cellData.id = cellView.id.value;
                cellData.borderWidth = cellView.borderWidth.value();
                cellData.borderColor = cellView.borderColor.value();
                cellData.borderStyle = cellView.borderStyle.value();
                cellData.wrapText = cellView.wrapText.checked;
                if (!cellData.width) {
                    cellData.selectAllCells = true;
                    cellData.width = 100 / table.tableProperties.columns;
                    cellData.widthUnit = '%';
                }
            },
            _collectAccessibilityViewValues: function (table) {
                var tableProperties = table.tableProperties;
                var accessibilityView = this.components.accessibilityView;
                tableProperties.captionContent = accessibilityView.captionContent.value;
                tableProperties.captionAlignment = accessibilityView.captionAlignment.value();
                tableProperties.summary = accessibilityView.summary.value;
                tableProperties.cellsWithHeaders = accessibilityView.cellsWithHeaders.checked;
            },
            _addUnit: function (units, value) {
                if (value && $.inArray(value, units) == -1) {
                    units.push(value);
                }
            },
            _initTableViewComponents: function (element, table) {
                var components = this.components;
                var tableView = components.tableView = {};
                var tableProperties = table.tableProperties = table.tableProperties || {};
                tableProperties.borderStyle = tableProperties.borderStyle || '';
                this._addUnit(units, tableProperties.widthUnit);
                this._addUnit(units, tableProperties.heightUnit);
                this._initNumericTextbox(element.find('#k-editor-table-width'), 'width', tableProperties, tableView);
                this._initNumericTextbox(element.find('#k-editor-table-height'), 'height', tableProperties, tableView);
                this._initNumericTextbox(element.find('#k-editor-table-columns'), 'columns', tableProperties, tableView, {
                    min: 1,
                    value: 4
                });
                this._initNumericTextbox(element.find('#k-editor-table-rows'), 'rows', tableProperties, tableView, {
                    min: 1,
                    value: 4
                });
                this._initDropDownList(element.find('#k-editor-table-width-type'), 'widthUnit', tableProperties, tableView, units);
                this._initDropDownList(element.find('#k-editor-table-height-type'), 'heightUnit', tableProperties, tableView, units);
                this._initNumericTextbox(element.find('#k-editor-table-cell-spacing'), 'cellSpacing', tableProperties, tableView);
                this._initNumericTextbox(element.find('#k-editor-table-cell-padding'), 'cellPadding', tableProperties, tableView);
                this._initTableAlignmentDropDown(element.find('#k-editor-table-alignment'), tableProperties);
                this._initColorPicker(element.find('#k-editor-table-bg'), 'bgColor', tableProperties, tableView);
                this._initInput(element.find('#k-editor-css-class'), 'className', tableProperties, tableView);
                this._initInput(element.find('#k-editor-id'), 'id', tableProperties, tableView);
                this._initNumericTextbox(element.find('#k-editor-border-width'), 'borderWidth', tableProperties, tableView);
                this._initColorPicker(element.find('#k-editor-border-color'), 'borderColor', tableProperties, tableView);
                this._initDropDownList(element.find('#k-editor-border-style'), 'borderStyle', tableProperties, tableView, borderStyles);
                this._initCheckbox(element.find('#k-editor-collapse-borders'), 'collapseBorders', tableProperties, tableView);
            },
            _initCellViewComponents: function (element, table) {
                var components = this.components;
                var cellView = components.cellView = {};
                table.selectedCells = table.selectedCells = table.selectedCells || [];
                var cellProperties = table.selectedCells[0] || {
                    borderStyle: '',
                    wrapText: true
                };
                this._addUnit(units, cellProperties.widthUnit);
                this._addUnit(units, cellProperties.heightUnit);
                this._initCheckbox(element.find('#k-editor-selectAllCells'), 'selectAllCells', table.tableProperties, cellView);
                this._initNumericTextbox(element.find('#k-editor-cell-width'), 'width', cellProperties, cellView);
                this._initNumericTextbox(element.find('#k-editor-cell-height'), 'height', cellProperties, cellView);
                this._initDropDownList(element.find('#k-editor-cell-width-type'), 'widthUnit', cellProperties, cellView, units);
                this._initDropDownList(element.find('#k-editor-cell-height-type'), 'heightUnit', cellProperties, cellView, units);
                this._initNumericTextbox(element.find('#k-editor-table-cell-margin'), 'cellMargin', cellProperties, cellView);
                this._initNumericTextbox(element.find('#k-editor-table-cells-padding'), 'cellPadding', cellProperties, cellView);
                this._initCellAlignmentDropDown(element.find('#k-editor-cell-alignment'), cellProperties);
                this._initColorPicker(element.find('#k-editor-cell-bg'), 'bgColor', cellProperties, cellView);
                this._initInput(element.find('#k-editor-cell-css-class'), 'className', cellProperties, cellView);
                this._initInput(element.find('#k-editor-cell-id'), 'id', cellProperties, cellView);
                this._initNumericTextbox(element.find('#k-editor-cell-border-width'), 'borderWidth', cellProperties, cellView);
                this._initColorPicker(element.find('#k-editor-cell-border-color'), 'borderColor', cellProperties, cellView);
                this._initDropDownList(element.find('#k-editor-cell-border-style'), 'borderStyle', cellProperties, cellView, borderStyles);
                this._initCheckbox(element.find('#k-editor-wrap-text'), 'wrapText', cellProperties, cellView);
            },
            _initAccessibilityViewComponents: function (element, table) {
                var components = this.components;
                var accessibilityView = components.accessibilityView = {};
                var tableProperties = table.tableProperties;
                this._initInput(element.find('#k-editor-table-caption'), 'captionContent', tableProperties, accessibilityView);
                this._initAccessibilityAlignmentDropDown(element.find('#k-editor-accessibility-alignment'), tableProperties);
                this._initInput(element.find('#k-editor-accessibility-summary'), 'summary', tableProperties, accessibilityView);
                this._initCheckbox(element.find('#k-editor-cells-headers'), 'cellsWithHeaders', tableProperties, accessibilityView);
            },
            _initNumericTextbox: function (element, property, data, storage, settings) {
                var component = storage[property] = element.kendoNumericTextBox(settings ? $.extend({}, numericTextBoxSettings, settings) : numericTextBoxSettings).data('kendoNumericTextBox');
                if (property in data) {
                    component.value(parseInt(data[property], 10));
                }
            },
            _initDropDownList: function (element, property, data, storage, dataSource) {
                var component = storage[property] = element.kendoDropDownList({ dataSource: dataSource }).data('kendoDropDownList');
                this._setComponentValue(component, data, property);
            },
            _initTableAlignmentDropDown: function (element, data) {
                var messages = this.options.messages;
                var tableView = this.components.tableView;
                var dataSource = tableAlignmentDropDownSettings.dataSource;
                dataSource[0].tooltip = messages.alignLeft;
                dataSource[1].tooltip = messages.alignCenter;
                dataSource[2].tooltip = messages.alignRight;
                dataSource[3].tooltip = messages.alignRemove;
                this._initAlignmentDropDown(element, tableAlignmentDropDownSettings, 'alignment', data, tableView);
            },
            _initCellAlignmentDropDown: function (element, data) {
                var messages = this.options.messages;
                var cellView = this.components.cellView;
                var dataSource = cellAlignmentDropDownSettings.dataSource;
                dataSource[0].tooltip = messages.alignLeftTop;
                dataSource[1].tooltip = messages.alignCenterTop;
                dataSource[2].tooltip = messages.alignRightTop;
                dataSource[3].tooltip = messages.alignLeftMiddle;
                dataSource[4].tooltip = messages.alignCenterMiddle;
                dataSource[5].tooltip = messages.alignRightMiddle;
                dataSource[6].tooltip = messages.alignLeftBottom;
                dataSource[7].tooltip = messages.alignCenterBottom;
                dataSource[8].tooltip = messages.alignRightBottom;
                dataSource[9].tooltip = messages.alignRemove;
                this._initAlignmentDropDown(element, cellAlignmentDropDownSettings, 'alignment', data, cellView);
            },
            _initAccessibilityAlignmentDropDown: function (element, data) {
                var messages = this.options.messages;
                var accessibilityView = this.components.accessibilityView;
                var dataSource = accessibilityAlignmentDropDownSettings.dataSource;
                dataSource[0].tooltip = messages.alignLeftTop;
                dataSource[1].tooltip = messages.alignCenterTop;
                dataSource[2].tooltip = messages.alignRightTop;
                dataSource[3].tooltip = messages.alignLeftBottom;
                dataSource[4].tooltip = messages.alignCenterBottom;
                dataSource[5].tooltip = messages.alignRightBottom;
                dataSource[6].tooltip = messages.alignRemove;
                this._initAlignmentDropDown(element, accessibilityAlignmentDropDownSettings, 'captionAlignment', data, accessibilityView);
            },
            _initAlignmentDropDown: function (element, settings, name, data, storage) {
                var component = storage[name] = element.kendoDropDownList(settings).data('kendoDropDownList');
                component.list.addClass('k-align').css('width', '110px');
                this._setComponentValue(component, data, name);
            },
            _setComponentValue: function (component, data, property) {
                if (property in data) {
                    component.value(data[property]);
                }
            },
            _initColorPicker: function (element, property, data, storage) {
                var component = storage[property] = element.kendoColorPicker({
                    buttons: false,
                    clearButton: true
                }).data('kendoColorPicker');
                if (data[property]) {
                    component.value(data[property]);
                }
            },
            _initInput: function (element, property, data, storage) {
                var component = storage[property] = element.get(0);
                if (property in data) {
                    component.value = data[property];
                }
            },
            _initCheckbox: function (element, property, data, storage) {
                var component = storage[property] = element.get(0);
                if (property in data) {
                    component.checked = data[property];
                }
            },
            destroy: function () {
                this._destroyComponents(this.components.tableView);
                this._destroyComponents(this.components.cellView);
                this._destroyComponents(this.components.accessibilityView);
                this._destroyComponents(this.components);
                delete this.components;
            },
            _destroyComponents: function (components) {
                for (var widget in components) {
                    if (components[widget].destroy) {
                        components[widget].destroy();
                    }
                    delete components[widget];
                }
            },
            _dialogTemplate: function (messages) {
                return kendo.template(dialogTemplate)({ messages: messages });
            }
        });
        kendo.ui.editor.TableWizardDialog = TableWizardDialog;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.editor', [
        'kendo.combobox',
        'kendo.dropdownlist',
        'kendo.resizable',
        'kendo.window',
        'kendo.colorpicker',
        'kendo.imagebrowser',
        'kendo.numerictextbox',
        'util/undoredostack',
        'editor/main',
        'editor/dom',
        'editor/serializer',
        'editor/range',
        'editor/command',
        'editor/components',
        'editor/toolbar',
        'editor/immutables',
        'editor/plugins/viewhtml',
        'editor/plugins/link',
        'editor/plugins/lists',
        'editor/plugins/formatting',
        'editor/plugins/image',
        'editor/plugins/import',
        'editor/plugins/insert',
        'editor/plugins/export',
        'editor/plugins/indent',
        'editor/plugins/linebreak',
        'editor/plugins/format',
        'editor/plugins/inlineformat',
        'editor/plugins/formatblock',
        'editor/plugins/file',
        'editor/plugins/tables',
        'editor/plugins/clipboard',
        'editor/plugins/keyboard',
        'editor/plugins/exportpdf',
        'editor/plugins/print',
        'editor/resizing/column-resizing',
        'editor/resizing/row-resizing',
        'editor/resizing/table-resizing',
        'editor/resizing/table-resize-handle',
        'editor/table-wizard/table-wizard-command',
        'editor/table-wizard/table-wizard-dialog'
    ], f);
}(function () {
    var __meta__ = {
        id: 'editor',
        name: 'Editor',
        category: 'web',
        description: 'Rich text editor component',
        depends: [
            'combobox',
            'dropdownlist',
            'window',
            'colorpicker'
        ],
        features: [
            {
                id: 'editor-imagebrowser',
                name: 'Image Browser',
                description: 'Support for uploading and inserting images',
                depends: ['imagebrowser']
            },
            {
                id: 'editor-resizable',
                name: 'Resize handle',
                description: 'Support for resizing the content area via a resize handle',
                depends: ['resizable']
            },
            {
                id: 'editor-tablewizard',
                name: 'Table wizard dialog',
                description: 'Support for table properties configuration',
                depends: [
                    'tabstrip',
                    'button',
                    'numerictextbox'
                ]
            },
            {
                id: 'editor-pdf-export',
                name: 'PDF export',
                description: 'Export Editor content as PDF',
                depends: [
                    'pdf',
                    'drawing'
                ]
            }
        ]
    };
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.maskedtextbox', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'maskedtextbox',
        name: 'MaskedTextBox',
        category: 'web',
        description: 'The MaskedTextBox widget allows to specify a mask type on an input field.',
        depends: ['core']
    };
    (function ($, undefined) {
        var global = window;
        var min = global.Math.min;
        var kendo = global.kendo;
        var caret = kendo.caret;
        var keys = kendo.keys;
        var ui = kendo.ui;
        var Widget = ui.Widget;
        var NS = '.kendoMaskedTextBox';
        var proxy = $.proxy;
        var setTimeout = window.setTimeout;
        var STATEDISABLED = 'k-state-disabled';
        var STATEINVALID = 'k-state-invalid';
        var DISABLED = 'disabled';
        var READONLY = 'readonly';
        var CHANGE = 'change';
        var MOUSEUP = 'mouseup';
        var DROP = 'drop';
        var KEYDOWN = 'keydown';
        var PASTE = 'paste';
        var INPUT = 'input';
        function ns(name) {
            return name + NS;
        }
        var INPUT_EVENT_NAME = ns(kendo.support.propertyChangeEvent ? 'propertychange' : INPUT);
        function stringDiffStart(str1, str2) {
            var i = 0;
            while (i < str2.length) {
                if (str1[i] !== str2[i]) {
                    break;
                }
                i++;
            }
            return i;
        }
        var MaskedTextBox = Widget.extend({
            init: function (element, options) {
                var that = this;
                var DOMElement;
                Widget.fn.init.call(that, element, options);
                that._rules = $.extend({}, that.rules, that.options.rules);
                element = that.element;
                DOMElement = element[0];
                that._wrapper();
                that._tokenize();
                that._form();
                that.element.addClass('k-textbox').attr('autocomplete', 'off').on('focus' + NS, function () {
                    var value = DOMElement.value;
                    if (!value) {
                        DOMElement.value = that._old = that._emptyMask;
                    } else {
                        that._togglePrompt(true);
                    }
                    that._oldValue = value;
                    that._timeoutId = setTimeout(function () {
                        caret(element, 0, value ? that._maskLength : 0);
                    });
                }).on('focusout' + NS, function () {
                    var value = element.val();
                    clearTimeout(that._timeoutId);
                    DOMElement.value = that._old = '';
                    if (value !== that._emptyMask) {
                        DOMElement.value = that._old = value;
                    }
                    that._change();
                    that._togglePrompt();
                });
                var disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                that.value(that.options.value || element.val());
                that._validationIcon = $('<span class=\'k-icon k-i-warning\'></span>').insertAfter(element);
                kendo.notify(that);
            },
            options: {
                name: 'MaskedTextBox',
                clearPromptChar: false,
                unmaskOnPost: false,
                promptChar: '_',
                culture: '',
                rules: {},
                value: '',
                mask: ''
            },
            events: [CHANGE],
            rules: {
                '0': /\d/,
                '9': /\d|\s/,
                '#': /\d|\s|\+|\-/,
                'L': /[a-zA-Z]/,
                '?': /[a-zA-Z]|\s/,
                '&': /\S/,
                'C': /./,
                'A': /[a-zA-Z0-9]/,
                'a': /[a-zA-Z0-9]|\s/
            },
            setOptions: function (options) {
                var that = this;
                Widget.fn.setOptions.call(that, options);
                that._rules = $.extend({}, that.rules, that.options.rules);
                that._tokenize();
                this._unbindInput();
                this._bindInput();
                that.value(that.element.val());
            },
            destroy: function () {
                var that = this;
                that.element.off(NS);
                if (that._formElement) {
                    that._formElement.off('reset', that._resetHandler);
                    that._formElement.off('submit', that._submitHandler);
                }
                Widget.fn.destroy.call(that);
            },
            raw: function () {
                var unmasked = this._unmask(this.element.val(), 0);
                return unmasked.replace(new RegExp(escapeRegExp(this.options.promptChar), 'g'), '');
            },
            value: function (value) {
                var element = this.element;
                var emptyMask = this._emptyMask;
                if (value === undefined) {
                    return this.element.val();
                }
                if (value === null) {
                    value = '';
                }
                if (!emptyMask) {
                    this._oldValue = value;
                    element.val(value);
                    return;
                }
                value = this._unmask(value + '');
                element.val(value ? emptyMask : '');
                this._mask(0, this._maskLength, value);
                this._unmaskedValue = null;
                value = element.val();
                this._oldValue = value;
                if (kendo._activeElement() !== element) {
                    if (value === emptyMask) {
                        element.val('');
                    } else {
                        this._togglePrompt();
                    }
                }
            },
            _togglePrompt: function (show) {
                var DOMElement = this.element[0];
                var value = DOMElement.value;
                if (this.options.clearPromptChar) {
                    if (!show) {
                        value = value.replace(new RegExp(escapeRegExp(this.options.promptChar), 'g'), ' ');
                    } else {
                        value = this._oldValue;
                    }
                    DOMElement.value = this._old = value;
                }
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            _bindInput: function () {
                var that = this;
                if (that._maskLength) {
                    if (that.options.$angular) {
                        that.element.off(INPUT);
                    }
                    that.element.on(ns(KEYDOWN), proxy(that._keydown, that)).on(ns(DROP), proxy(that._drop, that)).on(ns(CHANGE), proxy(that._trackChange, that)).on(INPUT_EVENT_NAME, proxy(that._inputHandler, that));
                    if (kendo.support.browser.msie) {
                        var version = kendo.support.browser.version;
                        if (version > 8 && version < 11) {
                            var events = [
                                ns(MOUSEUP),
                                ns(DROP),
                                ns(KEYDOWN),
                                ns(PASTE)
                            ].join(' ');
                            that.element.on(events, proxy(that._legacyIEInputHandler, that));
                        }
                    }
                }
            },
            _unbindInput: function () {
                var events = [
                    INPUT_EVENT_NAME,
                    ns(KEYDOWN),
                    ns(MOUSEUP),
                    ns(DROP),
                    ns(PASTE)
                ].join(' ');
                this.element.off(events);
            },
            _editable: function (options) {
                var that = this;
                var element = that.element;
                var wrapper = that.wrapper;
                var disable = options.disable;
                var readonly = options.readonly;
                that._unbindInput();
                if (!readonly && !disable) {
                    element.removeAttr(DISABLED).removeAttr(READONLY);
                    wrapper.removeClass(STATEDISABLED);
                    that._bindInput();
                } else {
                    element.attr(DISABLED, disable).attr(READONLY, readonly);
                    wrapper.toggleClass(STATEDISABLED, disable);
                }
            },
            _change: function () {
                var that = this;
                var value = that.value();
                if (value !== that._oldValue) {
                    that._oldValue = value;
                    that.trigger(CHANGE);
                    that.element.trigger(CHANGE);
                } else if (value === '' && that.__changing) {
                    that.element.trigger(CHANGE);
                }
            },
            inputChange: function (backward) {
                var that = this;
                var old = that._old;
                var element = that.element[0];
                var value = element.value;
                var selection = caret(element);
                var cursor = selection[1];
                var lengthDiff = value.length - old.length;
                var mobile = kendo.support.mobileOS;
                if (that.__dropping && lengthDiff < 0) {
                    return;
                }
                if (lengthDiff === -1 && mobile.android && mobile.browser === 'chrome') {
                    backward = true;
                }
                var contentStart = min(cursor, stringDiffStart(value, old));
                var content = value.substring(contentStart, cursor);
                element.value = value.substring(0, contentStart) + that._emptyMask.substring(contentStart);
                var caretPos = that._mask(contentStart, cursor, content);
                var endContent = that._trimStartPromptChars(value.substring(cursor), min(lengthDiff, caretPos - contentStart));
                var unmasked = that._unmask(endContent, old.length - endContent.length);
                that._mask(caretPos, caretPos, unmasked);
                if (backward) {
                    caretPos = that._findCaretPosBackwards(contentStart);
                }
                caret(element, caretPos);
                that.__dropping = false;
            },
            _trimStartPromptChars: function (content, count) {
                var promptChar = this.options.promptChar;
                while (count-- > 0 && content.indexOf(promptChar) === 0) {
                    content = content.substring(1);
                }
                return content;
            },
            _findCaretPosBackwards: function (pos) {
                var caretStart = this._find(pos, true);
                if (caretStart < pos) {
                    caretStart += 1;
                }
                return caretStart;
            },
            _inputHandler: function () {
                if (kendo._activeElement() !== this.element[0]) {
                    return;
                }
                this.inputChange(this.__backward);
            },
            _legacyIEInputHandler: function (e) {
                var that = this;
                var input = that.element[0];
                var value = input.value;
                var type = e.type;
                that.__pasting = type === 'paste';
                setTimeout(function () {
                    if (type === 'mouseup' && that.__pasting) {
                        return;
                    }
                    if (input.value && input.value !== value) {
                        that.inputChange(that.__backward);
                    }
                });
            },
            _trackChange: function () {
                var that = this;
                that.__changing = true;
                setTimeout(function () {
                    that.__changing = false;
                });
            },
            _form: function () {
                var that = this;
                var element = that.element;
                var formId = element.attr('form');
                var form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(element[0].value);
                        });
                    };
                    that._submitHandler = function () {
                        that.element[0].value = that._old = that.raw();
                    };
                    if (that.options.unmaskOnPost) {
                        form.on('submit', that._submitHandler);
                    }
                    that._formElement = form.on('reset', that._resetHandler);
                }
            },
            _keydown: function (e) {
                var key = e.keyCode;
                this.__backward = key === keys.BACKSPACE;
                if (key === keys.ENTER) {
                    this._change();
                }
            },
            _drop: function () {
                this.__dropping = true;
            },
            _find: function (idx, backward) {
                var value = this.element.val() || this._emptyMask;
                var step = 1;
                if (backward === true) {
                    step = -1;
                }
                while (idx > -1 || idx <= this._maskLength) {
                    if (value.charAt(idx) !== this.tokens[idx]) {
                        return idx;
                    }
                    idx += step;
                }
                return -1;
            },
            _mask: function (start, end, value, backward) {
                var element = this.element[0];
                var current = element.value || this._emptyMask;
                var empty = this.options.promptChar;
                var valueLength;
                var chrIdx = 0;
                var unmasked;
                var chr;
                var idx;
                start = this._find(start, backward);
                if (start > end) {
                    end = start;
                }
                unmasked = this._unmask(current.substring(end), end);
                value = this._unmask(value, start);
                valueLength = value.length;
                if (value) {
                    unmasked = unmasked.replace(new RegExp('^_{0,' + valueLength + '}'), '');
                }
                value += unmasked;
                current = current.split('');
                chr = value.charAt(chrIdx);
                while (start < this._maskLength) {
                    current[start] = chr || empty;
                    chr = value.charAt(++chrIdx);
                    if (idx === undefined && chrIdx > valueLength) {
                        idx = start;
                    }
                    start = this._find(start + 1);
                }
                element.value = this._old = current.join('');
                if (kendo._activeElement() === element) {
                    if (idx === undefined) {
                        idx = this._maskLength;
                    }
                    caret(element, idx);
                }
                return idx;
            },
            _unmask: function (value, idx) {
                if (!value) {
                    return '';
                }
                if (this._unmaskedValue === value) {
                    return this._unmaskedValue;
                }
                value = (value + '').split('');
                var chr;
                var token;
                var chrIdx = 0;
                var tokenIdx = idx || 0;
                var empty = this.options.promptChar;
                var valueLength = value.length;
                var tokensLength = this.tokens.length;
                var result = '';
                while (tokenIdx < tokensLength) {
                    chr = value[chrIdx];
                    token = this.tokens[tokenIdx];
                    if (chr === token || chr === empty) {
                        result += chr === empty ? empty : '';
                        chrIdx += 1;
                        tokenIdx += 1;
                    } else if (typeof token !== 'string') {
                        if (token && token.test && token.test(chr) || $.isFunction(token) && token(chr)) {
                            result += chr;
                            tokenIdx += 1;
                        } else {
                            if (valueLength === 1) {
                                this._blinkInvalidState();
                            }
                        }
                        chrIdx += 1;
                    } else {
                        tokenIdx += 1;
                    }
                    if (chrIdx >= valueLength) {
                        break;
                    }
                }
                this._unmaskedValue = result;
                return result;
            },
            _wrapper: function () {
                var that = this;
                var element = that.element;
                var DOMElement = element[0];
                var wrapper = element.wrap('<span class=\'k-widget k-maskedtextbox\'></span>').parent();
                wrapper[0].style.cssText = DOMElement.style.cssText;
                DOMElement.style.width = '100%';
                that.wrapper = wrapper.addClass(DOMElement.className);
            },
            _blinkInvalidState: function () {
                var that = this;
                that.wrapper.addClass(STATEINVALID);
                clearTimeout(that._invalidStateTimeout);
                that._invalidStateTimeout = setTimeout(proxy(that._removeInvalidState, that), 100);
            },
            _removeInvalidState: function () {
                var that = this;
                that.wrapper.removeClass(STATEINVALID);
                that._invalidStateTimeout = null;
            },
            _tokenize: function () {
                var tokens = [];
                var tokenIdx = 0;
                var mask = this.options.mask || '';
                var maskChars = mask.split('');
                var length = maskChars.length;
                var idx = 0;
                var chr;
                var rule;
                var emptyMask = '';
                var promptChar = this.options.promptChar;
                var numberFormat = kendo.getCulture(this.options.culture).numberFormat;
                var rules = this._rules;
                for (; idx < length; idx++) {
                    chr = maskChars[idx];
                    rule = rules[chr];
                    if (rule) {
                        tokens[tokenIdx] = rule;
                        emptyMask += promptChar;
                        tokenIdx += 1;
                    } else {
                        if (chr === '.' || chr === ',') {
                            chr = numberFormat[chr];
                        } else if (chr === '$') {
                            chr = numberFormat.currency.symbol;
                        } else if (chr === '\\') {
                            idx += 1;
                            chr = maskChars[idx];
                        }
                        chr = chr.split('');
                        for (var i = 0, l = chr.length; i < l; i++) {
                            tokens[tokenIdx] = chr[i];
                            emptyMask += chr[i];
                            tokenIdx += 1;
                        }
                    }
                }
                this.tokens = tokens;
                this._emptyMask = emptyMask;
                this._maskLength = emptyMask.length;
            }
        });
        function escapeRegExp(text) {
            return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
        }
        ui.plugin(MaskedTextBox);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.toolbar', [
        'kendo.core',
        'kendo.userevents',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'toolbar',
        name: 'ToolBar',
        category: 'web',
        description: 'The ToolBar widget displays one or more command buttons divided into groups.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Class = kendo.Class, Widget = kendo.ui.Widget, proxy = $.proxy, isFunction = kendo.isFunction, keys = kendo.keys, outerWidth = kendo._outerWidth, TOOLBAR = 'k-toolbar', BUTTON = 'k-button', OVERFLOW_BUTTON = 'k-overflow-button', TOGGLE_BUTTON = 'k-toggle-button', BUTTON_GROUP = 'k-button-group', SPLIT_BUTTON = 'k-split-button', SEPARATOR = 'k-separator', SPACER_CLASS = 'k-spacer', SPACER = 'spacer', POPUP = 'k-popup', RESIZABLE_TOOLBAR = 'k-toolbar-resizable', STATE_ACTIVE = 'k-state-active', STATE_DISABLED = 'k-state-disabled', STATE_HIDDEN = 'k-state-hidden', GROUP_START = 'k-group-start', GROUP_END = 'k-group-end', PRIMARY = 'k-primary', ICON = 'k-icon', ICON_PREFIX = 'k-i-', BUTTON_ICON = 'k-button-icon', BUTTON_ICON_TEXT = 'k-button-icontext', LIST_CONTAINER = 'k-list-container k-split-container', SPLIT_BUTTON_ARROW = 'k-split-button-arrow', OVERFLOW_ANCHOR = 'k-overflow-anchor', OVERFLOW_CONTAINER = 'k-overflow-container', FIRST_TOOLBAR_VISIBLE = 'k-toolbar-first-visible', LAST_TOOLBAR_VISIBLE = 'k-toolbar-last-visible', CLICK = 'click', TOGGLE = 'toggle', OPEN = 'open', CLOSE = 'close', OVERFLOW_OPEN = 'overflowOpen', OVERFLOW_CLOSE = 'overflowClose', OVERFLOW_NEVER = 'never', OVERFLOW_AUTO = 'auto', OVERFLOW_ALWAYS = 'always', OVERFLOW_HIDDEN = 'k-overflow-hidden', OPTION_LIST_SUFFIX = '_optionlist', KENDO_UID_ATTR = kendo.attr('uid');
        kendo.toolbar = {};
        var components = {
            overflowAnchor: '<div tabindex="0" class="k-overflow-anchor k-button"></div>',
            overflowContainer: '<ul class="k-overflow-container k-list-container"></ul>'
        };
        kendo.toolbar.registerComponent = function (name, toolbar, overflow) {
            components[name] = {
                toolbar: toolbar,
                overflow: overflow
            };
        };
        var Item = kendo.Class.extend({
            addOverflowAttr: function () {
                this.element.attr(kendo.attr('overflow'), this.options.overflow || OVERFLOW_AUTO);
            },
            addUidAttr: function () {
                this.element.attr(KENDO_UID_ATTR, this.options.uid);
            },
            addIdAttr: function () {
                if (this.options.id) {
                    this.element.attr('id', this.options.id);
                }
            },
            addOverflowIdAttr: function () {
                if (this.options.id) {
                    this.element.attr('id', this.options.id + '_overflow');
                }
            },
            attributes: function () {
                if (this.options.attributes) {
                    this.element.attr(this.options.attributes);
                }
            },
            show: function () {
                this.element.removeClass(STATE_HIDDEN).show();
                this.options.hidden = false;
            },
            hide: function () {
                this.element.addClass(STATE_HIDDEN).hide();
                if (this.overflow && this.overflowHidden) {
                    this.overflowHidden();
                }
                this.options.hidden = true;
            },
            remove: function () {
                this.element.remove();
            },
            enable: function (isEnabled) {
                if (isEnabled === undefined) {
                    isEnabled = true;
                }
                this.element.toggleClass(STATE_DISABLED, !isEnabled);
                this.options.enable = isEnabled;
            },
            twin: function () {
                var uid = this.element.attr(KENDO_UID_ATTR);
                if (this.overflow && this.options.splitContainerId) {
                    return $('#' + this.options.splitContainerId).find('[' + KENDO_UID_ATTR + '=\'' + uid + '\']').data(this.options.type);
                } else if (this.overflow) {
                    return this.toolbar.element.find('[' + KENDO_UID_ATTR + '=\'' + uid + '\']').data(this.options.type);
                } else if (this.toolbar.options.resizable) {
                    return this.toolbar.popup.element.find('[' + KENDO_UID_ATTR + '=\'' + uid + '\']').data(this.options.type);
                }
            }
        });
        kendo.toolbar.Item = Item;
        var Button = Item.extend({
            init: function (options, toolbar) {
                var element = options.useButtonTag ? $('<button tabindex="0"></button>') : $('<a href tabindex="0"></a>');
                this.element = element;
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                if (options.primary) {
                    element.addClass(PRIMARY);
                }
                if (options.togglable) {
                    element.addClass(TOGGLE_BUTTON);
                    this.toggle(options.selected);
                }
                if (options.url !== undefined && !options.useButtonTag) {
                    element.attr('href', options.url);
                    if (options.mobile) {
                        element.attr(kendo.attr('role'), 'button');
                    }
                }
                if (options.group) {
                    element.attr(kendo.attr('group'), options.group);
                    this.group = this.toolbar.addToGroup(this, options.group);
                }
                if (!options.togglable && options.click && isFunction(options.click)) {
                    this.clickHandler = options.click;
                }
                if (options.togglable && options.toggle && isFunction(options.toggle)) {
                    this.toggleHandler = options.toggle;
                }
            },
            toggle: function (state, propagate) {
                state = !!state;
                if (this.group && state) {
                    this.group.select(this);
                } else if (!this.group) {
                    this.select(state);
                }
                if (propagate && this.twin()) {
                    this.twin().toggle(state);
                }
            },
            getParentGroup: function () {
                if (this.options.isChild) {
                    return this.element.closest('.' + BUTTON_GROUP).data('buttonGroup');
                }
            },
            _addGraphics: function () {
                var element = this.element, icon = this.options.icon, spriteCssClass = this.options.spriteCssClass, imageUrl = this.options.imageUrl, isEmpty, span, img;
                if (spriteCssClass || imageUrl || icon) {
                    isEmpty = true;
                    element.contents().filter(function () {
                        return !$(this).hasClass('k-sprite') && !$(this).hasClass(ICON) && !$(this).hasClass('k-image');
                    }).each(function (idx, el) {
                        if (el.nodeType == 1 || el.nodeType == 3 && $.trim(el.nodeValue).length > 0) {
                            isEmpty = false;
                        }
                    });
                    if (isEmpty) {
                        element.addClass(BUTTON_ICON);
                    } else {
                        element.addClass(BUTTON_ICON_TEXT);
                    }
                }
                if (icon) {
                    span = element.children('span.' + ICON).first();
                    if (!span[0]) {
                        span = $('<span class="' + ICON + '"></span>').prependTo(element);
                    }
                    span.addClass(ICON_PREFIX + icon);
                } else if (spriteCssClass) {
                    span = element.children('span.k-sprite').first();
                    if (!span[0]) {
                        span = $('<span class="k-sprite ' + ICON + '"></span>').prependTo(element);
                    }
                    span.addClass(spriteCssClass);
                } else if (imageUrl) {
                    img = element.children('img.k-image').first();
                    if (!img[0]) {
                        img = $('<img alt="icon" class="k-image" />').prependTo(element);
                    }
                    img.attr('src', imageUrl);
                }
            }
        });
        kendo.toolbar.Button = Button;
        var ToolBarButton = Button.extend({
            init: function (options, toolbar) {
                Button.fn.init.call(this, options, toolbar);
                var element = this.element;
                element.addClass(BUTTON);
                this.addIdAttr();
                if (options.align) {
                    element.addClass('k-align-' + options.align);
                }
                if (options.showText != 'overflow' && options.text) {
                    if (options.mobile) {
                        element.html('<span class="km-text">' + options.text + '</span>');
                    } else {
                        element.html(options.text);
                    }
                }
                options.hasIcon = options.showIcon != 'overflow' && (options.icon || options.spriteCssClass || options.imageUrl);
                if (options.hasIcon) {
                    this._addGraphics();
                }
                this.addUidAttr();
                this.addOverflowAttr();
                this.enable(options.enable);
                if (options.hidden) {
                    this.hide();
                }
                this.element.data({
                    type: 'button',
                    button: this
                });
            },
            select: function (selected) {
                if (selected === undefined) {
                    selected = false;
                }
                this.element.toggleClass(STATE_ACTIVE, selected);
                this.options.selected = selected;
            }
        });
        kendo.toolbar.ToolBarButton = ToolBarButton;
        var OverflowButton = Button.extend({
            init: function (options, toolbar) {
                this.overflow = true;
                Button.fn.init.call(this, $.extend({}, options), toolbar);
                var element = this.element;
                if (options.showText != 'toolbar' && options.text) {
                    if (options.mobile) {
                        element.html('<span class="km-text">' + options.text + '</span>');
                    } else {
                        element.html('<span class="k-text">' + options.text + '</span>');
                    }
                }
                options.hasIcon = options.showIcon != 'toolbar' && (options.icon || options.spriteCssClass || options.imageUrl);
                if (options.hasIcon) {
                    this._addGraphics();
                }
                if (!options.isChild) {
                    this._wrap();
                }
                this.addOverflowIdAttr();
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                this.enable(options.enable);
                element.addClass(OVERFLOW_BUTTON + ' ' + BUTTON);
                if (options.hidden) {
                    this.hide();
                }
                if (options.togglable) {
                    this.toggle(options.selected);
                }
                this.element.data({
                    type: 'button',
                    button: this
                });
            },
            _wrap: function () {
                this.element = this.element.wrap('<li></li>').parent();
            },
            overflowHidden: function () {
                this.element.addClass(OVERFLOW_HIDDEN);
            },
            select: function (selected) {
                if (selected === undefined) {
                    selected = false;
                }
                if (this.options.isChild) {
                    this.element.toggleClass(STATE_ACTIVE, selected);
                } else {
                    this.element.find('.k-button').toggleClass(STATE_ACTIVE, selected);
                }
                this.options.selected = selected;
            }
        });
        kendo.toolbar.OverflowButton = OverflowButton;
        kendo.toolbar.registerComponent('button', ToolBarButton, OverflowButton);
        var ButtonGroup = Item.extend({
            createButtons: function (buttonConstructor) {
                var options = this.options;
                var items = options.buttons || [];
                var item;
                for (var i = 0; i < items.length; i++) {
                    if (!items[i].uid) {
                        items[i].uid = kendo.guid();
                    }
                    item = new buttonConstructor($.extend({
                        mobile: options.mobile,
                        isChild: true,
                        type: 'button'
                    }, items[i]), this.toolbar);
                    item.element.appendTo(this.element);
                }
            },
            refresh: function () {
                this.element.children().filter(':not(\'.' + STATE_HIDDEN + '\'):first').addClass(GROUP_START);
                this.element.children().filter(':not(\'.' + STATE_HIDDEN + '\'):last').addClass(GROUP_END);
            }
        });
        kendo.toolbar.ButtonGroup = ButtonGroup;
        var ToolBarButtonGroup = ButtonGroup.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<div></div>');
                this.options = options;
                this.toolbar = toolbar;
                this.addIdAttr();
                if (options.align) {
                    element.addClass('k-align-' + options.align);
                }
                this.createButtons(ToolBarButton);
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                this.refresh();
                element.addClass(BUTTON_GROUP);
                this.element.data({
                    type: 'buttonGroup',
                    buttonGroup: this
                });
            }
        });
        kendo.toolbar.ToolBarButtonGroup = ToolBarButtonGroup;
        var OverflowButtonGroup = ButtonGroup.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<li></li>');
                this.options = options;
                this.toolbar = toolbar;
                this.overflow = true;
                this.addOverflowIdAttr();
                this.createButtons(OverflowButton);
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                this.refresh();
                element.addClass((options.mobile ? '' : BUTTON_GROUP) + ' k-overflow-group');
                this.element.data({
                    type: 'buttonGroup',
                    buttonGroup: this
                });
            },
            overflowHidden: function () {
                this.element.addClass(OVERFLOW_HIDDEN);
            }
        });
        kendo.toolbar.OverflowButtonGroup = OverflowButtonGroup;
        kendo.toolbar.registerComponent('buttonGroup', ToolBarButtonGroup, OverflowButtonGroup);
        var ToolBarSplitButton = Item.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<div class="' + SPLIT_BUTTON + '" tabindex="0"></div>');
                this.options = options;
                this.toolbar = toolbar;
                this.mainButton = new ToolBarButton($.extend({}, options, { hidden: false }), toolbar);
                this.arrowButton = $('<a class="' + BUTTON + ' ' + SPLIT_BUTTON_ARROW + '"><span class="' + (options.mobile ? 'km-icon km-arrowdown' : 'k-icon k-i-arrow-60-down') + '"></span></a>');
                this.popupElement = $('<ul class="' + LIST_CONTAINER + '"></ul>');
                this.mainButton.element.removeAttr('href tabindex').appendTo(element);
                this.arrowButton.appendTo(element);
                this.popupElement.appendTo(element);
                if (options.align) {
                    element.addClass('k-align-' + options.align);
                }
                if (!options.id) {
                    options.id = options.uid;
                }
                element.attr('id', options.id + '_wrapper');
                this.addOverflowAttr();
                this.addUidAttr();
                this.createMenuButtons();
                this.createPopup();
                this._navigatable();
                this.mainButton.main = true;
                this.enable(options.enable);
                if (options.hidden) {
                    this.hide();
                }
                element.data({
                    type: 'splitButton',
                    splitButton: this,
                    kendoPopup: this.popup
                });
            },
            _navigatable: function () {
                var that = this;
                that.popupElement.on('keydown', '.' + BUTTON, function (e) {
                    var li = $(e.target).parent();
                    e.preventDefault();
                    if (e.keyCode === keys.ESC || e.keyCode === keys.TAB || e.altKey && e.keyCode === keys.UP) {
                        that.toggle();
                        that.focus();
                    } else if (e.keyCode === keys.DOWN) {
                        findFocusableSibling(li, 'next').focus();
                    } else if (e.keyCode === keys.UP) {
                        findFocusableSibling(li, 'prev').focus();
                    } else if (e.keyCode === keys.SPACEBAR || e.keyCode === keys.ENTER) {
                        that.toolbar.userEvents.trigger('tap', { target: $(e.target) });
                    } else if (e.keyCode === keys.HOME) {
                        li.parent().find(':kendoFocusable').first().focus();
                    } else if (e.keyCode === keys.END) {
                        li.parent().find(':kendoFocusable').last().focus();
                    }
                });
            },
            createMenuButtons: function () {
                var options = this.options;
                var items = options.menuButtons;
                var item;
                for (var i = 0; i < items.length; i++) {
                    item = new ToolBarButton($.extend({
                        mobile: options.mobile,
                        type: 'button',
                        click: options.click
                    }, items[i]), this.toolbar);
                    item.element.wrap('<li></li>').parent().appendTo(this.popupElement);
                }
            },
            createPopup: function () {
                var that = this;
                var options = this.options;
                var element = this.element;
                this.popupElement.attr('id', options.id + OPTION_LIST_SUFFIX).attr(KENDO_UID_ATTR, options.rootUid);
                if (options.mobile) {
                    this.popupElement = actionSheetWrap(this.popupElement);
                }
                this.popup = this.popupElement.kendoPopup({
                    appendTo: options.mobile ? $(options.mobile).children('.km-pane') : null,
                    anchor: element,
                    isRtl: this.toolbar._isRtl,
                    copyAnchorStyles: false,
                    animation: options.animation,
                    open: function (e) {
                        var isDefaultPrevented = that.toolbar.trigger(OPEN, { target: element });
                        if (isDefaultPrevented) {
                            e.preventDefault();
                            return;
                        }
                        that.adjustPopupWidth(e.sender);
                    },
                    activate: function () {
                        this.element.find(':kendoFocusable').first().focus();
                    },
                    close: function (e) {
                        var isDefaultPrevented = that.toolbar.trigger(CLOSE, { target: element });
                        if (isDefaultPrevented) {
                            e.preventDefault();
                        }
                        element.focus();
                    }
                }).data('kendoPopup');
                this.popup.element.on(CLICK, 'a.k-button', preventClick);
            },
            adjustPopupWidth: function (popup) {
                var anchor = popup.options.anchor, computedWidth = outerWidth(anchor), width;
                kendo.wrap(popup.element).addClass('k-split-wrapper');
                if (popup.element.css('box-sizing') !== 'border-box') {
                    width = computedWidth - (outerWidth(popup.element) - popup.element.width());
                } else {
                    width = computedWidth;
                }
                popup.element.css({
                    fontFamily: anchor.css('font-family'),
                    'min-width': width
                });
            },
            remove: function () {
                this.popup.element.off(CLICK, 'a.k-button');
                this.popup.destroy();
                this.element.remove();
            },
            toggle: function () {
                if (this.options.enable || this.popup.visible()) {
                    this.popup.toggle();
                }
            },
            enable: function (isEnabled) {
                if (isEnabled === undefined) {
                    isEnabled = true;
                }
                this.mainButton.enable(isEnabled);
                this.element.toggleClass(STATE_DISABLED, !isEnabled);
                this.options.enable = isEnabled;
            },
            focus: function () {
                this.element.focus();
            },
            hide: function () {
                if (this.popup) {
                    this.popup.close();
                }
                this.element.addClass(STATE_HIDDEN).hide();
                this.options.hidden = true;
            },
            show: function () {
                this.element.removeClass(STATE_HIDDEN).hide();
                this.options.hidden = false;
            }
        });
        kendo.toolbar.ToolBarSplitButton = ToolBarSplitButton;
        var OverflowSplitButton = Item.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<li class="' + SPLIT_BUTTON + '"></li>'), items = options.menuButtons, item, splitContainerId;
                this.options = options;
                this.toolbar = toolbar;
                this.overflow = true;
                splitContainerId = (options.id || options.uid) + OPTION_LIST_SUFFIX;
                this.mainButton = new OverflowButton($.extend({}, options));
                this.mainButton.element.appendTo(element);
                for (var i = 0; i < items.length; i++) {
                    item = new OverflowButton($.extend({
                        mobile: options.mobile,
                        type: 'button',
                        splitContainerId: splitContainerId
                    }, items[i]), this.toolbar);
                    item.element.appendTo(element);
                }
                this.addUidAttr();
                this.addOverflowAttr();
                this.mainButton.main = true;
                element.data({
                    type: 'splitButton',
                    splitButton: this
                });
            },
            overflowHidden: function () {
                this.element.addClass(OVERFLOW_HIDDEN);
            }
        });
        kendo.toolbar.OverflowSplitButton = OverflowSplitButton;
        kendo.toolbar.registerComponent('splitButton', ToolBarSplitButton, OverflowSplitButton);
        var ToolBarSeparator = Item.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<div>&nbsp;</div>');
                this.element = element;
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                this.addIdAttr();
                this.addUidAttr();
                this.addOverflowAttr();
                element.addClass(SEPARATOR);
                element.data({
                    type: 'separator',
                    separator: this
                });
            }
        });
        var OverflowSeparator = Item.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<li>&nbsp;</li>');
                this.element = element;
                this.options = options;
                this.toolbar = toolbar;
                this.overflow = true;
                this.attributes();
                this.addUidAttr();
                this.addOverflowIdAttr();
                element.addClass(SEPARATOR);
                element.data({
                    type: 'separator',
                    separator: this
                });
            },
            overflowHidden: function () {
                this.element.addClass(OVERFLOW_HIDDEN);
            }
        });
        kendo.toolbar.registerComponent('separator', ToolBarSeparator, OverflowSeparator);
        var ToolBarSpacer = Item.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<div>&nbsp;</div>');
                this.element = element;
                this.options = options;
                this.toolbar = toolbar;
                element.addClass(SPACER_CLASS);
                element.data({ type: SPACER });
            }
        });
        kendo.toolbar.registerComponent(SPACER, ToolBarSpacer);
        var TemplateItem = Item.extend({
            init: function (template, options, toolbar) {
                var element = isFunction(template) ? template(options) : template;
                if (!(element instanceof jQuery)) {
                    element = $('<div></div>').html(element);
                } else {
                    element = element.wrap('<div></div>').parent();
                }
                this.element = element;
                this.options = options;
                this.options.type = 'template';
                this.toolbar = toolbar;
                this.attributes();
                this.addUidAttr();
                this.addIdAttr();
                this.addOverflowAttr();
                element.data({
                    type: 'template',
                    template: this
                });
            }
        });
        kendo.toolbar.TemplateItem = TemplateItem;
        var OverflowTemplateItem = Item.extend({
            init: function (template, options, toolbar) {
                var element = isFunction(template) ? $(template(options)) : $(template);
                if (!(element instanceof jQuery)) {
                    element = $('<li></li>').html(element);
                } else {
                    element = element.wrap('<li></li>').parent();
                }
                this.element = element;
                this.options = options;
                this.options.type = 'template';
                this.toolbar = toolbar;
                this.overflow = true;
                this.attributes();
                this.addUidAttr();
                this.addOverflowIdAttr();
                this.addOverflowAttr();
                element.data({
                    type: 'template',
                    template: this
                });
            },
            overflowHidden: function () {
                this.element.addClass(OVERFLOW_HIDDEN);
            }
        });
        kendo.toolbar.OverflowTemplateItem = OverflowTemplateItem;
        function toggleActive(e) {
            if (!e.target.is('.k-toggle-button')) {
                e.target.toggleClass(STATE_ACTIVE, e.type == 'press');
            }
        }
        function actionSheetWrap(element) {
            element = $(element);
            return element.hasClass('km-actionsheet') ? element.closest('.km-popup-wrapper') : element.addClass('km-widget km-actionsheet').wrap('<div class="km-actionsheet-wrapper km-actionsheet-tablet km-widget km-popup"></div>').parent().wrap('<div class="km-popup-wrapper k-popup"></div>').parent();
        }
        function preventClick(e) {
            if ($(e.target).closest('a.k-button').length) {
                e.preventDefault();
            }
        }
        function findFocusableSibling(element, dir) {
            var getSibling = dir === 'next' ? $.fn.next : $.fn.prev;
            var getter = dir === 'next' ? $.fn.first : $.fn.last;
            var candidate = getSibling.call(element);
            if (!candidate.length && element.is('.' + OVERFLOW_ANCHOR)) {
                return element;
            }
            if (candidate.is(':kendoFocusable') || !candidate.length) {
                return candidate;
            }
            if (candidate.find(':kendoFocusable').length) {
                return getter.call(candidate.find(':kendoFocusable'));
            }
            return findFocusableSibling(candidate, dir);
        }
        var Group = Class.extend({
            init: function (name) {
                this.name = name;
                this.buttons = [];
            },
            add: function (button) {
                this.buttons[this.buttons.length] = button;
            },
            remove: function (button) {
                var index = $.inArray(button, this.buttons);
                this.buttons.splice(index, 1);
            },
            select: function (button) {
                var tmp;
                for (var i = 0; i < this.buttons.length; i++) {
                    tmp = this.buttons[i];
                    tmp.select(false);
                }
                button.select(true);
                if (button.twin()) {
                    button.twin().select(true);
                }
            }
        });
        var ToolBar = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.wrapper = that.element;
                element.addClass(TOOLBAR + ' k-widget');
                this.uid = kendo.guid();
                this._isRtl = kendo.support.isRtl(element);
                this._groups = {};
                element.attr(KENDO_UID_ATTR, this.uid);
                that.isMobile = typeof options.mobile === 'boolean' ? options.mobile : that.element.closest('.km-root')[0];
                that.animation = that.isMobile ? { open: { effects: 'fade' } } : {};
                if (that.isMobile) {
                    element.addClass('km-widget');
                    ICON = 'km-icon';
                    ICON_PREFIX = 'km-';
                    BUTTON = 'km-button';
                    BUTTON_GROUP = 'km-buttongroup';
                    STATE_ACTIVE = 'km-state-active';
                    STATE_DISABLED = 'km-state-disabled';
                }
                if (options.resizable) {
                    that._renderOverflow();
                    element.addClass(RESIZABLE_TOOLBAR);
                    that.overflowUserEvents = new kendo.UserEvents(that.element, {
                        threshold: 5,
                        allowSelection: true,
                        filter: '.' + OVERFLOW_ANCHOR,
                        tap: proxy(that._toggleOverflow, that)
                    });
                    that._resizeHandler = kendo.onResize(function () {
                        that.resize();
                    });
                } else {
                    that.popup = { element: $([]) };
                }
                if (options.items && options.items.length) {
                    for (var i = 0; i < options.items.length; i++) {
                        that.add(options.items[i]);
                    }
                    if (options.resizable) {
                        that._shrink(that.element.innerWidth());
                    }
                }
                that.userEvents = new kendo.UserEvents(document, {
                    threshold: 5,
                    allowSelection: true,
                    filter: '[' + KENDO_UID_ATTR + '=' + this.uid + '] a.' + BUTTON + ', ' + '[' + KENDO_UID_ATTR + '=' + this.uid + '] .' + OVERFLOW_BUTTON,
                    tap: proxy(that._buttonClick, that),
                    press: toggleActive,
                    release: toggleActive
                });
                that.element.on(CLICK, 'a.k-button', preventClick);
                that._navigatable();
                if (options.resizable) {
                    that.popup.element.on(CLICK, +'a.k-button', preventClick);
                }
                if (options.resizable) {
                    this._toggleOverflowAnchor();
                }
                kendo.notify(that);
            },
            events: [
                CLICK,
                TOGGLE,
                OPEN,
                CLOSE,
                OVERFLOW_OPEN,
                OVERFLOW_CLOSE
            ],
            options: {
                name: 'ToolBar',
                items: [],
                resizable: true,
                mobile: null
            },
            addToGroup: function (button, groupName) {
                var group;
                if (!this._groups[groupName]) {
                    group = this._groups[groupName] = new Group();
                } else {
                    group = this._groups[groupName];
                }
                group.add(button);
                return group;
            },
            destroy: function () {
                var that = this;
                that.element.find('.' + SPLIT_BUTTON).each(function (idx, element) {
                    $(element).data('kendoPopup').destroy();
                });
                that.element.off(CLICK, 'a.k-button');
                that.userEvents.destroy();
                if (that.options.resizable) {
                    kendo.unbindResize(that._resizeHandler);
                    that.overflowUserEvents.destroy();
                    that.popup.element.off(CLICK, 'a.k-button');
                    that.popup.destroy();
                }
                Widget.fn.destroy.call(that);
            },
            add: function (options) {
                var component = components[options.type], template = options.template, tool, that = this, itemClasses = that.isMobile ? '' : 'k-item k-state-default', overflowTemplate = options.overflowTemplate, overflowTool;
                $.extend(options, {
                    uid: kendo.guid(),
                    animation: that.animation,
                    mobile: that.isMobile,
                    rootUid: that.uid
                });
                if (options.menuButtons) {
                    for (var i = 0; i < options.menuButtons.length; i++) {
                        $.extend(options.menuButtons[i], { uid: kendo.guid() });
                    }
                }
                if (template && !overflowTemplate || options.type === SPACER) {
                    options.overflow = OVERFLOW_NEVER;
                } else if (!options.overflow) {
                    options.overflow = OVERFLOW_AUTO;
                }
                if (options.overflow !== OVERFLOW_NEVER && that.options.resizable) {
                    if (overflowTemplate) {
                        overflowTool = new OverflowTemplateItem(overflowTemplate, options, that);
                    } else if (component) {
                        overflowTool = new component.overflow(options, that);
                        overflowTool.element.addClass(itemClasses);
                    }
                    if (overflowTool) {
                        if (options.overflow === OVERFLOW_AUTO) {
                            overflowTool.overflowHidden();
                        }
                        overflowTool.element.appendTo(that.popup.container);
                        that.angular('compile', function () {
                            return { elements: overflowTool.element.get() };
                        });
                    }
                }
                if (options.overflow !== OVERFLOW_ALWAYS) {
                    if (template) {
                        tool = new TemplateItem(template, options, that);
                    } else if (component) {
                        tool = new component.toolbar(options, that);
                    }
                    if (tool) {
                        tool.element.appendTo(that.element);
                        that.angular('compile', function () {
                            return { elements: tool.element.get() };
                        });
                    }
                }
            },
            _getItem: function (candidate) {
                var element, toolbarItem, overflowItem, isResizable = this.options.resizable, type;
                element = this.element.find(candidate);
                if (!element.length) {
                    element = $('.k-split-container[data-uid=' + this.uid + ']').find(candidate);
                }
                type = element.length ? element.data('type') : '';
                toolbarItem = element.data(type);
                if (toolbarItem) {
                    if (toolbarItem.main) {
                        element = element.parent('.' + SPLIT_BUTTON);
                        type = 'splitButton';
                        toolbarItem = element.data(type);
                    }
                    if (isResizable) {
                        overflowItem = toolbarItem.twin();
                    }
                } else if (isResizable) {
                    element = this.popup.element.find(candidate);
                    type = element.length ? element.data('type') : '';
                    overflowItem = element.data(type);
                    if (overflowItem && overflowItem.main) {
                        element = element.parent('.' + SPLIT_BUTTON);
                        type = 'splitButton';
                        overflowItem = element.data(type);
                    }
                }
                return {
                    type: type,
                    toolbar: toolbarItem,
                    overflow: overflowItem
                };
            },
            remove: function (candidate) {
                var item = this._getItem(candidate);
                if (item.toolbar) {
                    item.toolbar.remove();
                }
                if (item.overflow) {
                    item.overflow.remove();
                }
                this.resize(true);
            },
            hide: function (candidate) {
                var item = this._getItem(candidate);
                var buttonGroupInstance;
                if (item.toolbar) {
                    if (item.toolbar.options.type === 'button' && item.toolbar.options.isChild) {
                        buttonGroupInstance = item.toolbar.getParentGroup();
                        item.toolbar.hide();
                        if (buttonGroupInstance) {
                            buttonGroupInstance.refresh();
                        }
                    } else if (!item.toolbar.options.hidden) {
                        item.toolbar.hide();
                    }
                }
                if (item.overflow) {
                    if (item.overflow.options.type === 'button' && item.overflow.options.isChild) {
                        buttonGroupInstance = item.overflow.getParentGroup();
                        item.overflow.hide();
                        if (buttonGroupInstance) {
                            buttonGroupInstance.refresh();
                        }
                    } else if (!item.overflow.options.hidden) {
                        item.overflow.hide();
                    }
                }
                this.resize(true);
            },
            show: function (candidate) {
                var item = this._getItem(candidate);
                if (item.toolbar) {
                    if (item.toolbar.options.type === 'button' && item.toolbar.options.isChild) {
                        item.toolbar.show();
                        item.toolbar.getParentGroup().refresh();
                    } else if (item.toolbar.options.hidden) {
                        item.toolbar.show();
                    }
                }
                if (item.overflow) {
                    if (item.overflow.options.type === 'button' && item.overflow.options.isChild) {
                        item.toolbar.show();
                        item.overflow.getParentGroup().refresh();
                    } else if (item.overflow.options.hidden) {
                        item.overflow.show();
                    }
                }
                this.resize(true);
            },
            enable: function (element, enable) {
                var item = this._getItem(element);
                if (typeof enable == 'undefined') {
                    enable = true;
                }
                if (item.toolbar) {
                    item.toolbar.enable(enable);
                }
                if (item.overflow) {
                    item.overflow.enable(enable);
                }
            },
            getSelectedFromGroup: function (groupName) {
                return this.element.find('.' + TOGGLE_BUTTON + '[data-group=\'' + groupName + '\']').filter('.' + STATE_ACTIVE);
            },
            toggle: function (button, checked) {
                var element = $(button), item = element.data('button');
                if (item.options.togglable) {
                    if (checked === undefined) {
                        checked = true;
                    }
                    item.toggle(checked, true);
                }
            },
            _renderOverflow: function () {
                var that = this, overflowContainer = components.overflowContainer, isRtl = that._isRtl, horizontalDirection = isRtl ? 'left' : 'right';
                that.overflowAnchor = $(components.overflowAnchor).addClass(BUTTON);
                that.element.append(that.overflowAnchor);
                if (that.isMobile) {
                    that.overflowAnchor.append('<span class="km-icon km-more"></span>');
                    overflowContainer = actionSheetWrap(overflowContainer);
                } else {
                    that.overflowAnchor.append('<span class="k-icon k-i-more-vertical"></span>');
                }
                that.popup = new kendo.ui.Popup(overflowContainer, {
                    origin: 'bottom ' + horizontalDirection,
                    position: 'top ' + horizontalDirection,
                    anchor: that.overflowAnchor,
                    isRtl: isRtl,
                    animation: that.animation,
                    appendTo: that.isMobile ? $(that.isMobile).children('.km-pane') : null,
                    copyAnchorStyles: false,
                    open: function (e) {
                        var wrapper = kendo.wrap(that.popup.element).addClass('k-overflow-wrapper');
                        if (!that.isMobile) {
                            wrapper.css('margin-left', (isRtl ? -1 : 1) * ((outerWidth(wrapper) - wrapper.width()) / 2 + 1));
                        } else {
                            that.popup.container.css('max-height', parseFloat($('.km-content:visible').innerHeight()) - 15 + 'px');
                        }
                        if (that.trigger(OVERFLOW_OPEN)) {
                            e.preventDefault();
                        }
                    },
                    activate: function () {
                        this.element.find(':kendoFocusable').first().focus();
                    },
                    close: function (e) {
                        if (that.trigger(OVERFLOW_CLOSE)) {
                            e.preventDefault();
                        }
                        this.element.focus();
                    }
                });
                that.popup.element.on('keydown', '.' + BUTTON, function (e) {
                    var target = $(e.target), li = target.parent(), isComplexTool = li.is('.' + BUTTON_GROUP) || li.is('.' + SPLIT_BUTTON), element;
                    e.preventDefault();
                    if (e.keyCode === keys.ESC || e.keyCode === keys.TAB || e.altKey && e.keyCode === keys.UP) {
                        that._toggleOverflow();
                        that.overflowAnchor.focus();
                    } else if (e.keyCode === keys.DOWN) {
                        element = !isComplexTool || isComplexTool && target.is(':last-child') ? li : target;
                        findFocusableSibling(element, 'next').focus();
                    } else if (e.keyCode === keys.UP) {
                        element = !isComplexTool || isComplexTool && target.is(':first-child') ? li : target;
                        findFocusableSibling(element, 'prev').focus();
                    } else if (e.keyCode === keys.SPACEBAR || e.keyCode === keys.ENTER) {
                        that.userEvents.trigger('tap', { target: $(e.target) });
                        that.overflowAnchor.focus();
                    } else if (e.keyCode === keys.HOME) {
                        li.parent().find(':kendoFocusable').first().focus();
                    } else if (e.keyCode === keys.END) {
                        li.parent().find(':kendoFocusable').last().focus();
                    }
                });
                if (that.isMobile) {
                    that.popup.container = that.popup.element.find('.' + OVERFLOW_CONTAINER);
                } else {
                    that.popup.container = that.popup.element;
                }
                that.popup.container.attr(KENDO_UID_ATTR, this.uid);
            },
            _toggleOverflowAnchor: function () {
                var hasVisibleChildren = false;
                var paddingEnd = this._isRtl ? 'padding-left' : 'padding-right';
                if (this.options.mobile) {
                    hasVisibleChildren = this.popup.element.find('.' + OVERFLOW_CONTAINER).children(':not(.' + OVERFLOW_HIDDEN + ', .' + POPUP + ')').length > 0;
                } else {
                    hasVisibleChildren = this.popup.element.children(':not(.' + OVERFLOW_HIDDEN + ', .' + POPUP + ')').length > 0;
                }
                if (hasVisibleChildren) {
                    this.overflowAnchor.css({
                        visibility: 'visible',
                        width: ''
                    });
                    this.wrapper.css(paddingEnd, this.overflowAnchor.outerWidth(true));
                } else {
                    this.overflowAnchor.css({
                        visibility: 'hidden',
                        width: '1px'
                    });
                    this.wrapper.css(paddingEnd, '');
                }
            },
            _buttonClick: function (e) {
                var that = this, popup, target, item, splitContainer, isSplitButtonArrow = e.target.closest('.' + SPLIT_BUTTON_ARROW).length, handler, eventData, urlTarget;
                e.preventDefault();
                if (isSplitButtonArrow) {
                    that._toggle(e);
                    return;
                }
                target = $(e.target).closest('.' + BUTTON, that.element);
                if (target.hasClass(OVERFLOW_ANCHOR)) {
                    return;
                }
                item = target.data('button');
                if (!item && that.popup) {
                    target = $(e.target).closest('.' + OVERFLOW_BUTTON, that.popup.container);
                    item = target.parent('li').data('button');
                }
                if (!item || !item.options.enable) {
                    return;
                }
                if (item.options.togglable) {
                    handler = isFunction(item.toggleHandler) ? item.toggleHandler : null;
                    item.toggle(!item.options.selected, true);
                    eventData = {
                        target: target,
                        group: item.options.group,
                        checked: item.options.selected,
                        id: item.options.id,
                        item: item
                    };
                    if (handler) {
                        handler.call(that, eventData);
                    }
                    that.trigger(TOGGLE, eventData);
                } else {
                    handler = isFunction(item.clickHandler) ? item.clickHandler : null;
                    eventData = {
                        sender: that,
                        target: target,
                        id: item.options.id,
                        item: item
                    };
                    if (handler) {
                        handler.call(that, eventData);
                    }
                    that.trigger(CLICK, eventData);
                }
                if (item.options.url) {
                    if (item.options.attributes && item.options.attributes.target) {
                        urlTarget = item.options.attributes.target;
                    }
                    window.open(item.options.url, urlTarget || '_self');
                }
                if (target.hasClass(OVERFLOW_BUTTON)) {
                    that.popup.close();
                }
                splitContainer = target.closest('.k-split-container');
                if (splitContainer[0]) {
                    popup = splitContainer.data('kendoPopup');
                    (popup ? popup : splitContainer.parents('.km-popup-wrapper').data('kendoPopup')).close();
                }
            },
            _navigatable: function () {
                var that = this;
                that.element.attr('tabindex', 0).on('focusin', function (ev) {
                    var target = $(ev.target);
                    var element = $(this).find(':kendoFocusable:first');
                    if (!target.is('.' + TOOLBAR) || element.length === 0) {
                        return;
                    }
                    if (element.is('.' + OVERFLOW_ANCHOR)) {
                        element = findFocusableSibling(element, 'next');
                    }
                    if (element.length) {
                        element[0].focus();
                    }
                }).on('keydown', proxy(that._keydown, that));
            },
            _keydown: function (e) {
                var target = $(e.target), keyCode = e.keyCode, items = this.element.children(':not(.k-separator):visible'), direction = this._isRtl ? -1 : 1;
                if (keyCode === keys.TAB) {
                    var element = target.parentsUntil(this.element).last(), lastHasFocus = false, firstHasFocus = false, isOnlyOverflowAnchor = false;
                    if (!items.not('.' + OVERFLOW_ANCHOR).length) {
                        isOnlyOverflowAnchor = true;
                    }
                    if (!element.length) {
                        element = target;
                    }
                    if (element.is('.' + OVERFLOW_ANCHOR) && !isOnlyOverflowAnchor) {
                        var lastItemNotOverflowAnchor = items.last();
                        if (e.shiftKey) {
                            e.preventDefault();
                        }
                        if (lastItemNotOverflowAnchor.is(':kendoFocusable')) {
                            items.last().focus();
                        } else {
                            items.last().find(':kendoFocusable').last().focus();
                        }
                    }
                    if (!e.shiftKey && items.index(element) === items.length - 1) {
                        if (element.is('.' + BUTTON_GROUP)) {
                            lastHasFocus = target.is(':last-child');
                        } else {
                            lastHasFocus = true;
                        }
                    }
                    var isFirstTool = items.index(element) === items.not('.k-overflow-anchor').first().index();
                    if (e.shiftKey && isFirstTool) {
                        if (element.is('.' + BUTTON_GROUP)) {
                            firstHasFocus = target.is(':first-child');
                        } else {
                            firstHasFocus = true;
                        }
                    }
                    if (lastHasFocus && this.overflowAnchor && this.overflowAnchor.css('visibility') !== 'hidden' && !isOnlyOverflowAnchor) {
                        e.preventDefault();
                        this.overflowAnchor.focus();
                    }
                    if (firstHasFocus || isOnlyOverflowAnchor && e.shiftKey) {
                        e.preventDefault();
                        var prevFocusable = this._getPrevFocusable(this.wrapper);
                        if (prevFocusable) {
                            prevFocusable.focus();
                        }
                    }
                    this._preventNextFocus = false;
                }
                if (e.altKey && keyCode === keys.DOWN) {
                    var splitButton = $(document.activeElement).data('splitButton');
                    var isOverflowAnchor = $(document.activeElement).is('.' + OVERFLOW_ANCHOR);
                    if (splitButton) {
                        splitButton.toggle();
                    } else if (isOverflowAnchor) {
                        this._toggleOverflow();
                    }
                    return;
                }
                if ((keyCode === keys.SPACEBAR || keyCode === keys.ENTER) && !target.is('input, checkbox')) {
                    if (keyCode === keys.SPACEBAR) {
                        e.preventDefault();
                    }
                    if (target.is('.' + SPLIT_BUTTON)) {
                        target = target.children().first();
                        this.userEvents.trigger('tap', { target: target });
                    } else if (keyCode === keys.SPACEBAR) {
                        this.userEvents.trigger('tap', { target: target });
                    }
                    return;
                }
                if (keyCode === keys.HOME) {
                    if (target.is('.k-dropdown') || target.is('input')) {
                        return;
                    }
                    if (this.overflowAnchor) {
                        items.eq(1).focus();
                    } else {
                        items.first().focus();
                    }
                    e.preventDefault();
                } else if (keyCode === keys.END) {
                    if (target.is('.k-dropdown') || target.is('input')) {
                        return;
                    }
                    if (this.overflowAnchor && $(this.overflowAnchor).css('visibility') != 'hidden') {
                        this.overflowAnchor.focus();
                    } else {
                        items.last().focus();
                    }
                    e.preventDefault();
                } else if (keyCode === keys.RIGHT && !this._preventNextFocus && !target.is('input, select, .k-dropdown, .k-colorpicker') && this._getNextElement(e.target, 1 * direction)) {
                    this._getNextElement(e.target, 1 * direction).focus();
                    e.preventDefault();
                } else if (keyCode === keys.LEFT && !this._preventNextFocus && !target.is('input, select, .k-dropdown, .k-colorpicker') && this._getNextElement(e.target, -1 * direction)) {
                    this._getNextElement(e.target, -1 * direction).focus();
                    e.preventDefault();
                }
            },
            _getNextElement: function (item, direction) {
                var items = this.element.children(':not(.k-separator):visible');
                var itemIndex = items.index(item) === -1 ? items.index(item.parentElement) : items.index(item);
                var startIndex = this.overflowAnchor ? 1 : 0;
                var directionNumber = direction;
                var searchIndex = direction === 1 ? items.length - 1 : startIndex;
                var index = direction === 1 ? startIndex : items.length - 1;
                var focusableItem = items[itemIndex + direction];
                this._preventNextFocus = false;
                if ($(item).closest('.' + BUTTON_GROUP).length && !$(item).is(direction === 1 ? ':last-child' : ':first-child')) {
                    return $(item).closest('.' + BUTTON_GROUP).children()[$(item).closest('.' + BUTTON_GROUP).children().index(item) + direction];
                }
                if (this.overflowAnchor && item === this.overflowAnchor[0] && direction === -1) {
                    focusableItem = items[items.length - 1];
                }
                if (itemIndex === searchIndex) {
                    focusableItem = !this.overflowAnchor || this.overflowAnchor && $(this.overflowAnchor).css('visibility') === 'hidden' ? items[index] : this.overflowAnchor;
                }
                while (!$(focusableItem).is(':kendoFocusable')) {
                    if (direction === -1 && $(focusableItem).closest('.' + BUTTON_GROUP).length) {
                        focusableItem = $(focusableItem).children(':not(label, div)').last();
                    } else {
                        focusableItem = $(focusableItem).children(':not(label, div)').first();
                    }
                    if (!focusableItem.length) {
                        directionNumber = directionNumber + direction;
                        focusableItem = items[itemIndex + directionNumber];
                        if (!focusableItem) {
                            return this.overflowAnchor;
                        }
                    }
                    this._preventNextFocus = $(focusableItem).closest('.' + BUTTON_GROUP).length ? false : true;
                }
                return focusableItem;
            },
            _getPrevFocusable: function (element) {
                if (element.is('html')) {
                    return element;
                }
                var elementToFocus, prevElement, prevElements = element.prevAll();
                prevElements.each(function () {
                    prevElement = $(this);
                    if (prevElement.is(':kendoFocusable')) {
                        elementToFocus = prevElement;
                        return false;
                    } else if (prevElement.find(':kendoFocusable').length > 0) {
                        elementToFocus = prevElement.find(':kendoFocusable').last();
                        return false;
                    }
                });
                if (elementToFocus) {
                    return elementToFocus;
                } else {
                    return this._getPrevFocusable(element.parent());
                }
            },
            _toggle: function (e) {
                var splitButton = $(e.target).closest('.' + SPLIT_BUTTON).data('splitButton');
                e.preventDefault();
                if (!splitButton.options.enable) {
                    return;
                }
                splitButton.toggle();
            },
            _toggleOverflow: function () {
                this.popup.toggle();
            },
            _resize: function (e) {
                var containerWidth = e.width;
                if (!this.options.resizable) {
                    return;
                }
                this.popup.close();
                this._shrink(containerWidth);
                this._stretch(containerWidth);
                this._markVisibles();
                this._toggleOverflowAnchor();
            },
            _childrenWidth: function () {
                var childrenWidth = 0;
                this.element.children(':visible:not(.' + STATE_HIDDEN + ', .' + SPACER_CLASS + ')').each(function () {
                    childrenWidth += outerWidth($(this), true);
                });
                return Math.ceil(childrenWidth);
            },
            _shrink: function (containerWidth) {
                var commandElement, visibleCommands;
                if (containerWidth < this._childrenWidth()) {
                    visibleCommands = this.element.children(':visible:not([data-overflow=\'never\'], .' + OVERFLOW_ANCHOR + ')');
                    for (var i = visibleCommands.length - 1; i >= 0; i--) {
                        commandElement = visibleCommands.eq(i);
                        if (containerWidth > this._childrenWidth()) {
                            break;
                        } else {
                            this._hideItem(commandElement);
                        }
                    }
                }
            },
            _stretch: function (containerWidth) {
                var commandElement, hiddenCommands;
                if (containerWidth > this._childrenWidth()) {
                    hiddenCommands = this.element.children(':hidden:not(\'.' + STATE_HIDDEN + '\')');
                    for (var i = 0; i < hiddenCommands.length; i++) {
                        commandElement = hiddenCommands.eq(i);
                        if (containerWidth < this._childrenWidth() || !this._showItem(commandElement, containerWidth)) {
                            break;
                        }
                    }
                }
            },
            _hideItem: function (item) {
                item.hide();
                if (this.popup) {
                    this.popup.container.find('>li[data-uid=\'' + item.data('uid') + '\']').removeClass(OVERFLOW_HIDDEN);
                }
            },
            _showItem: function (item, containerWidth) {
                if (item.length && containerWidth > this._childrenWidth() + outerWidth(item, true)) {
                    item.show();
                    if (this.popup) {
                        this.popup.container.find('>li[data-uid=\'' + item.data('uid') + '\']').addClass(OVERFLOW_HIDDEN);
                    }
                    return true;
                }
                return false;
            },
            _markVisibles: function () {
                var overflowItems = this.popup.container.children(), toolbarItems = this.element.children(':not(.k-overflow-anchor)'), visibleOverflowItems = overflowItems.filter(':not(.k-overflow-hidden)'), visibleToolbarItems = toolbarItems.filter(':visible');
                overflowItems.add(toolbarItems).removeClass(FIRST_TOOLBAR_VISIBLE + ' ' + LAST_TOOLBAR_VISIBLE);
                visibleOverflowItems.first().add(visibleToolbarItems.first()).addClass(FIRST_TOOLBAR_VISIBLE);
                visibleOverflowItems.last().add(visibleToolbarItems.last()).addClass(LAST_TOOLBAR_VISIBLE);
            }
        });
        kendo.ui.plugin(ToolBar);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mediaplayer', [
        'kendo.slider',
        'kendo.toolbar',
        'kendo.dropdownlist',
        'kendo.tooltip'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mediaplayer',
        name: 'MediaPlayer',
        category: 'web',
        description: '',
        depends: [
            'slider',
            'toolbar',
            'dropdownlist',
            'tooltip'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, END = 'end', PAUSE = 'pause', PLAY = 'play', READY = 'ready', TIMECHANGE = 'timeChange', VOLUMECHANGE = 'volumeChange', FULLSCREEN_ENTER = 'k-i-full-screen', FULLSCREEN_EXIT = 'k-i-full-screen-exit', MUTE = 'k-i-volume-off', LOW_VOLUME = 'k-i-volume-down', HIGH_VOLUME = 'k-i-volume-up', VIDEO_QUALITY = 'k-mediaplayer-quality', STATE_PLAY = 'k-i-play', STATE_PAUSE = 'k-i-pause', TITLEBAR = 'k-mediaplayer-titlebar', TITLE = 'k-title', TOOLBARWRAP = 'k-mediaplayer-toolbar-wrap', TOOLBAR = 'k-mediaplayer-toolbar', SLIDER = 'k-mediaplayer-seekbar', VOLUME_SLIDER = 'k-mediaplayer-volume', MEDIA = 'k-mediaplayer-media', OVERLAY = 'k-mediaplayer-overlay', YTPLAYER = 'k-mediaplayer-yt', DOT = '.', ui = kendo.ui, ns = '.kendoMediaPlayer', baseTime = new Date(1970, 0, 1), timeZoneSec = baseTime.getTimezoneOffset() * 60, Widget = kendo.ui.Widget, isArray = $.isArray, timeFormats = {
                shortTime: 'mm:ss',
                longTime: 'HH:mm:ss'
            }, template = kendo.template, proxy = $.proxy, keys = kendo.keys, templates = {
                htmlPlayer: '<video class=\'' + MEDIA + '\'> </video>',
                titleBar: template('<div class=\'' + TITLEBAR + '\' role=\'heading\'><span class=\'' + TITLE + '\'>Video Title</span></div>'),
                toolBar: '<div class=\'' + TOOLBARWRAP + '\'><div class=\'' + TOOLBAR + '\'></div></div>',
                youtubePlayer: '<div class=\'' + YTPLAYER + '\'> </div>',
                toolBarTime: '<span class=\'k-mediaplayer-currenttime\'>00:00:00</span> / <span class=\'k-mediaplayer-duration\'>00:00:00</span>',
                slider: '<input class=\'' + SLIDER + '\' value=\'0\' title=\'seekbar\' />',
                volumeSlider: '<input class=\'' + VOLUME_SLIDER + '\' title=\'volume\'/>',
                qualityDropDown: '<input class=\'' + VIDEO_QUALITY + '\' title=\'video quality\' />',
                toolTip: '#= kendo.toString(new Date(value), \'HH:mm:ss\') #'
            };
        var MediaPlayer = Widget.extend({
            init: function (element, options) {
                this.wrapper = $(element);
                Widget.fn.init.call(this, element, options);
                this.wrapper.addClass('k-mediaplayer k-widget');
                options = this.options;
                this._currentIndex = 0;
                this._createTitlebar();
                this._createToolbar();
                this._createDropDown();
                this._createSlider();
                this._createVolumeSlider();
                this._timers = {};
                this._aria();
                this._navigatable();
                if (options.fullScreen) {
                    this.fullScreen(true);
                }
                if (options.media) {
                    this.media(this.options.media);
                }
                kendo.notify(this);
            },
            events: [
                END,
                PAUSE,
                PLAY,
                READY,
                TIMECHANGE,
                VOLUMECHANGE
            ],
            options: {
                name: 'MediaPlayer',
                autoPlay: false,
                autoRepeat: false,
                volume: 100,
                fullScreen: false,
                mute: false,
                navigatable: false,
                forwardSeek: true,
                media: null,
                messages: {
                    'pause': 'Pause',
                    'play': 'Play',
                    'mute': 'Mute',
                    'unmute': 'Unmute',
                    'quality': 'Quality',
                    'fullscreen': 'Full Screen'
                }
            },
            _msToTime: function (ms) {
                var time = new Date(baseTime.getTime());
                time.setSeconds(ms);
                return time;
            },
            _timeToSec: function (time) {
                var curTime = new Date(time).getTime();
                return curTime / 1000;
            },
            _createTitlebar: function () {
                this._titleBar = this.wrapper.find(DOT + TITLEBAR);
                if (this._titleBar.length === 0) {
                    this.wrapper.append(templates.titleBar);
                    this._titleBar = this.wrapper.find(DOT + TITLEBAR);
                }
            },
            _createSlider: function () {
                var sliderElement = this.wrapper.find(DOT + SLIDER);
                if (!this._slider) {
                    this._sliderDragChangeHandler = proxy(this._sliderDragChange, this);
                    this._sliderDraggingHandler = proxy(this._sliderDragging, this);
                    sliderElement = this.wrapper.find(DOT + SLIDER);
                    this._slider = new ui.Slider(sliderElement[0], {
                        smallStep: 1000,
                        tickPlacement: 'none',
                        showButtons: false,
                        change: this._sliderDragChangeHandler,
                        slide: this._sliderDraggingHandler,
                        tooltip: { template: templates.toolTip },
                        dragHandleTitle: ''
                    });
                }
            },
            _createVolumeSlider: function () {
                var volumeSliderElement = this.wrapper.find(DOT + VOLUME_SLIDER);
                if (!this._volumeSlider) {
                    this._volumeDraggingHandler = proxy(this._volumeDragging, this);
                    this._volumeChangeHandler = proxy(this._volumeChange, this);
                    volumeSliderElement.width(87);
                    this._volumeSlider = new ui.Slider(volumeSliderElement[0], {
                        smallStep: 1,
                        min: 0,
                        max: 100,
                        value: this.options.volume,
                        slide: this._volumeDraggingHandler,
                        change: this._volumeChangeHandler,
                        tickPlacement: 'none',
                        showButtons: false,
                        tooltip: { enabled: false },
                        dragHandleTitle: ''
                    });
                }
            },
            _resetTime: function () {
                if (this._youTubeVideo) {
                    this._ytmedia.seekTo(0, true);
                } else {
                    this._media.currentTime = 0;
                }
                this._mediaTimeUpdate();
                $.grep(this._toolBar.options.items, function (e) {
                    return !!e.template;
                }).template = templates.toolBarTime;
            },
            _currentUrl: function () {
                var media = this.media();
                return isArray(media.source) ? media.source[this._currentIndex].url : media.source;
            },
            _isYouTubeUrl: function () {
                return !!this._currentUrl().match('youtube.com/|youtu.be/');
            },
            _setPlayerUrl: function () {
                var oldPlayer = this._youTubeVideo;
                this.stop();
                this._youTubeVideo = this._isYouTubeUrl();
                if (oldPlayer !== this._youTubeVideo) {
                    this.wrapper.find(DOT + YTPLAYER).toggle();
                    this.wrapper.find(DOT + MEDIA).toggle();
                }
                var initialized = this._media || this._ytmedia;
                this._initializePlayer();
                if (initialized) {
                    this.mute(this.mute());
                    this.volume(this.volume());
                }
                if (!this._youTubeVideo) {
                    this._videoOverlay.show();
                    this.wrapper.find(DOT + MEDIA + ' > source').remove();
                    this.wrapper.find(DOT + MEDIA).attr('src', this._currentUrl());
                    if (this.options.autoPlay) {
                        this.play();
                    }
                } else if (this._ytmedia) {
                    if (this._videoOverlay) {
                        this._videoOverlay.hide();
                    }
                    if (this.options.autoPlay) {
                        this._ytmedia.loadVideoById(this._getMediaId());
                        this._playStateToggle(true);
                    } else {
                        this._ytmedia.cueVideoById(this._getMediaId());
                        this._playStateToggle(true);
                    }
                }
            },
            _createToolbar: function () {
                var toolBarElement = this.wrapper.find(DOT + TOOLBAR);
                if (toolBarElement.length === 0) {
                    this._toolbarClickHandler = proxy(this._toolbarClick, this);
                    this.wrapper.append(templates.toolBar);
                    toolBarElement = this.wrapper.find(DOT + TOOLBAR);
                    toolBarElement.width(this.wrapper.find(DOT + MEDIA).width());
                    this._toolBar = new ui.ToolBar(toolBarElement, {
                        click: this._toolbarClickHandler,
                        resizable: false,
                        items: [
                            {
                                type: 'button',
                                attributes: { 'class': 'k-play-button' },
                                icon: 'play'
                            },
                            {
                                template: templates.toolBarTime,
                                attributes: { 'class': 'k-mediaplayer-currenttime-wrap' }
                            },
                            {
                                type: 'separator',
                                attributes: { 'class': 'k-toolbar-spacer' }
                            },
                            {
                                type: 'button',
                                attributes: { 'class': 'k-volume-button' },
                                icon: 'volume-up'
                            },
                            {
                                template: templates.volumeSlider,
                                attributes: { 'class': 'k-mediaplayer-volume-wrap' }
                            },
                            {
                                template: templates.qualityDropDown,
                                attributes: { 'class': 'k-mediaplayer-quality-wrap' }
                            },
                            {
                                type: 'button',
                                attributes: { 'class': 'k-fullscreen-button' },
                                icon: 'full-screen'
                            }
                        ]
                    });
                    this._toolBar.wrapper.off('keydown');
                    toolBarElement.before(templates.slider);
                    this._volumeButton = toolBarElement.find('.k-volume-button');
                    this._fullscreenButton = toolBarElement.find('.k-fullscreen-button');
                    this._volumeButton.attr('title', this.options.mute ? this.options.messages.unmute : this.options.messages.mute);
                    this._volumeButton.attr('aria-label', this.options.mute ? this.options.messages.unmute : this.options.messages.mute);
                    this._fullscreenButton.attr('title', this.options.messages.fullscreen);
                    this._fullscreenButton.attr('aria-label', this.options.messages.fullscreen);
                    toolBarElement.width('auto');
                    this._currentTimeElement = toolBarElement.find('.k-mediaplayer-currenttime');
                    this._durationElement = toolBarElement.find('.k-mediaplayer-duration');
                    this._playButton = toolBarElement.find('.k-play-button');
                    this._playButtonSpan = this._playButton.find('.k-i-play');
                    if (this.options.autoPlay) {
                        this._playStateToggle(true);
                    }
                    $([
                        this._volumeButton[0],
                        toolBarElement.find('.k-mediaplayer-volume-wrap')[0],
                        toolBarElement.find('.k-mediaplayer-quality-wrap')[0],
                        this._fullscreenButton[0]
                    ]).wrapAll('<div class=\'k-align-right\' />');
                    toolBarElement.find('.k-button').addClass('k-bare');
                }
            },
            _createDropDown: function () {
                var dropDownElement = this.wrapper.find(DOT + VIDEO_QUALITY);
                var media = this.media();
                if (typeof dropDownElement.data('kendoDropDownList') === 'undefined') {
                    this._dropDownSelectHandler = proxy(this._dropDownSelect, this);
                    this._dropDown = new ui.DropDownList(dropDownElement, {
                        dataTextField: 'quality',
                        dataValueField: 'url',
                        popup: {
                            position: 'bottom',
                            origin: 'top',
                            appendTo: this.wrapper
                        },
                        animation: {
                            open: {
                                effects: 'slideIn:up',
                                duration: 1
                            }
                        },
                        select: this._dropDownSelectHandler
                    });
                    if (media && isArray(media.source)) {
                        this._dropDown.setDataSource(media.source);
                        this._dropDown.select(0);
                    }
                    this._dropDown.wrapper.addClass('k-button k-bare');
                    this._dropDown.wrapper.attr('title', this.options.messages.quality).hide();
                    this._dropDown.wrapper.find('span.k-i-arrow-60-down').removeClass('k-i-arrow-60-down').addClass('k-icon k-i-hd');
                    this._dropDown.list.addClass('k-quality-list');
                }
            },
            _dropDownSelect: function (e) {
                if (this._currentIndex !== e.item.index()) {
                    this._currentIndex = e.item.index();
                    this._setPlayerUrl();
                }
            },
            _toolbarClick: function (e) {
                var target = $(e.target).children().first();
                var isPaused = target.hasClass(STATE_PLAY);
                if (!this.media()) {
                    return;
                }
                if (target.hasClass(STATE_PLAY) || target.hasClass(STATE_PAUSE)) {
                    if (isPaused) {
                        this.play();
                    } else {
                        this.pause();
                    }
                }
                if (target.hasClass(FULLSCREEN_ENTER) || target.hasClass(FULLSCREEN_EXIT)) {
                    if (this._isInFullScreen) {
                        target.removeClass(FULLSCREEN_EXIT).addClass(FULLSCREEN_ENTER);
                        this.fullScreen(false);
                    } else {
                        target.removeClass(FULLSCREEN_ENTER).addClass(FULLSCREEN_EXIT);
                        this.fullScreen(true);
                    }
                }
                if (target.hasClass(MUTE) || target.hasClass(LOW_VOLUME) || target.hasClass(HIGH_VOLUME)) {
                    var muted = this.mute();
                    this.mute(!muted);
                }
            },
            _sliderDragging: function () {
                if (!this.media()) {
                    return;
                }
                this._isDragging = true;
            },
            _sliderDragChange: function (e) {
                var that = this;
                var slider = e.sender;
                var tzOffset = timeZoneSec * 1000;
                if (!this.media()) {
                    return;
                }
                that._sliderChangeFired = true;
                that._isDragging = false;
                if (!this.options.forwardSeek && slider.value() > this._seekBarLastPosition) {
                    setTimeout(function () {
                        slider.value(that._seekBarLastPosition);
                    }, 1);
                } else if (this._youTubeVideo) {
                    that._ytmedia.seekTo(that._timeToSec(e.value - tzOffset));
                } else {
                    that._media.currentTime = that._timeToSec(e.value - tzOffset);
                }
                that.trigger(TIMECHANGE);
                that._preventPlay = true;
            },
            _changeVolumeButtonImage: function (volume) {
                var volumeButton = this._volumeButton;
                var volumeElement = volumeButton.find('span');
                var cssClass = volumeElement.attr('class');
                cssClass = cssClass.substring(0, cssClass.lastIndexOf(' '));
                if (volume === 0) {
                    volumeElement.attr('class', cssClass + ' ' + MUTE);
                    volumeButton.attr('title', this.options.messages.unmute);
                    volumeButton.attr('aria-label', this.options.messages.unmute);
                } else if (volume > 0 && volume < 51) {
                    volumeElement.attr('class', cssClass + ' ' + LOW_VOLUME);
                    volumeButton.attr('title', this.options.messages.mute);
                    volumeButton.attr('aria-label', this.options.messages.mute);
                } else {
                    volumeElement.attr('class', cssClass + ' ' + HIGH_VOLUME);
                    volumeButton.attr('title', this.options.messages.mute);
                    volumeButton.attr('aria-label', this.options.messages.mute);
                }
            },
            _volumeDragging: function (e) {
                if (!this.media()) {
                    return;
                }
                this.volume(e.value);
                this._changeVolumeButtonImage(e.value);
                this.trigger(VOLUMECHANGE);
            },
            _volumeChange: function (e) {
                if (!this.media()) {
                    return;
                }
                this.volume(e.value);
                this._changeVolumeButtonImage(e.value);
                this.trigger(VOLUMECHANGE);
            },
            _mediaTimeUpdate: function () {
                var currentTime = this._youTubeVideo ? this._ytmedia.getCurrentTime() : this._media.currentTime;
                currentTime = currentTime ? currentTime : 0;
                var timeInMs = this._msToTime(currentTime);
                this._currentTimeElement.text(kendo.toString(timeInMs, this._timeFormat));
                if (!this._isDragging) {
                    this._seekBarLastPosition = (currentTime + timeZoneSec) * 1000;
                    this._slider.value(this._seekBarLastPosition);
                }
                return this.isPlaying();
            },
            _playStateToggle: function (play) {
                if (typeof play === 'undefined') {
                    play = this._playButtonSpan.is(DOT + STATE_PLAY);
                }
                if (play) {
                    this._playButtonSpan.removeClass(STATE_PLAY).addClass(STATE_PAUSE);
                    this._playButton.attr('title', this.options.messages.pause);
                    this._playButton.attr('aria-label', this.options.messages.pause);
                } else {
                    this._playButtonSpan.removeClass(STATE_PAUSE).addClass(STATE_PLAY);
                    this._playButton.attr('title', this.options.messages.play);
                    this._playButton.attr('aria-label', this.options.messages.play);
                }
            },
            _mediaEnded: function () {
                this._playStateToggle(false);
                this._currentTimeElement.text(kendo.toString(this._msToTime(0), this._timeFormat));
                this._slider.value((0 + timeZoneSec) * 1000);
                this.trigger(END);
            },
            _mediaPlay: function () {
                this.trigger(PLAY);
            },
            _mediaReady: function () {
                this.trigger(READY);
            },
            _mediaDurationChange: function () {
                var durationTime = this._msToTime(this._youTubeVideo ? this._ytmedia.getDuration() : this._media.duration);
                this._timeFormat = durationTime.getHours() === 0 ? timeFormats.shortTime : timeFormats.longTime;
                this._durationElement.text(kendo.toString(durationTime, this._timeFormat));
                this._slider.setOptions({
                    min: baseTime.getTime(),
                    max: durationTime.getTime()
                });
                if (!this._isFirstRun) {
                    this._resetTime();
                    this._isFirstRun = true;
                }
            },
            _createYoutubePlayer: function () {
                this._mediaTimeUpdateHandler = proxy(this._mediaTimeUpdate, this);
                this._mediaDurationChangeHandler = proxy(this._mediaDurationChange, this);
                this.wrapper.prepend(templates.youtubePlayer);
                this._ytPlayer = this.wrapper.find(DOT + YTPLAYER)[0];
                $(this._ytPlayer).css({
                    width: this.wrapper.width(),
                    height: this.wrapper.height()
                });
                if (!window.YT || !window.YT.Player) {
                    if (!window.onYouTubeIframeAPIReadyRegister) {
                        window.onYouTubeIframeAPIReadyRegister = [];
                        $.getScript('https://www.youtube.com/iframe_api');
                        window.onYouTubeIframeAPIReady = function () {
                            if (window.onYouTubeIframeAPIReadyRegister) {
                                for (var i = 0; i < window.onYouTubeIframeAPIReadyRegister.length; i++) {
                                    window.onYouTubeIframeAPIReadyRegister[i]._youtubeApiReady();
                                }
                            }
                            window.onYouTubeIframeAPIReadyRegister.length = 0;
                            window.onYouTubeIframeAPIReadyRegister = undefined;
                        };
                    }
                    window.onYouTubeIframeAPIReadyRegister[window.onYouTubeIframeAPIReadyRegister.length] = this;
                } else {
                    this._configurePlayer();
                }
            },
            _poll: function (name, callback, interval, context) {
                var that = this;
                if (that._timers[name] !== null) {
                    clearTimeout(that._timers[name]);
                }
                that._timers[name] = setTimeout(function (context) {
                    return function callLater() {
                        if (callback.call(context)) {
                            that._timers[name] = setTimeout(callLater, interval);
                        }
                    };
                }(context), interval);
                return that._timers[name];
            },
            _youtubeApiReady: function () {
                this._configurePlayer();
            },
            _configurePlayer: function () {
                var vars = {
                    'autoplay': +this.options.autoPlay,
                    'wmode': 'transparent',
                    'controls': 0,
                    'rel': 0,
                    'showinfo': 0
                };
                this._onYouTubePlayerReady = proxy(this._onYouTubePlayerReady, this);
                window.onYouTubePlayerReady = this._onYouTubePlayerReady;
                this._onPlayerStateChangeHandler = proxy(this._onPlayerStateChange, this);
                window.onPlayerStateChange = this._onPlayerStateChange;
                var player = new window.YT.Player(this.wrapper.find(DOT + YTPLAYER)[0], {
                    height: this.wrapper.height(),
                    width: this.wrapper.width(),
                    videoId: this._getMediaId(),
                    playerVars: vars,
                    events: {
                        'onReady': this._onYouTubePlayerReady,
                        'onStateChange': this._onPlayerStateChangeHandler
                    }
                });
            },
            _onYouTubePlayerReady: function (event) {
                this._ytmedia = event.target;
                this._ytmedia.getIframe().style.width = '100%';
                this._ytmedia.getIframe().style.height = '100%';
                this._youTubeVideo = true;
                this._mediaDurationChangeHandler();
                if (this.options.autoPlay) {
                    this._playStateToggle(true);
                    this._ytmedia.loadVideoById(this._getMediaId());
                } else {
                    this._ytmedia.cueVideoById(this._getMediaId());
                }
                if (this.options.mute) {
                    this.mute(true);
                }
                this.trigger(READY);
            },
            _updateTitle: function () {
                this.titlebar().text(this.media().title || this.media().source);
            },
            _onPlayerStateChange: function (event) {
                if (event.data === 0) {
                    this._slider.value(0);
                    this._paused = false;
                    this._playStateToggle(true);
                    this.trigger(END);
                    if (this.options.autoRepeat) {
                        this.play();
                    }
                } else if (event.data === 1) {
                    this._mediaDurationChange();
                    this._ytmedia.setVolume(this.volume());
                    if (this._sliderChangeFired) {
                        this._sliderChangeFired = false;
                    } else {
                        this._uiDisplay(false);
                    }
                    this.trigger(PLAY);
                    this._playStateToggle(true);
                    this._poll('progress', this._mediaTimeUpdate, 500, this);
                    this._paused = false;
                } else if (event.data === 2) {
                    if (!this._paused) {
                        this._uiDisplay(true);
                        this._playStateToggle(false);
                        this.trigger(PAUSE);
                        this._paused = true;
                    }
                }
            },
            _getMediaId: function () {
                var result = this._currentUrl();
                var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
                var match = result.match(regExp);
                if (match && match[7].length === 11) {
                    result = match[7];
                }
                return result;
            },
            _mouseClick: function () {
                if (this.isPaused()) {
                    this.play();
                } else {
                    this.pause();
                }
            },
            _initializePlayer: function () {
                if (!this._mouseMoveHandler) {
                    this._mouseMoveHandler = proxy(this._mouseMove, this);
                    this._mouseInHandler = proxy(this._mouseIn, this);
                    this._mouseOutHandler = proxy(this._mouseOut, this);
                    $(this.wrapper).on('mouseenter' + ns, this._mouseInHandler).on('mouseleave' + ns, this._mouseOutHandler).on('mousemove' + ns, this._mouseMoveHandler);
                }
                if (!this._ytmedia && this._youTubeVideo) {
                    this._createYoutubePlayer();
                } else if (!this._media && !this._youTubeVideo) {
                    this._createHtmlPlayer();
                }
            },
            _createHtmlPlayer: function () {
                if (!this._videoOverlay) {
                    this._mouseClickHanlder = proxy(this._mouseClick, this);
                    this.wrapper.append('<div class=\'' + OVERLAY + '\'></div>');
                    this._videoOverlay = this.wrapper.find('.k-mediaplayer-overlay').on('click' + ns, this._mouseClickHanlder);
                }
                this._mediaTimeUpdateHandler = proxy(this._mediaTimeUpdate, this);
                this._mediaDurationChangeHandler = proxy(this._mediaDurationChange, this);
                this._mediaEndedHandler = proxy(this._mediaEnded, this);
                this._mediaCanPlayHandler = proxy(this._mediaReady, this);
                this._mediaPlayHandler = proxy(this._mediaPlay, this);
                this._videoOverlay.after(templates.htmlPlayer);
                this._media = this.wrapper.find(DOT + MEDIA)[0];
                $(this._media).css({
                    width: '100%',
                    height: '100%'
                });
                if (this.options.mute) {
                    this.mute(true);
                }
                this._media.ontimeupdate = this._mediaTimeUpdateHandler;
                this._media.ondurationchange = this._mediaDurationChangeHandler;
                this._media.oncanplay = this._mediaCanPlayHandler;
                this._media.onplay = this._mediaPlayHandler;
                this._media.onended = this._mediaEndedHandler;
                this._media.loop = this.options.autoRepeat;
            },
            _mouseIn: function () {
                this._uiDisplay(true);
            },
            _mouseOut: function () {
                this._poll('mouseIdle', this._mouseIdle, 3000, this);
            },
            _mouseIdle: function () {
                this._uiDisplay(false);
                return false;
            },
            _mouseMove: function () {
                if (!(this._titleBar.is(':animated') || this._toolBar.element.is(':animated') || this._slider.wrapper.is(':animated'))) {
                    this._uiDisplay(true);
                }
                this._poll('mouseIdle', this._mouseIdle, 3000, this);
            },
            _uiDisplay: function (state) {
                var animationSpeed = 'slow';
                var uiElements = this._titleBar.add(this._toolBar.element.parent());
                if (state) {
                    uiElements.fadeIn(animationSpeed);
                } else {
                    uiElements.fadeOut(animationSpeed);
                    if (this.options.navigatable) {
                        this.wrapper.focus();
                    }
                }
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (!this.isPaused()) {
                    this.pause();
                }
                this.element.off(ns);
                this.element.find(DOT + OVERLAY).off(ns);
                this._timers = null;
                this._mouseMoveHandler = null;
                this._mouseOutHandler = null;
                this._mouseInHandler = null;
                this._mouseClickHanlder = null;
                this._keyDownHandler = null;
                this._fullscreenHandler = null;
                this._toolbarClickHandler = null;
                this._sliderDragChangeHandler = null;
                this._sliderDraggingHandler = null;
                this._volumeDraggingHandler = null;
                this._volumeChangeHandler = null;
                this._youtubeApiReadyHandler = null;
                this._onYouTubePlayerReady = null;
                this._onPlayerStateChangeHandler = null;
                this._dropDownSelectHandler = null;
                if (this._youTubeVideo) {
                    this._ytmedia.destroy();
                } else {
                    this._media.ontimeupdate = this._mediaTimeUpdateHandler = null;
                    this._media.ondurationchange = this._mediaDurationChangeHandler = null;
                    this._media.oncanplay = this._mediaCanPlayHandler = null;
                    this._media.onplay = this._mediaPlayHandler = null;
                    this._media.onended = this._mediaEndedHandler = null;
                    this._media.src = '';
                    this._media.remove();
                }
                this._mouseMoveTimer = null;
                clearTimeout(this._mouseMoveTimer);
                kendo.destroy(this.element);
            },
            seek: function (ms) {
                if (typeof ms === 'undefined') {
                    return 1000 * this._youTubeVideo ? this._ytmedia.getCurrentTime() : this._media ? this._media.currentTime : 0;
                }
                var seconds = ms / 1000;
                if (this._youTubeVideo) {
                    if (seconds + 3 >= this._ytmedia.getDuration() | 0) {
                        this._ytmedia.seekTo(this._ytmedia.getDuration() - 3 | 0, true);
                    } else {
                        this._ytmedia.seekTo(seconds, true);
                    }
                } else {
                    this._media.currentTime = seconds;
                }
                return this;
            },
            play: function () {
                if (this._youTubeVideo) {
                    this._ytmedia.playVideo();
                } else {
                    if (kendo.support.mobileOS) {
                        this._uiDisplay(false);
                    }
                    this._media.play();
                }
                this._paused = false;
                this._playStateToggle(true);
                return this;
            },
            stop: function () {
                if (this._youTubeVideo && this._ytmedia) {
                    this._ytmedia.stopVideo();
                } else if (this._media && !this._youTubeVideo) {
                    if (kendo.support.mobileOS) {
                        this._uiDisplay(true);
                    }
                    this._media.pause();
                    this._media.currentTime = 0;
                }
                this._paused = true;
                this._playStateToggle(false);
                return this;
            },
            pause: function () {
                if (this._youTubeVideo) {
                    this._ytmedia.pauseVideo();
                } else {
                    if (kendo.support.mobileOS) {
                        this._uiDisplay(true);
                    }
                    this._media.pause();
                }
                this._paused = true;
                this._playStateToggle(false);
                this.trigger(PAUSE);
                return this;
            },
            toolbar: function () {
                return this._toolBar;
            },
            dropdown: function () {
                return this._dropDown;
            },
            titlebar: function () {
                return this._titleBar;
            },
            fullScreen: function (enterFullScreen) {
                if (typeof enterFullScreen === 'undefined') {
                    return this._isInFullScreen || false;
                }
                var element = this.element.get(0);
                if (enterFullScreen) {
                    this.element.addClass('k-mediaplayer-fullscreen');
                    if (element.requestFullscreen) {
                        element.requestFullscreen();
                    } else if (element.webkitRequestFullscreen) {
                        element.webkitRequestFullscreen();
                    } else if (element.mozRequestFullScreen) {
                        element.mozRequestFullScreen();
                    } else if (element.msRequestFullscreen) {
                        element.msRequestFullscreen();
                    }
                    this._isInFullScreen = true;
                } else {
                    if (document.cancelFullscreen) {
                        document.cancelFullscreen();
                    } else if (document.webkitCancelFullScreen) {
                        document.webkitCancelFullScreen();
                    } else if (document.mozCancelFullScreen) {
                        document.mozCancelFullScreen();
                    } else if (document.msCancelFullscreen) {
                        document.msCancelFullscreen();
                    } else if (document.exitFullscreen) {
                        document.exitFullscreen();
                    } else if (document.msExitFullscreen) {
                        document.msExitFullscreen();
                    }
                    this.element.removeClass('k-mediaplayer-fullscreen');
                    this._isInFullScreen = false;
                }
                this._slider.resize();
            },
            volume: function (value) {
                if (typeof value === 'undefined') {
                    return typeof this._volume !== 'undefined' ? this._volume : this._volume = this.options.volume;
                }
                this._volume = value;
                this.mute(value <= 0);
                if (this._youTubeVideo) {
                    this._ytmedia.setVolume(this._volume);
                } else {
                    this._media.volume = this._volume / 100;
                }
                this._volumeSlider.value(value);
            },
            mute: function (muted) {
                var currentState = this._youTubeVideo ? this._ytmedia && this._ytmedia.isMuted() : this._media && this._media.muted;
                if (typeof muted === 'undefined' || muted === currentState) {
                    return currentState;
                }
                if (this._youTubeVideo) {
                    if (muted) {
                        this._ytmedia.mute();
                    } else {
                        this._ytmedia.unMute();
                    }
                } else {
                    this._media.muted = muted;
                }
                if (muted) {
                    this._volumeSlider.value(0);
                } else {
                    this._volumeSlider.value(this._media && this._media.volume * 100 || this._ytmedia && this._ytmedia.getVolume());
                }
                this.trigger(VOLUMECHANGE);
                this._changeVolumeButtonImage(this._volumeSlider.value());
            },
            isEnded: function () {
                if (this._youTubeVideo) {
                    return this._ytmedia.getPlayerState() === 0;
                } else {
                    return this._media.ended;
                }
            },
            media: function (value) {
                var dropdown = this.dropdown();
                if (typeof value === 'undefined') {
                    return typeof this._mediaData !== 'undefined' ? this._mediaData : this._mediaData = this.options.media;
                }
                if (isArray(value.source)) {
                    dropdown.setDataSource(value.source);
                    dropdown.wrapper.show();
                } else {
                    dropdown.wrapper.hide();
                }
                this._mediaData = value;
                this._updateTitle();
                this._setPlayerUrl();
            },
            isPaused: function () {
                return this._paused;
            },
            isPlaying: function () {
                return !this.isEnded() && !this._paused;
            },
            _aria: function () {
                this.wrapper.attr('role', 'region');
            },
            _navigatable: function () {
                this._fullscreenHandler = proxy(this._fullscreen, this);
                $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange' + ns, this._fullscreenHandler);
                if (this.options.navigatable) {
                    this.wrapper.attr('tabIndex', 0);
                    this._keyDownHandler = proxy(this._keyDown, this);
                    this.wrapper.on('keydown' + ns, this._keyDownHandler);
                }
            },
            _fullscreen: function () {
                var isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
                this._uiDisplay(true);
                this._slider.resize();
                if (!isFullScreen) {
                    this.wrapper.find('span[class*="k-i-fullscreen"]').removeClass(FULLSCREEN_EXIT).addClass(FULLSCREEN_ENTER);
                    this.fullScreen(false);
                }
            },
            _keyDown: function (e) {
                e.preventDefault();
                var fsButton = this.wrapper.find('span[class*="k-i-fullscreen"]');
                if (e.keyCode === keys.SPACEBAR) {
                    if (this.isPlaying()) {
                        this.pause();
                    } else {
                        this.play();
                    }
                } else if (e.keyCode === keys.ENTER && !this._isInFullScreen) {
                    fsButton.removeClass(FULLSCREEN_ENTER).addClass(FULLSCREEN_EXIT);
                    this.fullScreen(true);
                } else if (e.keyCode === 77) {
                    var muted = this.mute();
                    this.mute(!muted);
                } else if (e.keyCode === keys.ESC && this._isInFullScreen) {
                    fsButton.removeClass(FULLSCREEN_EXIT).addClass(FULLSCREEN_ENTER);
                    this.fullScreen(false);
                }
            },
            _error: function () {
            },
            _progress: function () {
            }
        });
        ui.plugin(MediaPlayer);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define === 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pivotgrid', [
        'kendo.dom',
        'kendo.data'
    ], f);
}(function () {
    var __meta__ = {
        id: 'pivotgrid',
        name: 'PivotGrid',
        category: 'web',
        description: 'The PivotGrid widget is a data summarization tool.',
        depends: [
            'dom',
            'data',
            'data.xml',
            'sortable'
        ],
        features: [
            {
                id: 'pivotgrid-configurator',
                name: 'Configurator',
                description: 'The PivotConfigurator widget allows the user to select data slices displayed in PivotGrid',
                depends: ['pivot.configurator']
            },
            {
                id: 'pivotgrid-filtering',
                name: 'Filtering',
                description: 'Support for filtering',
                depends: ['pivot.fieldmenu']
            },
            {
                id: 'pivotgrid-excel-export',
                name: 'Excel export',
                description: 'Export pivot grid data as Excel spreadsheet',
                depends: ['ooxml']
            },
            {
                id: 'pivotgrid-pdf-export',
                name: 'PDF export',
                description: 'Export pivot grid data as PDF',
                depends: [
                    'pdf',
                    'drawing'
                ]
            },
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Class = kendo.Class, Widget = ui.Widget, DataSource = kendo.data.DataSource, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, toString = {}.toString, identity = function (o) {
                return o;
            }, map = $.map, extend = $.extend, isFunction = kendo.isFunction, CHANGE = 'change', ERROR = 'error', MEASURES = 'Measures', PROGRESS = 'progress', STATERESET = 'stateReset', AUTO = 'auto', DIV = '<div/>', NS = '.kendoPivotGrid', ROW_TOTAL_KEY = '__row_total__', DATABINDING = 'dataBinding', DATABOUND = 'dataBound', EXPANDMEMBER = 'expandMember', COLLAPSEMEMBER = 'collapseMember', STATE_EXPANDED = 'k-i-collapse', STATE_COLLAPSED = 'k-i-expand', HEADER_TEMPLATE = '<span>#: data.member.caption || data.member.name #</span>', KPISTATUS_TEMPLATE = '<span class="k-icon k-i-kpi-status-#=data.dataItem.value > 0 ? "open" : data.dataItem.value < 0 ? "deny" : "hold"#" title="#:data.dataItem.value#"></span>', KPITREND_TEMPLATE = '<span class="k-icon k-i-kpi-trend-#=data.dataItem.value > 0 ? "increase" : data.dataItem.value < 0 ? "decrease" : "equal"#" title="#:data.dataItem.value#"></span>', DATACELL_TEMPLATE = '#= data.dataItem ? kendo.htmlEncode(data.dataItem.fmtValue || data.dataItem.value) || "&nbsp;" : "&nbsp;" #', LAYOUT_TABLE = '<table class="k-pivot-layout">' + '<tr>' + '<td>' + '<div class="k-pivot-rowheaders"></div>' + '</td>' + '<td>' + '<div class="k-pivot-table k-state-default"></div>' + '</td>' + '</tr>' + '</table>';
        var AXIS_ROWS = 'rows';
        var AXIS_COLUMNS = 'columns';
        function normalizeMeasures(measure) {
            var descriptor = typeof measure === 'string' ? [{ name: measure }] : measure;
            var descriptors = toString.call(descriptor) === '[object Array]' ? descriptor : descriptor !== undefined ? [descriptor] : [];
            return map(descriptors, function (d) {
                if (typeof d === 'string') {
                    return { name: d };
                }
                return {
                    name: d.name,
                    type: d.type
                };
            });
        }
        function normalizeMembers(member) {
            var descriptor = typeof member === 'string' ? [{
                    name: [member],
                    expand: false
                }] : member;
            var descriptors = toString.call(descriptor) === '[object Array]' ? descriptor : descriptor !== undefined ? [descriptor] : [];
            return map(descriptors, function (d) {
                if (typeof d === 'string') {
                    return {
                        name: [d],
                        expand: false
                    };
                }
                return {
                    name: toString.call(d.name) === '[object Array]' ? d.name.slice() : [d.name],
                    expand: d.expand
                };
            });
        }
        function normalizeName(name) {
            if (name.indexOf(' ') !== -1) {
                name = '["' + name + '"]';
            }
            return name;
        }
        function accumulateMembers(accumulator, rootTuple, tuple, level) {
            var idx, length;
            var children;
            var member;
            if (!tuple) {
                tuple = rootTuple;
            }
            if (!level) {
                level = 0;
            }
            member = tuple.members[level];
            if (!member || member.measure) {
                return;
            }
            children = member.children;
            length = children.length;
            if (tuple === rootTuple) {
                accumulator[kendo.stringify([member.name])] = !!length;
            } else if (length) {
                accumulator[kendo.stringify(buildPath(tuple, level))] = true;
            }
            if (length) {
                for (idx = 0; idx < length; idx++) {
                    accumulateMembers(accumulator, rootTuple, children[idx], level);
                }
            }
            accumulateMembers(accumulator, rootTuple, tuple, level + 1);
        }
        function descriptorsForAxes(tuples) {
            var result = {};
            if (tuples.length) {
                accumulateMembers(result, tuples[0]);
            }
            var descriptors = [];
            for (var k in result) {
                descriptors.push({
                    name: $.parseJSON(k),
                    expand: result[k]
                });
            }
            return descriptors;
        }
        function addMissingPathMembers(members, axis) {
            var tuples = axis.tuples || [];
            var firstTuple = tuples[0];
            if (firstTuple && members.length < firstTuple.members.length) {
                var tupleMembers = firstTuple.members;
                for (var idx = 0; idx < tupleMembers.length; idx++) {
                    if (tupleMembers[idx].measure) {
                        continue;
                    }
                    var found = false;
                    for (var j = 0; j < members.length; j++) {
                        if (getName(members[j]).indexOf(tupleMembers[idx].hierarchy) === 0) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        members.push({
                            name: [tupleMembers[idx].name],
                            expand: false
                        });
                    }
                }
            }
        }
        function tupleToDescriptors(tuple) {
            var result = [];
            var members = tuple.members;
            for (var idx = 0; idx < members.length; idx++) {
                if (members[idx].measure) {
                    continue;
                }
                result.push({
                    name: [members[idx].name],
                    expand: members[idx].children.length > 0
                });
            }
            return result;
        }
        function descriptorsForMembers(axis, members, measures) {
            axis = axis || {};
            addMissingPathMembers(members, axis);
            if (measures.length > 1) {
                members.push({
                    name: MEASURES,
                    measure: true,
                    children: normalizeMembers(measures)
                });
            }
            var tupletoSearch = { members: members };
            if (axis.tuples) {
                var result = findExistingTuple(axis.tuples, tupletoSearch);
                if (result.tuple) {
                    members = tupleToDescriptors(result.tuple);
                }
            }
            return members;
        }
        function createAggregateGetter(m) {
            var measureGetter = kendo.getter(m.field, true);
            return function (aggregatorContext, state) {
                return m.aggregate(measureGetter(aggregatorContext.dataItem), state, aggregatorContext);
            };
        }
        function isNumber(val) {
            return typeof val === 'number' && !isNaN(val);
        }
        function isDate(val) {
            return val && val.getTime;
        }
        var functions = {
            sum: function (value, state) {
                var accumulator = state.accumulator;
                if (!isNumber(accumulator)) {
                    accumulator = value;
                } else if (isNumber(value)) {
                    accumulator += value;
                }
                return accumulator;
            },
            count: function (value, state) {
                return (state.accumulator || 0) + 1;
            },
            average: {
                aggregate: function (value, state) {
                    var accumulator = state.accumulator;
                    if (state.count === undefined) {
                        state.count = 0;
                    }
                    if (!isNumber(accumulator)) {
                        accumulator = value;
                    } else if (isNumber(value)) {
                        accumulator += value;
                    }
                    if (isNumber(value)) {
                        state.count++;
                    }
                    return accumulator;
                },
                result: function (state) {
                    var accumulator = state.accumulator;
                    if (isNumber(accumulator)) {
                        accumulator = accumulator / state.count;
                    }
                    return accumulator;
                }
            },
            max: function (value, state) {
                var accumulator = state.accumulator;
                if (!isNumber(accumulator) && !isDate(accumulator)) {
                    accumulator = value;
                }
                if (accumulator < value && (isNumber(value) || isDate(value))) {
                    accumulator = value;
                }
                return accumulator;
            },
            min: function (value, state) {
                var accumulator = state.accumulator;
                if (!isNumber(accumulator) && !isDate(accumulator)) {
                    accumulator = value;
                }
                if (accumulator > value && (isNumber(value) || isDate(value))) {
                    accumulator = value;
                }
                return accumulator;
            }
        };
        var PivotCubeBuilder = Class.extend({
            init: function (options) {
                this.options = extend({}, this.options, options);
                this.dimensions = this._normalizeDescriptors('field', this.options.dimensions);
                this.measures = this._normalizeDescriptors('name', this.options.measures);
            },
            _normalizeDescriptors: function (keyField, descriptors) {
                descriptors = descriptors || {};
                var fields = {};
                var field;
                if (toString.call(descriptors) === '[object Array]') {
                    for (var idx = 0, length = descriptors.length; idx < length; idx++) {
                        field = descriptors[idx];
                        if (typeof field === 'string') {
                            fields[field] = {};
                        } else if (field[keyField]) {
                            fields[field[keyField]] = field;
                        }
                    }
                    descriptors = fields;
                }
                return descriptors;
            },
            _rootTuples: function (rootNames, measureAggregators) {
                var aggregatorsLength = measureAggregators.length || 1;
                var dimensionsSchema = this.dimensions || [];
                var root, name, parts;
                var measureIdx = 0;
                var idx;
                var rootNamesLength = rootNames.length;
                var result = [];
                var keys = [];
                if (rootNamesLength || measureAggregators.length) {
                    for (measureIdx = 0; measureIdx < aggregatorsLength; measureIdx++) {
                        root = { members: [] };
                        for (idx = 0; idx < rootNamesLength; idx++) {
                            name = rootNames[idx];
                            parts = name.split('&');
                            root.members[root.members.length] = {
                                children: [],
                                caption: (dimensionsSchema[name] || {}).caption || 'All',
                                name: name,
                                levelName: name,
                                levelNum: '0',
                                hasChildren: true,
                                parentName: parts.length > 1 ? parts[0] : undefined,
                                hierarchy: name
                            };
                        }
                        if (aggregatorsLength > 1) {
                            root.members[root.members.length] = {
                                children: [],
                                caption: measureAggregators[measureIdx].caption,
                                name: measureAggregators[measureIdx].descriptor.name,
                                levelName: 'MEASURES',
                                levelNum: '0',
                                hasChildren: false,
                                parentName: undefined,
                                hierarchy: 'MEASURES'
                            };
                        }
                        result[result.length] = root;
                    }
                    keys.push(ROW_TOTAL_KEY);
                }
                return {
                    keys: keys,
                    tuples: result
                };
            },
            _expandedTuples: function (map, expanded, measureAggregators) {
                var aggregatorsLength = measureAggregators.length || 1;
                var dimensionsSchema = this.dimensions || [];
                var measureIdx;
                var tuple;
                var key;
                var mapItem;
                var current;
                var currentKeys;
                var accumulator = [];
                var accumulatorKeys = [];
                var memberInfo;
                var expandedNames;
                var parts;
                var name;
                var idx;
                for (key in map) {
                    mapItem = map[key];
                    memberInfo = this._findExpandedMember(expanded, mapItem.uniquePath);
                    current = accumulator[memberInfo.index] || [];
                    currentKeys = accumulatorKeys[memberInfo.index] || [];
                    expandedNames = memberInfo.member.names;
                    for (measureIdx = 0; measureIdx < aggregatorsLength; measureIdx++) {
                        tuple = { members: [] };
                        for (idx = 0; idx < expandedNames.length; idx++) {
                            if (idx === memberInfo.member.expandedIdx) {
                                tuple.members[tuple.members.length] = {
                                    children: [],
                                    caption: mapItem.value,
                                    name: mapItem.name,
                                    hasChildren: false,
                                    levelNum: 1,
                                    levelName: mapItem.parentName + mapItem.name,
                                    parentName: mapItem.parentName,
                                    hierarchy: mapItem.parentName + mapItem.name
                                };
                                if (measureIdx === 0) {
                                    currentKeys.push(buildPath(tuple, idx).join(''));
                                }
                            } else {
                                name = expandedNames[idx];
                                parts = name.split('&');
                                tuple.members[tuple.members.length] = {
                                    children: [],
                                    caption: (dimensionsSchema[name] || {}).caption || 'All',
                                    name: name,
                                    levelName: name,
                                    levelNum: '0',
                                    hasChildren: true,
                                    parentName: parts.length > 1 ? parts[0] : undefined,
                                    hierarchy: name
                                };
                            }
                        }
                        if (aggregatorsLength > 1) {
                            tuple.members[tuple.members.length] = {
                                children: [],
                                caption: measureAggregators[measureIdx].caption,
                                name: measureAggregators[measureIdx].descriptor.name,
                                levelName: 'MEASURES',
                                levelNum: '0',
                                hasChildren: true,
                                parentName: undefined,
                                hierarchy: 'MEASURES'
                            };
                        }
                        current[current.length] = tuple;
                    }
                    accumulator[memberInfo.index] = current;
                    accumulatorKeys[memberInfo.index] = currentKeys;
                }
                return {
                    keys: accumulatorKeys,
                    tuples: accumulator
                };
            },
            _findExpandedMember: function (members, parentName) {
                for (var idx = 0; idx < members.length; idx++) {
                    if (members[idx].uniquePath === parentName) {
                        return {
                            member: members[idx],
                            index: idx
                        };
                    }
                }
            },
            _asTuples: function (map, descriptor, measureAggregators) {
                measureAggregators = measureAggregators || [];
                var rootInfo = this._rootTuples(descriptor.root, measureAggregators);
                var expandedInfo = this._expandedTuples(map, descriptor.expanded, measureAggregators);
                return {
                    keys: [].concat.apply(rootInfo.keys, expandedInfo.keys),
                    tuples: [].concat.apply(rootInfo.tuples, expandedInfo.tuples)
                };
            },
            _measuresInfo: function (measures, rowAxis) {
                var idx = 0;
                var length = measures && measures.length;
                var aggregateNames = [];
                var resultFuncs = {};
                var formats = {};
                var descriptors = this.measures || {};
                var measure;
                var name;
                for (; idx < length; idx++) {
                    name = measures[idx].descriptor.name;
                    measure = descriptors[name] || {};
                    aggregateNames.push(name);
                    if (measure.result) {
                        resultFuncs[name] = measure.result;
                    }
                    if (measure.format) {
                        formats[name] = measure.format;
                    }
                }
                return {
                    names: aggregateNames,
                    formats: formats,
                    resultFuncs: resultFuncs,
                    rowAxis: rowAxis
                };
            },
            _toDataArray: function (map, measuresInfo, rowKeys, columnKeys) {
                var result = [];
                var aggregates;
                var name, i, j, k, n;
                var row, column, columnKey;
                var rowMeasureNamesLength = 1;
                var rowMeasureNames = [];
                var columnMeasureNames;
                var rowLength = rowKeys.length || 1;
                var columnLength = columnKeys.length || 1;
                if (measuresInfo.rowAxis) {
                    rowMeasureNames = measuresInfo.names;
                    rowMeasureNamesLength = rowMeasureNames.length;
                } else {
                    columnMeasureNames = measuresInfo.names;
                }
                for (i = 0; i < rowLength; i++) {
                    row = map[rowKeys[i] || ROW_TOTAL_KEY];
                    for (n = 0; n < rowMeasureNamesLength; n++) {
                        if (measuresInfo.rowAxis) {
                            columnMeasureNames = [rowMeasureNames[n]];
                        }
                        for (j = 0; j < columnLength; j++) {
                            columnKey = columnKeys[j] || ROW_TOTAL_KEY;
                            column = row.items[columnKey];
                            if (columnKey === ROW_TOTAL_KEY) {
                                aggregates = row.aggregates;
                            } else {
                                aggregates = column ? column.aggregates : {};
                            }
                            for (k = 0; k < columnMeasureNames.length; k++) {
                                name = columnMeasureNames[k];
                                this._addData(result, aggregates[name], measuresInfo.formats[name], measuresInfo.resultFuncs[name]);
                            }
                        }
                    }
                }
                return result;
            },
            _addData: function (result, value, format, resultFunc) {
                var fmtValue = '';
                var ordinal;
                if (value) {
                    value = resultFunc ? resultFunc(value) : value.accumulator;
                    fmtValue = format ? kendo.format(format, value) : value;
                }
                ordinal = result.length;
                result[ordinal] = {
                    ordinal: ordinal,
                    value: value || '',
                    fmtValue: fmtValue
                };
            },
            _matchDescriptors: function (dataItem, descriptor, getters) {
                var parts;
                var parentField;
                var expectedValue;
                var names = descriptor.names;
                var idx = descriptor.expandedIdx;
                var value;
                while (idx > 0) {
                    parts = names[--idx].split('&');
                    if (parts.length > 1) {
                        parentField = parts[0];
                        expectedValue = parts[1];
                        value = getters[parentField](dataItem);
                        value = value !== undefined && value !== null ? value.toString() : value;
                        if (value != expectedValue) {
                            return false;
                        }
                    }
                }
                return true;
            },
            _calculateAggregate: function (measureAggregators, aggregatorContext, totalItem) {
                var result = {};
                var state;
                var name;
                for (var measureIdx = 0; measureIdx < measureAggregators.length; measureIdx++) {
                    name = measureAggregators[measureIdx].descriptor.name;
                    state = totalItem.aggregates[name] || {};
                    state.accumulator = measureAggregators[measureIdx].aggregator(aggregatorContext, state);
                    result[name] = state;
                }
                return result;
            },
            _processColumns: function (measureAggregators, descriptors, getters, columns, aggregatorContext, rowTotal, state, updateColumn) {
                var value;
                var descriptor;
                var column;
                var totalItem;
                var key, name, parentName, path;
                var dataItem = aggregatorContext.dataItem;
                var idx = 0;
                for (; idx < descriptors.length; idx++) {
                    descriptor = descriptors[idx];
                    if (!this._matchDescriptors(dataItem, descriptor, getters)) {
                        continue;
                    }
                    path = descriptor.names.slice(0, descriptor.expandedIdx).join('');
                    name = descriptor.names[descriptor.expandedIdx];
                    value = getters[name](dataItem);
                    value = value !== undefined && value !== null ? value.toString() : value;
                    parentName = name;
                    name = name + '&' + value;
                    key = path + name;
                    column = columns[key] || {
                        index: state.columnIndex,
                        parentName: parentName,
                        name: name,
                        uniquePath: path + parentName,
                        value: value
                    };
                    totalItem = rowTotal.items[key] || { aggregates: {} };
                    rowTotal.items[key] = {
                        index: column.index,
                        aggregates: this._calculateAggregate(measureAggregators, aggregatorContext, totalItem)
                    };
                    if (updateColumn) {
                        if (!columns[key]) {
                            state.columnIndex++;
                        }
                        columns[key] = column;
                    }
                }
            },
            _measureAggregators: function (options) {
                var measureDescriptors = options.measures || [];
                var measures = this.measures || {};
                var aggregators = [];
                var descriptor, measure, idx, length;
                var defaultAggregate, aggregate;
                if (measureDescriptors.length) {
                    for (idx = 0, length = measureDescriptors.length; idx < length; idx++) {
                        descriptor = measureDescriptors[idx];
                        measure = measures[descriptor.name];
                        defaultAggregate = null;
                        if (measure) {
                            aggregate = measure.aggregate;
                            if (typeof aggregate === 'string') {
                                defaultAggregate = functions[aggregate.toLowerCase()];
                                if (!defaultAggregate) {
                                    throw new Error('There is no such aggregate function');
                                }
                                measure.aggregate = defaultAggregate.aggregate || defaultAggregate;
                                measure.result = defaultAggregate.result;
                            }
                            aggregators.push({
                                descriptor: descriptor,
                                caption: measure.caption,
                                result: measure.result,
                                aggregator: createAggregateGetter(measure)
                            });
                        }
                    }
                } else {
                    aggregators.push({
                        descriptor: { name: 'default' },
                        caption: 'default',
                        aggregator: function () {
                            return 1;
                        }
                    });
                }
                return aggregators;
            },
            _buildGetters: function (names) {
                var result = {};
                var parts;
                var name;
                for (var idx = 0; idx < names.length; idx++) {
                    name = names[idx];
                    parts = name.split('&');
                    if (parts.length > 1) {
                        result[parts[0]] = kendo.getter(parts[0], true);
                    } else {
                        result[name] = kendo.getter(normalizeName(name), true);
                    }
                }
                return result;
            },
            _parseDescriptors: function (descriptors) {
                var parsedDescriptors = parseDescriptors(descriptors);
                var rootNames = getRootNames(parsedDescriptors.root);
                var expanded = parsedDescriptors.expanded;
                var result = [];
                for (var idx = 0; idx < expanded.length; idx++) {
                    result.push(mapNames(expanded[idx].name, rootNames));
                }
                return {
                    root: rootNames,
                    expanded: result
                };
            },
            _filter: function (data, filter) {
                if (!filter) {
                    return data;
                }
                var expr;
                var idx = 0;
                var filters = filter.filters;
                for (; idx < filters.length; idx++) {
                    expr = filters[idx];
                    if (expr.operator === 'in') {
                        filters[idx] = this._normalizeFilter(expr);
                    }
                }
                return new kendo.data.Query(data).filter(filter).data;
            },
            _normalizeFilter: function (filter) {
                var value = filter.value.split(',');
                var result = [];
                if (!value.length) {
                    return value;
                }
                for (var idx = 0; idx < value.length; idx++) {
                    result.push({
                        field: filter.field,
                        operator: 'eq',
                        value: value[idx]
                    });
                }
                return {
                    logic: 'or',
                    filters: result
                };
            },
            process: function (data, options) {
                data = data || [];
                options = options || {};
                data = this._filter(data, options.filter);
                var measures = options.measures || [];
                var measuresRowAxis = options.measuresAxis === 'rows';
                var columnDescriptors = options.columns || [];
                var rowDescriptors = options.rows || [];
                if (!columnDescriptors.length && rowDescriptors.length && (!measures.length || measures.length && measuresRowAxis)) {
                    columnDescriptors = rowDescriptors;
                    rowDescriptors = [];
                    measuresRowAxis = false;
                }
                if (!columnDescriptors.length && !rowDescriptors.length) {
                    measuresRowAxis = false;
                }
                if (!columnDescriptors.length && measures.length) {
                    columnDescriptors = normalizeMembers(options.measures);
                }
                columnDescriptors = this._parseDescriptors(columnDescriptors);
                rowDescriptors = this._parseDescriptors(rowDescriptors);
                var aggregatedData = {};
                var columns = {};
                var rows = {};
                var rowValue;
                var state = { columnIndex: 0 };
                var measureAggregators = this._measureAggregators(options);
                var columnGetters = this._buildGetters(columnDescriptors.root);
                var rowGetters = this._buildGetters(rowDescriptors.root);
                var processed = false;
                var expandedColumns = columnDescriptors.expanded;
                var expandedRows = rowDescriptors.expanded;
                var dataItem;
                var aggregatorContext;
                var hasExpandedRows = expandedRows.length !== 0;
                var rowIdx, rowDescriptor, rowName, rowTotal;
                var key, path, parentName, value;
                var columnsInfo, rowsInfo;
                var length = data.length;
                var idx = 0;
                if (columnDescriptors.root.length || rowDescriptors.root.length) {
                    processed = true;
                    for (idx = 0; idx < length; idx++) {
                        dataItem = data[idx];
                        aggregatorContext = {
                            dataItem: dataItem,
                            index: idx
                        };
                        rowTotal = aggregatedData[ROW_TOTAL_KEY] || {
                            items: {},
                            aggregates: {}
                        };
                        this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, rowTotal, state, !hasExpandedRows);
                        rowTotal.aggregates = this._calculateAggregate(measureAggregators, aggregatorContext, rowTotal);
                        aggregatedData[ROW_TOTAL_KEY] = rowTotal;
                        for (rowIdx = 0; rowIdx < expandedRows.length; rowIdx++) {
                            rowDescriptor = expandedRows[rowIdx];
                            if (!this._matchDescriptors(dataItem, rowDescriptor, rowGetters)) {
                                this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, {
                                    items: {},
                                    aggregates: {}
                                }, state, true);
                                continue;
                            }
                            path = rowDescriptor.names.slice(0, rowDescriptor.expandedIdx).join('');
                            rowName = rowDescriptor.names[rowDescriptor.expandedIdx];
                            parentName = rowName;
                            rowValue = rowGetters[rowName](dataItem);
                            rowValue = rowValue !== undefined ? rowValue.toString() : rowValue;
                            rowName = rowName + '&' + rowValue;
                            key = path + rowName;
                            rows[key] = {
                                uniquePath: path + parentName,
                                parentName: parentName,
                                name: rowName,
                                value: rowValue
                            };
                            value = aggregatedData[key] || {
                                items: {},
                                aggregates: {}
                            };
                            this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, value, state, true);
                            value.aggregates = this._calculateAggregate(measureAggregators, aggregatorContext, value);
                            aggregatedData[key] = value;
                        }
                    }
                }
                if (processed && length) {
                    if (measureAggregators.length > 1 && (!options.columns || !options.columns.length)) {
                        columnDescriptors = {
                            root: [],
                            expanded: []
                        };
                    }
                    columnsInfo = this._asTuples(columns, columnDescriptors, measuresRowAxis ? [] : measureAggregators);
                    rowsInfo = this._asTuples(rows, rowDescriptors, measuresRowAxis ? measureAggregators : []);
                    columns = columnsInfo.tuples;
                    rows = rowsInfo.tuples;
                    aggregatedData = this._toDataArray(aggregatedData, this._measuresInfo(measureAggregators, measuresRowAxis), rowsInfo.keys, columnsInfo.keys);
                } else {
                    aggregatedData = columns = rows = [];
                }
                return {
                    axes: {
                        columns: { tuples: columns },
                        rows: { tuples: rows }
                    },
                    data: aggregatedData
                };
            }
        });
        var PivotTransport = Class.extend({
            init: function (options, transport) {
                this.transport = transport;
                this.options = transport.options || {};
                if (!this.transport.discover) {
                    if (isFunction(options.discover)) {
                        this.discover = options.discover;
                    }
                }
            },
            read: function (options) {
                return this.transport.read(options);
            },
            update: function (options) {
                return this.transport.update(options);
            },
            create: function (options) {
                return this.transport.create(options);
            },
            destroy: function (options) {
                return this.transport.destroy(options);
            },
            discover: function (options) {
                if (this.transport.discover) {
                    return this.transport.discover(options);
                }
                options.success({});
            },
            catalog: function (val) {
                var options = this.options || {};
                if (val === undefined) {
                    return (options.connection || {}).catalog;
                }
                var connection = options.connection || {};
                connection.catalog = val;
                this.options.connection = connection;
                $.extend(this.transport.options, { connection: connection });
            },
            cube: function (val) {
                var options = this.options || {};
                if (val === undefined) {
                    return (options.connection || {}).cube;
                }
                var connection = options.connection || {};
                connection.cube = val;
                this.options.connection = connection;
                extend(true, this.transport.options, { connection: connection });
            }
        });
        var PivotDataSource = DataSource.extend({
            init: function (options) {
                var cube = ((options || {}).schema || {}).cube;
                var measuresAxis = 'columns';
                var measures;
                var schema = {
                    axes: identity,
                    cubes: identity,
                    catalogs: identity,
                    measures: identity,
                    dimensions: identity,
                    hierarchies: identity,
                    levels: identity,
                    members: identity
                };
                if (cube) {
                    schema = $.extend(schema, this._cubeSchema(cube));
                    this.cubeBuilder = new PivotCubeBuilder(cube);
                }
                DataSource.fn.init.call(this, extend(true, {}, { schema: schema }, options));
                this.transport = new PivotTransport(this.options.transport || {}, this.transport);
                this._columns = normalizeMembers(this.options.columns);
                this._rows = normalizeMembers(this.options.rows);
                measures = this.options.measures || [];
                if (toString.call(measures) === '[object Object]') {
                    measuresAxis = measures.axis || 'columns';
                    measures = measures.values || [];
                }
                this._measures = normalizeMeasures(measures);
                this._measuresAxis = measuresAxis;
                this._skipNormalize = 0;
                this._axes = {};
            },
            _cubeSchema: function (cube) {
                return {
                    dimensions: function () {
                        var result = [];
                        var dimensions = cube.dimensions;
                        for (var key in dimensions) {
                            result.push({
                                name: key,
                                caption: dimensions[key].caption || key,
                                uniqueName: key,
                                defaultHierarchy: key,
                                type: 1
                            });
                        }
                        if (cube.measures) {
                            result.push({
                                name: MEASURES,
                                caption: MEASURES,
                                uniqueName: MEASURES,
                                type: 2
                            });
                        }
                        return result;
                    },
                    hierarchies: function () {
                        return [];
                    },
                    measures: function () {
                        var result = [];
                        var measures = cube.measures;
                        for (var key in measures) {
                            result.push({
                                name: key,
                                caption: key,
                                uniqueName: key,
                                aggregator: key
                            });
                        }
                        return result;
                    },
                    members: $.proxy(function (response, restrictions) {
                        var name = restrictions.levelUniqueName || restrictions.memberUniqueName;
                        var schemaData = this.options.schema.data;
                        var dataGetter = isFunction(schemaData) ? schemaData : kendo.getter(schemaData, true);
                        var data = this.options.data && dataGetter(this.options.data) || this._rawData || [];
                        var result = [];
                        var getter;
                        var value;
                        var idx = 0;
                        var distinct = {};
                        if (name) {
                            name = name.split('.')[0];
                        }
                        if (!restrictions.treeOp) {
                            result.push({
                                caption: cube.dimensions[name].caption || name,
                                childrenCardinality: '1',
                                dimensionUniqueName: name,
                                hierarchyUniqueName: name,
                                levelUniqueName: name,
                                name: name,
                                uniqueName: name
                            });
                            return result;
                        }
                        getter = kendo.getter(normalizeName(name), true);
                        for (; idx < data.length; idx++) {
                            value = getter(data[idx]);
                            if ((value || value === 0) && !distinct[value]) {
                                distinct[value] = true;
                                result.push({
                                    caption: value,
                                    childrenCardinality: '0',
                                    dimensionUniqueName: name,
                                    hierarchyUniqueName: name,
                                    levelUniqueName: name,
                                    name: value,
                                    uniqueName: value
                                });
                            }
                        }
                        return result;
                    }, this)
                };
            },
            options: {
                serverSorting: true,
                serverPaging: true,
                serverFiltering: true,
                serverGrouping: true,
                serverAggregates: true
            },
            catalog: function (val) {
                if (val === undefined) {
                    return this.transport.catalog();
                }
                this.transport.catalog(val);
                this._mergeState({});
                this._axes = {};
                this.data([]);
            },
            cube: function (val) {
                if (val === undefined) {
                    return this.transport.cube();
                }
                this.transport.cube(val);
                this._axes = {};
                this._mergeState({});
                this.data([]);
            },
            axes: function () {
                return this._axes;
            },
            columns: function (val) {
                if (val === undefined) {
                    return this._columns;
                }
                this._skipNormalize += 1;
                this._clearAxesData = true;
                this._columns = normalizeMembers(val);
                this.query({
                    columns: val,
                    rows: this.rowsAxisDescriptors(),
                    measures: this.measures(),
                    sort: this.sort(),
                    filter: this.filter()
                });
            },
            rows: function (val) {
                if (val === undefined) {
                    return this._rows;
                }
                this._skipNormalize += 1;
                this._clearAxesData = true;
                this._rows = normalizeMembers(val);
                this.query({
                    columns: this.columnsAxisDescriptors(),
                    rows: val,
                    measures: this.measures(),
                    sort: this.sort(),
                    filter: this.filter()
                });
            },
            measures: function (val) {
                if (val === undefined) {
                    return this._measures;
                }
                this._skipNormalize += 1;
                this._clearAxesData = true;
                this.query({
                    columns: this.columnsAxisDescriptors(),
                    rows: this.rowsAxisDescriptors(),
                    measures: normalizeMeasures(val),
                    sort: this.sort(),
                    filter: this.filter()
                });
            },
            measuresAxis: function () {
                return this._measuresAxis || 'columns';
            },
            _expandPath: function (path, axis) {
                var origin = axis === 'columns' ? 'columns' : 'rows';
                var other = axis === 'columns' ? 'rows' : 'columns';
                var members = normalizeMembers(path);
                var memberToExpand = getName(members[members.length - 1]);
                this._lastExpanded = origin;
                members = descriptorsForMembers(this.axes()[origin], members, this.measures());
                for (var idx = 0; idx < members.length; idx++) {
                    var memberName = getName(members[idx]);
                    if (memberName === memberToExpand) {
                        if (members[idx].expand) {
                            return;
                        }
                        members[idx].expand = true;
                    } else {
                        members[idx].expand = false;
                    }
                }
                var descriptors = {};
                descriptors[origin] = members;
                descriptors[other] = this._descriptorsForAxis(other);
                this._query(descriptors);
            },
            _descriptorsForAxis: function (axis) {
                var axes = this.axes();
                var descriptors = this[axis]() || [];
                if (axes && axes[axis] && axes[axis].tuples && axes[axis].tuples[0]) {
                    descriptors = descriptorsForAxes(axes[axis].tuples || []);
                }
                return descriptors;
            },
            columnsAxisDescriptors: function () {
                return this._descriptorsForAxis('columns');
            },
            rowsAxisDescriptors: function () {
                return this._descriptorsForAxis('rows');
            },
            _process: function (data, e) {
                this._view = data;
                e = e || {};
                e.items = e.items || this._view;
                this.trigger(CHANGE, e);
            },
            _query: function (options) {
                var that = this;
                if (!options) {
                    this._skipNormalize += 1;
                    this._clearAxesData = true;
                }
                return that.query(extend({}, {
                    page: that.page(),
                    pageSize: that.pageSize(),
                    sort: that.sort(),
                    filter: that.filter(),
                    group: that.group(),
                    aggregate: that.aggregate(),
                    columns: this.columnsAxisDescriptors(),
                    rows: this.rowsAxisDescriptors(),
                    measures: this.measures()
                }, options));
            },
            query: function (options) {
                var state = this._mergeState(options);
                if (this._data.length && this.cubeBuilder) {
                    this._params(state);
                    this._updateLocalData(this._pristineData);
                    return $.Deferred().resolve().promise();
                }
                return this.read(state);
            },
            _mergeState: function (options) {
                options = DataSource.fn._mergeState.call(this, options);
                if (options !== undefined) {
                    this._measures = normalizeMeasures(options.measures);
                    if (options.columns) {
                        options.columns = normalizeMembers(options.columns);
                    } else if (!options.columns) {
                        this._columns = [];
                    }
                    if (options.rows) {
                        options.rows = normalizeMembers(options.rows);
                    } else if (!options.rows) {
                        this._rows = [];
                    }
                }
                return options;
            },
            filter: function (val) {
                if (val === undefined) {
                    return this._filter;
                }
                this._skipNormalize += 1;
                this._clearAxesData = true;
                this._query({
                    filter: val,
                    page: 1
                });
            },
            expandColumn: function (path) {
                this._expandPath(path, 'columns');
            },
            expandRow: function (path) {
                this._expandPath(path, 'rows');
            },
            success: function (data) {
                var originalData;
                if (this.cubeBuilder) {
                    originalData = (this.reader.data(data) || []).slice(0);
                }
                DataSource.fn.success.call(this, data);
                if (originalData) {
                    this._pristineData = originalData;
                }
            },
            _processResult: function (data, axes) {
                if (this.cubeBuilder) {
                    var processedData = this.cubeBuilder.process(data, this._requestData);
                    data = processedData.data;
                    axes = processedData.axes;
                }
                var columnIndexes, rowIndexes;
                var tuples, resultAxis, measures, axisToSkip;
                var columnDescriptors = this.columns();
                var rowDescriptors = this.rows();
                var hasColumnTuples = axes.columns && axes.columns.tuples;
                if (!columnDescriptors.length && rowDescriptors.length && hasColumnTuples && (this._rowMeasures().length || !this.measures().length)) {
                    axes = {
                        columns: {},
                        rows: axes.columns
                    };
                }
                if (!columnDescriptors.length && !rowDescriptors.length && this.measuresAxis() === 'rows' && hasColumnTuples) {
                    axes = {
                        columns: {},
                        rows: axes.columns
                    };
                }
                this._axes = {
                    columns: normalizeAxis(this._axes.columns),
                    rows: normalizeAxis(this._axes.rows)
                };
                axes = {
                    columns: normalizeAxis(axes.columns),
                    rows: normalizeAxis(axes.rows)
                };
                columnIndexes = this._normalizeTuples(axes.columns.tuples, this._axes.columns.tuples, columnDescriptors, this._columnMeasures());
                rowIndexes = this._normalizeTuples(axes.rows.tuples, this._axes.rows.tuples, rowDescriptors, this._rowMeasures());
                if (this._skipNormalize > 0) {
                    this._skipNormalize -= 1;
                }
                if (!this.cubeBuilder) {
                    data = this._normalizeData({
                        columnsLength: axes.columns.tuples.length,
                        rowsLength: axes.rows.tuples.length,
                        columnIndexes: columnIndexes,
                        rowIndexes: rowIndexes,
                        data: data
                    });
                }
                if (this._lastExpanded == 'rows') {
                    tuples = axes.columns.tuples;
                    measures = this._columnMeasures();
                    resultAxis = validateAxis(axes.columns, this._axes.columns, measures);
                    if (resultAxis) {
                        axisToSkip = 'columns';
                        axes.columns = resultAxis;
                        adjustDataByColumn(tuples, resultAxis.tuples, axes.rows.tuples.length, measures, data);
                        if (!this.cubeBuilder) {
                            data = this._normalizeData({
                                columnsLength: membersCount(axes.columns.tuples, measures),
                                rowsLength: axes.rows.tuples.length,
                                data: data
                            });
                        }
                    }
                } else if (this._lastExpanded == 'columns') {
                    tuples = axes.rows.tuples;
                    measures = this._rowMeasures();
                    resultAxis = validateAxis(axes.rows, this._axes.rows, measures);
                    if (resultAxis) {
                        axisToSkip = 'rows';
                        axes.rows = resultAxis;
                        adjustDataByRow(tuples, resultAxis.tuples, axes.columns.tuples.length, measures, data);
                        if (!this.cubeBuilder) {
                            data = this._normalizeData({
                                columnsLength: membersCount(axes.rows.tuples, measures),
                                rowsLength: axes.columns.tuples.length,
                                data: data
                            });
                        }
                    }
                }
                this._lastExpanded = null;
                var result = this._mergeAxes(axes, data, axisToSkip);
                this._axes = result.axes;
                return result.data;
            },
            _readData: function (data) {
                var axes = this.reader.axes(data);
                var newData = this.reader.data(data);
                if (this.cubeBuilder) {
                    this._rawData = newData;
                }
                return this._processResult(newData, axes);
            },
            _createTuple: function (tuple, measure, buildRoot) {
                var members = tuple.members;
                var length = members.length;
                var root = { members: [] };
                var levelName, levelNum;
                var name, parentName;
                var hasChildren;
                var hierarchy;
                var caption;
                var member;
                var idx = 0;
                if (measure) {
                    length -= 1;
                }
                for (; idx < length; idx++) {
                    member = members[idx];
                    levelNum = Number(member.levelNum);
                    name = member.name;
                    parentName = member.parentName;
                    caption = member.caption || name;
                    hasChildren = member.hasChildren;
                    hierarchy = member.hierarchy;
                    levelName = member.levelName;
                    if (buildRoot) {
                        caption = 'All';
                        if (levelNum === 0) {
                            parentName = member.name;
                        } else {
                            levelNum -= 1;
                        }
                        hasChildren = true;
                        name = hierarchy = levelName = parentName;
                    }
                    root.members.push({
                        name: name,
                        children: [],
                        caption: caption,
                        levelName: levelName,
                        levelNum: levelNum.toString(),
                        hasChildren: hasChildren,
                        hierarchy: hierarchy,
                        parentName: !buildRoot ? parentName : ''
                    });
                }
                if (measure) {
                    root.members.push({
                        name: measure.name,
                        children: []
                    });
                }
                return root;
            },
            _hasRoot: function (target, source, descriptors) {
                if (source.length) {
                    return findExistingTuple(source, target).tuple;
                }
                var members = target.members;
                var member;
                var descriptor;
                var isRoot = true;
                var levelNum;
                for (var idx = 0, length = members.length; idx < length; idx++) {
                    member = members[idx];
                    levelNum = Number(member.levelNum) || 0;
                    descriptor = descriptors[idx];
                    if (!(levelNum === 0 || descriptor && member.name === getName(descriptor))) {
                        isRoot = false;
                        break;
                    }
                }
                return isRoot;
            },
            _mergeAxes: function (sourceAxes, data, axisToSkip) {
                var columnMeasures = this._columnMeasures();
                var rowMeasures = this._rowMeasures();
                var axes = this.axes();
                var startIndex, tuples;
                var oldRowsLength = membersCount(axes.rows.tuples, rowMeasures);
                var newRowsLength = sourceAxes.rows.tuples.length;
                var oldColumnsLength = membersCount(axes.columns.tuples, columnMeasures);
                var newColumnsLength = sourceAxes.columns.tuples.length;
                if (axisToSkip == 'columns') {
                    newColumnsLength = oldColumnsLength;
                    tuples = sourceAxes.columns.tuples;
                } else {
                    tuples = parseSource(sourceAxes.columns.tuples, columnMeasures);
                    data = prepareDataOnColumns(tuples, data);
                }
                var mergedColumns = mergeTuples(axes.columns.tuples, tuples, columnMeasures);
                if (axisToSkip == 'rows') {
                    newRowsLength = membersCount(sourceAxes.rows.tuples, rowMeasures);
                    tuples = sourceAxes.rows.tuples;
                } else {
                    tuples = parseSource(sourceAxes.rows.tuples, rowMeasures);
                    data = prepareDataOnRows(tuples, data);
                }
                var mergedRows = mergeTuples(axes.rows.tuples, tuples, rowMeasures);
                axes.columns.tuples = mergedColumns.tuples;
                axes.rows.tuples = mergedRows.tuples;
                if (oldColumnsLength !== membersCount(axes.columns.tuples, columnMeasures)) {
                    startIndex = mergedColumns.index + findDataIndex(mergedColumns.parsedRoot, mergedColumns.memberIndex, columnMeasures);
                    var offset = oldColumnsLength + newColumnsLength;
                    data = this._mergeColumnData(data, startIndex, newRowsLength, newColumnsLength, offset);
                } else if (oldRowsLength !== membersCount(axes.rows.tuples, rowMeasures)) {
                    startIndex = mergedRows.index + findDataIndex(mergedRows.parsedRoot, mergedRows.memberIndex, rowMeasures);
                    data = this._mergeRowData(data, startIndex, newRowsLength, newColumnsLength);
                }
                if (axes.columns.tuples.length === 0 && axes.rows.tuples.length === 0) {
                    data = [];
                }
                return {
                    axes: axes,
                    data: data
                };
            },
            _mergeColumnData: function (newData, columnIndex, rowsLength, columnsLength, offset) {
                var data = this.data().toJSON();
                var rowIndex, index, drop = 0, toAdd;
                var columnMeasures = Math.max(this._columnMeasures().length, 1);
                rowsLength = Math.max(rowsLength, 1);
                if (data.length > 0) {
                    drop = columnMeasures;
                    offset -= columnMeasures;
                }
                for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) {
                    index = columnIndex + rowIndex * offset;
                    toAdd = newData.splice(0, columnsLength);
                    toAdd.splice(0, drop);
                    [].splice.apply(data, [
                        index,
                        0
                    ].concat(toAdd));
                }
                return data;
            },
            _mergeRowData: function (newData, rowIndex, rowsLength, columnsLength) {
                var data = this.data().toJSON();
                var idx, dataIndex, toAdd;
                var rowMeasures = Math.max(this._rowMeasures().length, 1);
                columnsLength = Math.max(columnsLength, 1);
                if (data.length > 0) {
                    rowsLength -= rowMeasures;
                    newData.splice(0, columnsLength * rowMeasures);
                }
                for (idx = 0; idx < rowsLength; idx++) {
                    toAdd = newData.splice(0, columnsLength);
                    dataIndex = rowIndex * columnsLength + idx * columnsLength;
                    [].splice.apply(data, [
                        dataIndex,
                        0
                    ].concat(toAdd));
                }
                return data;
            },
            _columnMeasures: function () {
                var measures = this.measures();
                var columnMeasures = [];
                if (this.measuresAxis() === 'columns') {
                    if (this.columns().length === 0) {
                        columnMeasures = measures;
                    } else if (measures.length > 1) {
                        columnMeasures = measures;
                    }
                }
                return columnMeasures;
            },
            _rowMeasures: function () {
                var measures = this.measures();
                var rowMeasures = [];
                if (this.measuresAxis() === 'rows') {
                    if (this.rows().length === 0) {
                        rowMeasures = measures;
                    } else if (measures.length > 1) {
                        rowMeasures = measures;
                    }
                }
                return rowMeasures;
            },
            _updateLocalData: function (data, state) {
                if (this.cubeBuilder) {
                    if (state) {
                        this._requestData = state;
                    }
                    data = this._processResult(data);
                }
                this._data = this._observe(data);
                this._ranges = [];
                this._addRange(this._data);
                this._total = this._data.length;
                this._pristineTotal = this._total;
                this._process(this._data);
            },
            data: function (value) {
                var that = this;
                if (value !== undefined) {
                    this._pristineData = value.slice(0);
                    this._updateLocalData(value, {
                        columns: this.columns(),
                        rows: this.rows(),
                        measures: this.measures()
                    });
                } else {
                    return that._data;
                }
            },
            _normalizeTuples: function (tuples, source, descriptors, measures) {
                var length = measures.length || 1;
                var idx = 0;
                var roots = [];
                var indexes = {};
                var measureIdx = 0;
                var tuple, memberIdx, last;
                if (!tuples.length) {
                    return;
                }
                if (this._skipNormalize <= 0 && !this._hasRoot(tuples[0], source, descriptors)) {
                    this._skipNormalize = 0;
                    for (; idx < length; idx++) {
                        roots.push(this._createTuple(tuples[0], measures[idx], true));
                        indexes[idx] = idx;
                    }
                    tuples.splice.apply(tuples, [
                        0,
                        tuples.length
                    ].concat(roots).concat(tuples));
                    idx = length;
                }
                if (measures.length) {
                    last = tuple = tuples[idx];
                    memberIdx = tuple.members.length - 1;
                    while (tuple) {
                        if (measureIdx >= length) {
                            measureIdx = 0;
                        }
                        if (tuple.members[memberIdx].name !== measures[measureIdx].name) {
                            tuples.splice(idx, 0, this._createTuple(tuple, measures[measureIdx]));
                            indexes[idx] = idx;
                        }
                        idx += 1;
                        measureIdx += 1;
                        tuple = tuples[idx];
                        if (length > measureIdx && (!tuple || tupleName(last, memberIdx - 1) !== tupleName(tuple, memberIdx - 1))) {
                            for (; measureIdx < length; measureIdx++) {
                                tuples.splice(idx, 0, this._createTuple(last, measures[measureIdx]));
                                indexes[idx] = idx;
                                idx += 1;
                            }
                            tuple = tuples[idx];
                        }
                        last = tuple;
                    }
                }
                return indexes;
            },
            _addMissingDataItems: function (result, metadata) {
                while (metadata.rowIndexes[parseInt(result.length / metadata.columnsLength, 10)] !== undefined) {
                    for (var idx = 0; idx < metadata.columnsLength; idx++) {
                        result = addEmptyDataItem(result);
                    }
                }
                while (metadata.columnIndexes[result.length % metadata.columnsLength] !== undefined) {
                    result = addEmptyDataItem(result);
                }
                return result;
            },
            _normalizeOrdinals: function (result, dataItem, metadata) {
                var lastOrdinal = metadata.lastOrdinal;
                if (!dataItem) {
                    return addEmptyDataItem(result);
                }
                if (dataItem.ordinal - lastOrdinal > 1) {
                    lastOrdinal += 1;
                    while (lastOrdinal < dataItem.ordinal && result.length < metadata.length) {
                        result = this._addMissingDataItems(addEmptyDataItem(result), metadata);
                        lastOrdinal += 1;
                    }
                }
                dataItem.ordinal = result.length;
                result[result.length] = dataItem;
                return result;
            },
            _normalizeData: function (options) {
                var data = options.data;
                var dataIdx = 0;
                var dataItem;
                var result = [];
                var lastOrdinal;
                var length;
                options.lastOrdinal = 0;
                options.columnIndexes = options.columnIndexes || {};
                options.rowIndexes = options.rowIndexes || {};
                options.columnsLength = options.columnsLength || 1;
                options.rowsLength = options.rowsLength || 1;
                options.length = options.columnsLength * options.rowsLength;
                length = options.length;
                if (data.length === length) {
                    return data;
                }
                while (result.length < length) {
                    dataItem = data[dataIdx++];
                    if (dataItem) {
                        lastOrdinal = dataItem.ordinal;
                    }
                    result = this._normalizeOrdinals(this._addMissingDataItems(result, options), dataItem, options);
                    options.lastOrdinal = lastOrdinal;
                }
                return result;
            },
            discover: function (options, converter) {
                var that = this, transport = that.transport;
                return $.Deferred(function (deferred) {
                    transport.discover(extend({
                        success: function (response) {
                            response = that.reader.parse(response);
                            if (that._handleCustomErrors(response)) {
                                return;
                            }
                            if (converter) {
                                response = converter(response);
                            }
                            deferred.resolve(response);
                        },
                        error: function (response, status, error) {
                            deferred.reject(response);
                            that.error(response, status, error);
                        }
                    }, options));
                }).promise().done(function () {
                    that.trigger('schemaChange');
                });
            },
            schemaMeasures: function () {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaMeasures',
                        restrictions: {
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube()
                        }
                    }
                }, function (response) {
                    return that.reader.measures(response);
                });
            },
            schemaKPIs: function () {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaKPIs',
                        restrictions: {
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube()
                        }
                    }
                }, function (response) {
                    return that.reader.kpis(response);
                });
            },
            schemaDimensions: function () {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaDimensions',
                        restrictions: {
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube()
                        }
                    }
                }, function (response) {
                    return that.reader.dimensions(response);
                });
            },
            schemaHierarchies: function (dimensionName) {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaHierarchies',
                        restrictions: {
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube(),
                            dimensionUniqueName: dimensionName
                        }
                    }
                }, function (response) {
                    return that.reader.hierarchies(response);
                });
            },
            schemaLevels: function (hierarchyName) {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaLevels',
                        restrictions: {
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube(),
                            hierarchyUniqueName: hierarchyName
                        }
                    }
                }, function (response) {
                    return that.reader.levels(response);
                });
            },
            schemaCubes: function () {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaCubes',
                        restrictions: { catalogName: that.transport.catalog() }
                    }
                }, function (response) {
                    return that.reader.cubes(response);
                });
            },
            schemaCatalogs: function () {
                var that = this;
                return that.discover({ data: { command: 'schemaCatalogs' } }, function (response) {
                    return that.reader.catalogs(response);
                });
            },
            schemaMembers: function (restrictions) {
                var that = this;
                var success = function (restrictions) {
                    return function (response) {
                        return that.reader.members(response, restrictions);
                    };
                }(restrictions);
                return that.discover({
                    data: {
                        command: 'schemaMembers',
                        restrictions: extend({
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube()
                        }, restrictions)
                    }
                }, success);
            },
            _params: function (data) {
                if (this._clearAxesData) {
                    this._axes = {};
                    this._data = this._observe([]);
                    this._clearAxesData = false;
                    this.trigger(STATERESET);
                }
                var options = DataSource.fn._params.call(this, data);
                options = extend({
                    measures: this.measures(),
                    measuresAxis: this.measuresAxis(),
                    columns: this.columns(),
                    rows: this.rows()
                }, options);
                if (this.cubeBuilder) {
                    this._requestData = options;
                }
                return options;
            }
        });
        function addEmptyDataItem(result) {
            result[result.length] = {
                value: '',
                fmtValue: '',
                ordinal: result.length
            };
            return result;
        }
        function validateAxis(newAxis, axis, measures) {
            if (newAxis.tuples.length < membersCount(axis.tuples, measures)) {
                return axis;
            }
            return;
        }
        function adjustDataByColumn(sourceTuples, targetTuples, rowsLength, measures, data) {
            var columnIdx, rowIdx, dataIdx;
            var columnsLength = sourceTuples.length;
            var targetColumnsLength = membersCount(targetTuples, measures);
            var measuresLength = measures.length || 1;
            for (rowIdx = 0; rowIdx < rowsLength; rowIdx++) {
                for (columnIdx = 0; columnIdx < columnsLength; columnIdx++) {
                    dataIdx = tupleIndex(sourceTuples[columnIdx], targetTuples) * measuresLength;
                    dataIdx += columnIdx % measuresLength;
                    data[rowIdx * columnsLength + columnIdx].ordinal = rowIdx * targetColumnsLength + dataIdx;
                }
            }
        }
        function adjustDataByRow(sourceTuples, targetTuples, columnsLength, measures, data) {
            var columnIdx, rowIdx, dataIdx;
            var rowsLength = sourceTuples.length;
            var measuresLength = measures.length || 1;
            for (rowIdx = 0; rowIdx < rowsLength; rowIdx++) {
                dataIdx = tupleIndex(sourceTuples[rowIdx], targetTuples);
                dataIdx *= measuresLength;
                dataIdx += rowIdx % measuresLength;
                for (columnIdx = 0; columnIdx < columnsLength; columnIdx++) {
                    data[rowIdx * columnsLength + columnIdx].ordinal = dataIdx * columnsLength + columnIdx;
                }
            }
        }
        function tupleIndex(tuple, collection) {
            return findExistingTuple(collection, tuple).index;
        }
        function membersCount(tuples, measures) {
            if (!tuples.length) {
                return 0;
            }
            var queue = tuples.slice();
            var current = queue.shift();
            var result = 1;
            while (current) {
                if (current.members) {
                    [].push.apply(queue, current.members);
                } else if (current.children) {
                    if (!current.measure) {
                        result += current.children.length;
                    }
                    [].push.apply(queue, current.children);
                }
                current = queue.shift();
            }
            if (measures.length) {
                result = result * measures.length;
            }
            return result;
        }
        function normalizeAxis(axis) {
            if (!axis) {
                axis = { tuples: [] };
            }
            if (!axis.tuples) {
                axis.tuples = [];
            }
            return axis;
        }
        function findDataIndex(tuple, memberIndex, measures) {
            if (!tuple) {
                return 0;
            }
            var measuresLength = Math.max(measures.length, 1);
            var tuples = tuple.members.slice(0, memberIndex);
            var current = tuples.shift();
            var counter = measuresLength;
            while (current) {
                if (current.name === MEASURES) {
                    counter += measuresLength - 1;
                } else if (current.children) {
                    [].push.apply(tuples, current.children);
                } else {
                    counter++;
                    [].push.apply(tuples, current.members);
                }
                current = tuples.shift();
            }
            return counter;
        }
        function mergeTuples(target, source, measures) {
            if (!source[0]) {
                return {
                    parsedRoot: null,
                    tuples: target,
                    memberIndex: 0,
                    index: 0
                };
            }
            var result = findExistingTuple(target, source[0]);
            if (!result.tuple) {
                return {
                    parsedRoot: null,
                    tuples: source,
                    memberIndex: 0,
                    index: 0
                };
            }
            var targetMembers = result.tuple.members;
            var sourceMembers = source[0].members;
            var memberIndex = -1;
            if (targetMembers.length !== sourceMembers.length) {
                return {
                    parsedRoot: null,
                    tuples: source,
                    memberIndex: 0,
                    index: 0
                };
            }
            for (var idx = 0, length = targetMembers.length; idx < length; idx++) {
                if (!targetMembers[idx].measure && sourceMembers[idx].children[0]) {
                    if (memberIndex == -1 && sourceMembers[idx].children.length) {
                        memberIndex = idx;
                    }
                    targetMembers[idx].children = sourceMembers[idx].children;
                }
            }
            measures = Math.max(measures.length, 1);
            return {
                parsedRoot: result.tuple,
                index: result.index * measures,
                memberIndex: memberIndex,
                tuples: target
            };
        }
        function equalTuples(first, second) {
            var equal = true;
            var idx, length;
            first = first.members;
            second = second.members;
            for (idx = 0, length = first.length; idx < length; idx++) {
                if (first[idx].measure || second[idx].measure) {
                    continue;
                }
                equal = equal && getName(first[idx]) === getName(second[idx]);
            }
            return equal;
        }
        function findExistingTuple(tuples, toFind) {
            var idx, length, tuple, found, counter = 0;
            var memberIndex, membersLength, member;
            for (idx = 0, length = tuples.length; idx < length; idx++) {
                tuple = tuples[idx];
                if (equalTuples(tuple, toFind)) {
                    return {
                        tuple: tuple,
                        index: counter
                    };
                }
                counter++;
                for (memberIndex = 0, membersLength = tuple.members.length; memberIndex < membersLength; memberIndex++) {
                    member = tuple.members[memberIndex];
                    if (member.measure) {
                        continue;
                    }
                    found = findExistingTuple(member.children, toFind);
                    counter += found.index;
                    if (found.tuple) {
                        return {
                            tuple: found.tuple,
                            index: counter
                        };
                    }
                }
            }
            return { index: counter };
        }
        function addMembers(members, map) {
            var member, i, len, path = '';
            for (i = 0, len = members.length; i < len; i++) {
                member = members[i];
                path += member.name;
                if (!map[path]) {
                    map[path] = member;
                }
            }
        }
        function findParentMember(tuple, map) {
            var members = tuple.members;
            var i, len, member, path = '';
            var parentPath = '';
            var parentMember;
            for (i = 0, len = members.length; i < len; i++) {
                member = members[i];
                if (parentMember) {
                    if (map[path + member.name]) {
                        path += member.name;
                        parentMember = map[path];
                        continue;
                    } else if (map[path + member.parentName]) {
                        return map[path + member.parentName];
                    } else if (map[parentPath + member.parentName]) {
                        return map[parentPath + member.parentName];
                    } else {
                        return map[parentPath];
                    }
                }
                path += member.name;
                parentMember = map[member.parentName];
                if (!parentMember) {
                    parentMember = map[path];
                    if (!parentMember) {
                        return null;
                    }
                }
                if (parentMember) {
                    parentPath += parentMember.name;
                }
            }
            return parentMember;
        }
        function measurePosition(tuple, measures) {
            if (measures.length === 0) {
                return -1;
            }
            var measure = measures[0];
            var members = tuple.members;
            for (var idx = 0, len = members.length; idx < len; idx++) {
                if (members[idx].name == measure.name) {
                    return idx;
                }
            }
        }
        function normalizeTupleMeasures(tuple, index) {
            if (index < 0) {
                return;
            }
            var member = {
                name: MEASURES,
                measure: true,
                children: [$.extend({
                        members: [],
                        dataIndex: tuple.dataIndex
                    }, tuple.members[index])]
            };
            tuple.members.splice(index, 1, member);
            tuple.dataIndex = undefined;
        }
        function parseSource(tuples, measures) {
            if (tuples.length < 1) {
                return [];
            }
            var result = [];
            var map = {};
            var measureIndex = measurePosition(tuples[0], measures);
            for (var i = 0; i < tuples.length; i++) {
                var tuple = tuples[i];
                tuple.dataIndex = i;
                normalizeTupleMeasures(tuple, measureIndex);
                var parentMember = findParentMember(tuple, map);
                if (parentMember) {
                    if (measureIndex < 0 || !parentMember.measure) {
                        parentMember.children.push(tuple);
                    } else {
                        parentMember.children.push(tuple.members[measureIndex].children[0]);
                    }
                } else {
                    result.push(tuple);
                }
                addMembers(tuple.members, map);
            }
            return result;
        }
        function prepareDataOnRows(tuples, data) {
            if (!tuples || !tuples.length) {
                return data;
            }
            var result = [];
            var indices = buildDataIndices(tuples);
            var rowsLength = indices.length;
            var columnsLength = Math.max(data.length / rowsLength, 1);
            var rowIndex, columnIndex, targetIndex, sourceIndex;
            var calcIndex;
            for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) {
                targetIndex = columnsLength * rowIndex;
                sourceIndex = columnsLength * indices[rowIndex];
                for (columnIndex = 0; columnIndex < columnsLength; columnIndex++) {
                    calcIndex = parseInt(sourceIndex + columnIndex, 10);
                    result[parseInt(targetIndex + columnIndex, 10)] = data[calcIndex] || {
                        value: '',
                        fmtValue: '',
                        ordinal: calcIndex
                    };
                }
            }
            return result;
        }
        function prepareDataOnColumns(tuples, data) {
            if (!tuples || !tuples.length) {
                return data;
            }
            var result = [];
            var indices = buildDataIndices(tuples);
            var columnsLength = indices.length;
            var rowsLength = Math.max(data.length / columnsLength, 1);
            var columnIndex, rowIndex, dataIndex, calcIndex;
            for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) {
                dataIndex = columnsLength * rowIndex;
                for (columnIndex = 0; columnIndex < columnsLength; columnIndex++) {
                    calcIndex = indices[columnIndex] + dataIndex;
                    result[dataIndex + columnIndex] = data[calcIndex] || {
                        value: '',
                        fmtValue: '',
                        ordinal: calcIndex
                    };
                }
            }
            return result;
        }
        function buildDataIndices(tuples) {
            tuples = tuples.slice();
            var result = [];
            var tuple = tuples.shift();
            var idx, length, spliceIndex, children, member;
            while (tuple) {
                if (tuple.dataIndex !== undefined) {
                    result.push(tuple.dataIndex);
                }
                spliceIndex = 0;
                for (idx = 0, length = tuple.members.length; idx < length; idx++) {
                    member = tuple.members[idx];
                    children = member.children;
                    if (member.measure) {
                        [].splice.apply(tuples, [
                            0,
                            0
                        ].concat(children));
                    } else {
                        [].splice.apply(tuples, [
                            spliceIndex,
                            0
                        ].concat(children));
                    }
                    spliceIndex += children.length;
                }
                tuple = tuples.shift();
            }
            return result;
        }
        PivotDataSource.create = function (options) {
            options = options && options.push ? { data: options } : options;
            var dataSource = options || {}, data = dataSource.data;
            dataSource.data = data;
            if (!(dataSource instanceof PivotDataSource) && dataSource instanceof kendo.data.DataSource) {
                throw new Error('Incorrect DataSource type. Only PivotDataSource instances are supported');
            }
            return dataSource instanceof PivotDataSource ? dataSource : new PivotDataSource(dataSource);
        };
        function baseHierarchyPath(memberName) {
            var parts = memberName.split('.');
            if (parts.length > 2) {
                return parts[0] + '.' + parts[1];
            }
            return memberName;
        }
        function expandMemberDescriptor(names, sort) {
            var idx = names.length - 1;
            var name = names[idx];
            var sortDescriptor;
            sortDescriptor = sortDescriptorForMember(sort, name);
            if (sortDescriptor && sortDescriptor.dir) {
                name = 'ORDER(' + name + '.Children,' + sortDescriptor.field + '.CurrentMember.MEMBER_CAPTION,' + sortDescriptor.dir + ')';
            } else {
                name += '.Children';
            }
            names[idx] = name;
            return names;
        }
        function sortDescriptorForMember(sort, member) {
            for (var idx = 0, length = sort.length; idx < length; idx++) {
                if (member.indexOf(sort[idx].field) === 0) {
                    return sort[idx];
                }
            }
            return null;
        }
        function crossJoin(names) {
            var result = 'CROSSJOIN({';
            var r;
            if (names.length > 2) {
                r = names.pop();
                result += crossJoin(names);
            } else {
                result += names.shift();
                r = names.pop();
            }
            result += '},{';
            result += r;
            result += '})';
            return result;
        }
        function crossJoinCommand(members, measures) {
            var tmp = members.slice(0);
            if (measures.length > 1) {
                tmp.push('{' + measureNames(measures).join(',') + '}');
            }
            return crossJoin(tmp);
        }
        function measureNames(measures) {
            var idx = 0;
            var length = measures.length;
            var result = [];
            var measure;
            for (; idx < length; idx++) {
                measure = measures[idx];
                result.push(measure.name !== undefined ? measure.name : measure);
            }
            return result;
        }
        function getName(name) {
            name = name.name || name;
            if (toString.call(name) === '[object Array]') {
                name = name[name.length - 1];
            }
            return name;
        }
        function getRootNames(members) {
            var length = members.length;
            var names = [];
            var idx = 0;
            for (; idx < length; idx++) {
                names.push(members[idx].name[0]);
            }
            return names;
        }
        function mapNames(names, rootNames) {
            var name;
            var rootName;
            var j;
            var idx = 0;
            var length = names.length;
            var rootLength = rootNames.length;
            rootNames = rootNames.slice(0);
            for (; idx < length; idx++) {
                name = names[idx];
                for (j = 0; j < rootLength; j++) {
                    rootName = baseHierarchyPath(rootNames[j]);
                    if (name.indexOf(rootName) !== -1) {
                        rootNames[j] = name;
                        break;
                    }
                }
            }
            return {
                names: rootNames,
                expandedIdx: j,
                uniquePath: rootNames.slice(0, j + 1).join('')
            };
        }
        function parseDescriptors(members) {
            var expanded = [];
            var child = [];
            var root = [];
            var member;
            var j, l;
            var idx = 0;
            var length = members.length;
            var name;
            var hierarchyName;
            var found;
            for (; idx < length; idx++) {
                member = members[idx];
                name = member.name;
                found = false;
                if (toString.call(name) !== '[object Array]') {
                    member.name = name = [name];
                }
                if (name.length > 1) {
                    child.push(member);
                } else {
                    hierarchyName = baseHierarchyPath(name[0]);
                    for (j = 0, l = root.length; j < l; j++) {
                        if (root[j].name[0].indexOf(hierarchyName) === 0) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        root.push(member);
                    }
                    if (member.expand) {
                        expanded.push(member);
                    }
                }
            }
            expanded = expanded.concat(child);
            return {
                root: root,
                expanded: expanded
            };
        }
        function serializeMembers(members, measures, sort) {
            var command = '';
            members = members || [];
            var expanded = parseDescriptors(members);
            var root = expanded.root;
            var rootNames = getRootNames(root);
            var crossJoinCommands = [];
            expanded = expanded.expanded;
            var length = expanded.length;
            var idx = 0;
            var memberName;
            var names = [];
            if (rootNames.length > 1 || measures.length > 1) {
                crossJoinCommands.push(crossJoinCommand(rootNames, measures));
                for (; idx < length; idx++) {
                    memberName = expandMemberDescriptor(expanded[idx].name, sort);
                    names = mapNames(memberName, rootNames).names;
                    crossJoinCommands.push(crossJoinCommand(names, measures));
                }
                command += crossJoinCommands.join(',');
            } else {
                for (; idx < length; idx++) {
                    memberName = expandMemberDescriptor(expanded[idx].name, sort);
                    names.push(memberName[0]);
                }
                command += rootNames.concat(names).join(',');
            }
            return command;
        }
        var filterFunctionFormats = {
            contains: ', InStr({0}.CurrentMember.MEMBER_CAPTION,"{1}") > 0',
            doesnotcontain: ', InStr({0}.CurrentMember.MEMBER_CAPTION,"{1}")',
            startswith: ', Left({0}.CurrentMember.MEMBER_CAPTION,Len("{1}"))="{1}"',
            endswith: ', Right({0}.CurrentMember.MEMBER_CAPTION,Len("{1}"))="{1}"',
            eq: ', {0}.CurrentMember.MEMBER_CAPTION = "{1}"',
            neq: ', {0}.CurrentMember.MEMBER_CAPTION = "{1}"'
        };
        function serializeExpression(expression) {
            var command = '';
            var value = expression.value;
            var field = expression.field;
            var operator = expression.operator;
            if (operator == 'in') {
                command += '{';
                command += value;
                command += '}';
            } else {
                command += operator == 'neq' || operator == 'doesnotcontain' ? '-' : '';
                command += 'Filter(';
                command += field + '.MEMBERS';
                command += kendo.format(filterFunctionFormats[operator], field, value);
                command += ')';
            }
            return command;
        }
        function serializeFilters(filter, cube) {
            var command = '', current;
            var filters = filter.filters;
            var length = filters.length;
            var idx;
            for (idx = length - 1; idx >= 0; idx--) {
                current = 'SELECT (';
                current += serializeExpression(filters[idx]);
                current += ') ON 0';
                if (idx == length - 1) {
                    current += ' FROM [' + cube + ']';
                    command = current;
                } else {
                    command = current + ' FROM ( ' + command + ' )';
                }
            }
            return command;
        }
        function serializeOptions(parentTagName, options, capitalize) {
            var result = '';
            if (options) {
                result += '<' + parentTagName + '>';
                var value;
                for (var key in options) {
                    value = options[key];
                    if (capitalize) {
                        key = key.replace(/([A-Z]+(?=$|[A-Z][a-z])|[A-Z]?[a-z]+)/g, '$1_').toUpperCase().replace(/_$/, '');
                    }
                    result += '<' + key + '>' + value + '</' + key + '>';
                }
                result += '</' + parentTagName + '>';
            } else {
                result += '<' + parentTagName + '/>';
            }
            return result;
        }
        var xmlaDiscoverCommands = {
            schemaCubes: 'MDSCHEMA_CUBES',
            schemaCatalogs: 'DBSCHEMA_CATALOGS',
            schemaMeasures: 'MDSCHEMA_MEASURES',
            schemaDimensions: 'MDSCHEMA_DIMENSIONS',
            schemaHierarchies: 'MDSCHEMA_HIERARCHIES',
            schemaLevels: 'MDSCHEMA_LEVELS',
            schemaMembers: 'MDSCHEMA_MEMBERS',
            schemaKPIs: 'MDSCHEMA_KPIS'
        };
        var convertersMap = {
            read: function (options) {
                var command = '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Header/><Body><Execute xmlns="urn:schemas-microsoft-com:xml-analysis"><Command><Statement>';
                command += 'SELECT NON EMPTY {';
                var columns = options.columns || [];
                var rows = options.rows || [];
                var measures = options.measures || [];
                var measuresRowAxis = options.measuresAxis === 'rows';
                var sort = options.sort || [];
                if (!columns.length && rows.length && (!measures.length || measures.length && measuresRowAxis)) {
                    columns = rows;
                    rows = [];
                    measuresRowAxis = false;
                }
                if (!columns.length && !rows.length) {
                    measuresRowAxis = false;
                }
                if (columns.length) {
                    command += serializeMembers(columns, !measuresRowAxis ? measures : [], sort);
                } else if (measures.length && !measuresRowAxis) {
                    command += measureNames(measures).join(',');
                }
                command += '} DIMENSION PROPERTIES CHILDREN_CARDINALITY, PARENT_UNIQUE_NAME ON COLUMNS';
                if (rows.length || measuresRowAxis && measures.length > 1) {
                    command += ', NON EMPTY {';
                    if (rows.length) {
                        command += serializeMembers(rows, measuresRowAxis ? measures : [], sort);
                    } else {
                        command += measureNames(measures).join(',');
                    }
                    command += '} DIMENSION PROPERTIES CHILDREN_CARDINALITY, PARENT_UNIQUE_NAME ON ROWS';
                }
                if (options.filter) {
                    command += ' FROM ';
                    command += '(';
                    command += serializeFilters(options.filter, options.connection.cube);
                    command += ')';
                } else {
                    command += ' FROM [' + options.connection.cube + ']';
                }
                if (measures.length == 1 && columns.length) {
                    command += ' WHERE (' + measureNames(measures).join(',') + ')';
                }
                command += '</Statement></Command><Properties><PropertyList><Catalog>' + options.connection.catalog + '</Catalog><Format>Multidimensional</Format></PropertyList></Properties></Execute></Body></Envelope>';
                return command.replace(/\&/g, '&amp;');
            },
            discover: function (options) {
                options = options || {};
                var command = '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Header/><Body><Discover xmlns="urn:schemas-microsoft-com:xml-analysis">';
                command += '<RequestType>' + (xmlaDiscoverCommands[options.command] || options.command) + '</RequestType>';
                command += '<Restrictions>' + serializeOptions('RestrictionList', options.restrictions, true) + '</Restrictions>';
                if (options.connection && options.connection.catalog) {
                    options.properties = $.extend({}, { Catalog: options.connection.catalog }, options.properties);
                }
                command += '<Properties>' + serializeOptions('PropertyList', options.properties) + '</Properties>';
                command += '</Discover></Body></Envelope>';
                return command;
            }
        };
        var XmlaTransport = kendo.data.RemoteTransport.extend({
            init: function (options) {
                var originalOptions = options;
                options = this.options = extend(true, {}, this.options, options);
                kendo.data.RemoteTransport.call(this, options);
                if (isFunction(originalOptions.discover)) {
                    this.discover = originalOptions.discover;
                } else if (typeof originalOptions.discover === 'string') {
                    this.options.discover = { url: originalOptions.discover };
                } else if (!originalOptions.discover) {
                    this.options.discover = this.options.read;
                }
            },
            setup: function (options, type) {
                options.data = options.data || {};
                $.extend(true, options.data, { connection: this.options.connection });
                return kendo.data.RemoteTransport.fn.setup.call(this, options, type);
            },
            options: {
                read: {
                    dataType: 'text',
                    contentType: 'text/xml',
                    type: 'POST'
                },
                discover: {
                    dataType: 'text',
                    contentType: 'text/xml',
                    type: 'POST'
                },
                parameterMap: function (options, type) {
                    return convertersMap[type](options, type);
                }
            },
            discover: function (options) {
                return $.ajax(this.setup(options, 'discover'));
            }
        });
        function asArray(object) {
            if (object == null) {
                return [];
            }
            var type = toString.call(object);
            if (type !== '[object Array]') {
                return [object];
            }
            return object;
        }
        function translateAxis(axis) {
            var result = { tuples: [] };
            var tuples = asArray(kendo.getter('Tuples.Tuple', true)(axis));
            var captionGetter = kendo.getter('Caption[\'#text\']');
            var unameGetter = kendo.getter('UName[\'#text\']');
            var levelNameGetter = kendo.getter('LName[\'#text\']');
            var levelNumGetter = kendo.getter('LNum[\'#text\']');
            var childrenGetter = kendo.getter('CHILDREN_CARDINALITY[\'#text\']', true);
            var hierarchyGetter = kendo.getter('[\'@Hierarchy\']');
            var parentNameGetter = kendo.getter('PARENT_UNIQUE_NAME[\'#text\']', true);
            for (var idx = 0; idx < tuples.length; idx++) {
                var members = [];
                var member = asArray(tuples[idx].Member);
                for (var memberIdx = 0; memberIdx < member.length; memberIdx++) {
                    members.push({
                        children: [],
                        caption: captionGetter(member[memberIdx]),
                        name: unameGetter(member[memberIdx]),
                        levelName: levelNameGetter(member[memberIdx]),
                        levelNum: levelNumGetter(member[memberIdx]),
                        hasChildren: parseInt(childrenGetter(member[memberIdx]), 10) > 0,
                        parentName: parentNameGetter(member[memberIdx]),
                        hierarchy: hierarchyGetter(member[memberIdx])
                    });
                }
                result.tuples.push({ members: members });
            }
            return result;
        }
        var schemaDataReaderMap = {
            cubes: {
                name: kendo.getter('CUBE_NAME[\'#text\']', true),
                caption: kendo.getter('CUBE_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                type: kendo.getter('CUBE_TYPE[\'#text\']', true)
            },
            catalogs: {
                name: kendo.getter('CATALOG_NAME[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true)
            },
            measures: {
                name: kendo.getter('MEASURE_NAME[\'#text\']', true),
                caption: kendo.getter('MEASURE_CAPTION[\'#text\']', true),
                uniqueName: kendo.getter('MEASURE_UNIQUE_NAME[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                aggregator: kendo.getter('MEASURE_AGGREGATOR[\'#text\']', true),
                groupName: kendo.getter('MEASUREGROUP_NAME[\'#text\']', true),
                displayFolder: kendo.getter('MEASURE_DISPLAY_FOLDER[\'#text\']', true),
                defaultFormat: kendo.getter('DEFAULT_FORMAT_STRING[\'#text\']', true)
            },
            kpis: {
                name: kendo.getter('KPI_NAME[\'#text\']', true),
                caption: kendo.getter('KPI_CAPTION[\'#text\']', true),
                value: kendo.getter('KPI_VALUE[\'#text\']', true),
                goal: kendo.getter('KPI_GOAL[\'#text\']', true),
                status: kendo.getter('KPI_STATUS[\'#text\']', true),
                trend: kendo.getter('KPI_TREND[\'#text\']', true),
                statusGraphic: kendo.getter('KPI_STATUS_GRAPHIC[\'#text\']', true),
                trendGraphic: kendo.getter('KPI_TREND_GRAPHIC[\'#text\']', true),
                description: kendo.getter('KPI_DESCRIPTION[\'#text\']', true),
                groupName: kendo.getter('MEASUREGROUP_NAME[\'#text\']', true)
            },
            dimensions: {
                name: kendo.getter('DIMENSION_NAME[\'#text\']', true),
                caption: kendo.getter('DIMENSION_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                uniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                defaultHierarchy: kendo.getter('DEFAULT_HIERARCHY[\'#text\']', true),
                type: kendo.getter('DIMENSION_TYPE[\'#text\']', true)
            },
            hierarchies: {
                name: kendo.getter('HIERARCHY_NAME[\'#text\']', true),
                caption: kendo.getter('HIERARCHY_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                uniqueName: kendo.getter('HIERARCHY_UNIQUE_NAME[\'#text\']', true),
                dimensionUniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                displayFolder: kendo.getter('HIERARCHY_DISPLAY_FOLDER[\'#text\']', true),
                origin: kendo.getter('HIERARCHY_ORIGIN[\'#text\']', true),
                defaultMember: kendo.getter('DEFAULT_MEMBER[\'#text\']', true)
            },
            levels: {
                name: kendo.getter('LEVEL_NAME[\'#text\']', true),
                caption: kendo.getter('LEVEL_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                uniqueName: kendo.getter('LEVEL_UNIQUE_NAME[\'#text\']', true),
                dimensionUniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                displayFolder: kendo.getter('LEVEL_DISPLAY_FOLDER[\'#text\']', true),
                orderingProperty: kendo.getter('LEVEL_ORDERING_PROPERTY[\'#text\']', true),
                origin: kendo.getter('LEVEL_ORIGIN[\'#text\']', true),
                hierarchyUniqueName: kendo.getter('HIERARCHY_UNIQUE_NAME[\'#text\']', true)
            },
            members: {
                name: kendo.getter('MEMBER_NAME[\'#text\']', true),
                caption: kendo.getter('MEMBER_CAPTION[\'#text\']', true),
                uniqueName: kendo.getter('MEMBER_UNIQUE_NAME[\'#text\']', true),
                dimensionUniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                hierarchyUniqueName: kendo.getter('HIERARCHY_UNIQUE_NAME[\'#text\']', true),
                levelUniqueName: kendo.getter('LEVEL_UNIQUE_NAME[\'#text\']', true),
                childrenCardinality: kendo.getter('CHILDREN_CARDINALITY[\'#text\']', true)
            }
        };
        var xmlaReaderMethods = [
            'axes',
            'catalogs',
            'cubes',
            'dimensions',
            'hierarchies',
            'levels',
            'measures'
        ];
        var XmlaDataReader = kendo.data.XmlDataReader.extend({
            init: function (options) {
                kendo.data.XmlDataReader.call(this, options);
                this._extend(options);
            },
            _extend: function (options) {
                var idx = 0;
                var length = xmlaReaderMethods.length;
                var methodName;
                var option;
                for (; idx < length; idx++) {
                    methodName = xmlaReaderMethods[idx];
                    option = options[methodName];
                    if (option && option !== identity) {
                        this[methodName] = option;
                    }
                }
            },
            parse: function (xml) {
                var result = kendo.data.XmlDataReader.fn.parse(xml.replace(/<(\/?)(\w|-)+:/g, '<$1'));
                return kendo.getter('[\'Envelope\'][\'Body\']', true)(result);
            },
            errors: function (root) {
                var fault = kendo.getter('[\'Fault\']', true)(root);
                if (fault) {
                    return [{
                            faultstring: kendo.getter('faultstring[\'#text\']', true)(fault),
                            faultcode: kendo.getter('faultcode[\'#text\']', true)(fault)
                        }];
                }
                return null;
            },
            axes: function (root) {
                root = kendo.getter('ExecuteResponse["return"].root', true)(root);
                var axes = asArray(kendo.getter('Axes.Axis', true)(root));
                var axis;
                var result = {
                    columns: {},
                    rows: {}
                };
                for (var idx = 0; idx < axes.length; idx++) {
                    axis = axes[idx];
                    if (axis['@name'].toLowerCase() !== 'sliceraxis') {
                        if (!result.columns.tuples) {
                            result.columns = translateAxis(axis);
                        } else {
                            result.rows = translateAxis(axis);
                        }
                    }
                }
                return result;
            },
            data: function (root) {
                root = kendo.getter('ExecuteResponse["return"].root', true)(root);
                var cells = asArray(kendo.getter('CellData.Cell', true)(root));
                var result = [];
                var ordinalGetter = kendo.getter('[\'@CellOrdinal\']');
                var valueGetter = kendo.getter('Value[\'#text\']');
                var fmtValueGetter = kendo.getter('FmtValue[\'#text\']');
                for (var idx = 0; idx < cells.length; idx++) {
                    result.push({
                        value: valueGetter(cells[idx]),
                        fmtValue: fmtValueGetter(cells[idx]),
                        ordinal: parseInt(ordinalGetter(cells[idx]), 10)
                    });
                }
                return result;
            },
            _mapSchema: function (root, getters) {
                root = kendo.getter('DiscoverResponse["return"].root', true)(root);
                var rows = asArray(kendo.getter('row', true)(root));
                var result = [];
                for (var idx = 0; idx < rows.length; idx++) {
                    var obj = {};
                    for (var key in getters) {
                        obj[key] = getters[key](rows[idx]);
                    }
                    result.push(obj);
                }
                return result;
            },
            measures: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.measures);
            },
            kpis: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.kpis);
            },
            hierarchies: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.hierarchies);
            },
            levels: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.levels);
            },
            dimensions: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.dimensions);
            },
            cubes: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.cubes);
            },
            catalogs: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.catalogs);
            },
            members: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.members);
            }
        });
        extend(true, kendo.data, {
            PivotDataSource: PivotDataSource,
            XmlaTransport: XmlaTransport,
            XmlaDataReader: XmlaDataReader,
            PivotCubeBuilder: PivotCubeBuilder,
            transports: { xmla: XmlaTransport },
            readers: { xmla: XmlaDataReader }
        });
        var sortExpr = function (expressions, name) {
            if (!expressions) {
                return null;
            }
            for (var idx = 0, length = expressions.length; idx < length; idx++) {
                if (expressions[idx].field === name) {
                    return expressions[idx];
                }
            }
            return null;
        };
        var removeExpr = function (expressions, name) {
            var result = [];
            for (var idx = 0, length = expressions.length; idx < length; idx++) {
                if (expressions[idx].field !== name) {
                    result.push(expressions[idx]);
                }
            }
            return result;
        };
        kendo.ui.PivotSettingTarget = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.element.addClass('k-pivot-setting');
                that.dataSource = kendo.data.PivotDataSource.create(options.dataSource);
                that._refreshHandler = $.proxy(that.refresh, that);
                that.dataSource.first(CHANGE, that._refreshHandler);
                if (!options.template) {
                    that.options.template = '<div data-' + kendo.ns + 'name="${data.name || data}">${data.name || data}' + (that.options.enabled ? '<a class="k-button k-button-icon k-bare"><span class="k-icon k-i-close k-setting-delete"></span></a>' : '') + '</div>';
                }
                that.template = kendo.template(that.options.template);
                that.emptyTemplate = kendo.template(that.options.emptyTemplate);
                that._sortable();
                that.element.on('click' + NS, '.k-button,.k-item', function (e) {
                    var target = $(e.target);
                    var name = target.closest('[' + kendo.attr('name') + ']').attr(kendo.attr('name'));
                    if (!name) {
                        return;
                    }
                    if (target.hasClass('k-i-close')) {
                        that.remove(name);
                    } else if (that.options.sortable && target[0] === e.currentTarget) {
                        that.sort({
                            field: name,
                            dir: target.find('.k-i-sort-asc-sm')[0] ? 'desc' : 'asc'
                        });
                    }
                });
                if (options.filterable || options.sortable) {
                    that.fieldMenu = new ui.PivotFieldMenu(that.element, {
                        messages: that.options.messages.fieldMenu,
                        filter: '.k-setting-fieldmenu',
                        filterable: options.filterable,
                        sortable: options.sortable,
                        dataSource: that.dataSource
                    });
                }
                that.refresh();
            },
            options: {
                name: 'PivotSettingTarget',
                template: null,
                filterable: false,
                sortable: false,
                emptyTemplate: '<div class=\'k-empty\'>${data}</div>',
                setting: 'columns',
                enabled: true,
                messages: { empty: 'Drop Fields Here' }
            },
            setDataSource: function (dataSource) {
                this.dataSource.unbind(CHANGE, this._refreshHandler);
                this.dataSource = this.options.dataSource = dataSource;
                if (this.fieldMenu) {
                    this.fieldMenu.setDataSource(dataSource);
                }
                dataSource.first(CHANGE, this._refreshHandler);
                this.refresh();
            },
            _sortable: function () {
                var that = this;
                if (that.options.enabled) {
                    this.sortable = this.element.kendoSortable({
                        connectWith: this.options.connectWith,
                        hint: that.options.hint,
                        cursor: 'move',
                        start: function (e) {
                            e.item.focus().blur();
                        },
                        change: function (e) {
                            var name = e.item.attr(kendo.attr('name'));
                            if (e.action == 'receive') {
                                that.add(name);
                            } else if (e.action == 'remove') {
                                that.remove(name);
                            } else if (e.action == 'sort') {
                                that.move(name, e.newIndex);
                            }
                        }
                    }).data('kendoSortable');
                }
            },
            _indexOf: function (name, items) {
                var idx, length, index = -1;
                for (idx = 0, length = items.length; idx < length; idx++) {
                    if (getName(items[idx]) === name) {
                        index = idx;
                        break;
                    }
                }
                return index;
            },
            _isKPI: function (data) {
                return data.type === 'kpi' || data.measure;
            },
            validate: function (data) {
                var isMeasure = data.type == 2 || 'aggregator' in data || this._isKPI(data);
                if (isMeasure) {
                    return this.options.setting === 'measures';
                }
                if (this.options.setting === 'measures') {
                    return isMeasure;
                }
                var items = this.dataSource[this.options.setting]();
                var name = data.defaultHierarchy || data.uniqueName;
                if (this._indexOf(name, items) > -1) {
                    return false;
                }
                items = this.dataSource[this.options.setting === 'columns' ? 'rows' : 'columns']();
                if (this._indexOf(name, items) > -1) {
                    return false;
                }
                return true;
            },
            add: function (name) {
                var items = this.dataSource[this.options.setting]();
                var i, l;
                name = $.isArray(name) ? name.slice(0) : [name];
                for (i = 0, l = name.length; i < l; i++) {
                    if (this._indexOf(name[i], items) !== -1) {
                        name.splice(i, 1);
                        i -= 1;
                        l -= 1;
                    }
                }
                if (name.length) {
                    items = items.concat(name);
                    this.dataSource[this.options.setting](items);
                }
            },
            move: function (name, index) {
                var items = this.dataSource[this.options.setting]();
                var idx = this._indexOf(name, items);
                if (idx > -1) {
                    name = items.splice(idx, 1)[0];
                    items.splice(index, 0, name);
                    this.dataSource[this.options.setting](items);
                }
            },
            remove: function (name) {
                var items = this.dataSource[this.options.setting]();
                var idx = this._indexOf(name, items);
                var sortExpressions = this.dataSource.sort();
                var filter = this.dataSource.filter();
                if (idx > -1) {
                    if (filter) {
                        filter.filters = removeExpr(filter.filters, name);
                        this.dataSource._filter.filters = filter.filters;
                        if (!filter.filters.length) {
                            this.dataSource._filter = null;
                        }
                    }
                    if (sortExpressions) {
                        sortExpressions = removeExpr(sortExpressions, name);
                        this.dataSource._sort = sortExpressions;
                    }
                    items.splice(idx, 1);
                    this.dataSource[this.options.setting](items);
                }
            },
            sort: function (expr) {
                var sortable = this.options.sortable;
                var allowUnsort = sortable === true || sortable.allowUnsort;
                var skipExpr = allowUnsort && expr.dir === 'asc';
                var expressions = this.dataSource.sort() || [];
                var result = removeExpr(expressions, expr.field);
                if (skipExpr && expressions.length !== result.length) {
                    expr = null;
                }
                if (expr) {
                    result.push(expr);
                }
                this.dataSource.sort(result);
            },
            refresh: function () {
                var html = '';
                var items = this.dataSource[this.options.setting]();
                var length = items.length;
                var idx = 0;
                var item;
                if (length) {
                    for (; idx < length; idx++) {
                        item = items[idx];
                        item = item.name === undefined ? { name: item } : item;
                        html += this.template(extend({ sortIcon: this._sortIcon(item.name) }, item));
                    }
                } else {
                    html = this.emptyTemplate(this.options.messages.empty);
                }
                this.element.html(html);
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.dataSource.unbind(CHANGE, this._refreshHandler);
                this.element.off(NS);
                if (this.sortable) {
                    this.sortable.destroy();
                }
                if (this.fieldMenu) {
                    this.fieldMenu.destroy();
                }
                this.element = null;
                this._refreshHandler = null;
            },
            _sortIcon: function (name) {
                var expressions = this.dataSource.sort();
                var expr = sortExpr(expressions, getName(name));
                var icon = '';
                if (expr) {
                    icon = 'k-i-sort-' + expr.dir;
                }
                return icon;
            }
        });
        var PivotGrid = Widget.extend({
            init: function (element, options) {
                var that = this;
                var columnBuilder;
                var rowBuilder;
                Widget.fn.init.call(that, element, options);
                that._dataSource();
                that._bindConfigurator();
                that._wrapper();
                that._createLayout();
                that._columnBuilder = columnBuilder = new ColumnBuilder();
                that._rowBuilder = rowBuilder = new RowBuilder();
                that._contentBuilder = new ContentBuilder();
                that._templates();
                that.columnsHeader.add(that.rowsHeader).on('click', 'span.k-icon', function () {
                    var button = $(this);
                    var builder = columnBuilder;
                    var action = 'expandColumn';
                    var eventName;
                    var path = button.attr(kendo.attr('path'));
                    var eventArgs = {
                        axis: 'columns',
                        path: $.parseJSON(path)
                    };
                    if (button.parent().is('td')) {
                        builder = rowBuilder;
                        action = 'expandRow';
                        eventArgs.axis = 'rows';
                    }
                    var expanded = button.hasClass(STATE_EXPANDED);
                    var metadata = builder.metadata[path];
                    var request = metadata.expanded === undefined;
                    eventName = expanded ? COLLAPSEMEMBER : EXPANDMEMBER;
                    eventArgs.childrenLoaded = metadata.maxChildren > metadata.children;
                    if (that.trigger(eventName, eventArgs)) {
                        return;
                    }
                    builder.metadata[path].expanded = !expanded;
                    button.toggleClass(STATE_EXPANDED, !expanded).toggleClass(STATE_COLLAPSED, expanded);
                    if (!expanded && request) {
                        that.dataSource[action](eventArgs.path);
                    } else {
                        that.refresh();
                    }
                });
                that._scrollable();
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                }
                kendo.notify(that);
            },
            events: [
                DATABINDING,
                DATABOUND,
                EXPANDMEMBER,
                COLLAPSEMEMBER
            ],
            options: {
                name: 'PivotGrid',
                autoBind: true,
                reorderable: true,
                filterable: false,
                sortable: false,
                height: null,
                columnWidth: 100,
                configurator: '',
                columnHeaderTemplate: null,
                rowHeaderTemplate: null,
                dataCellTemplate: null,
                kpiStatusTemplate: null,
                kpiTrendTemplate: null,
                messages: {
                    measureFields: 'Drop Data Fields Here',
                    columnFields: 'Drop Column Fields Here',
                    rowFields: 'Drop Rows Fields Here'
                }
            },
            _templates: function () {
                var columnTemplate = this.options.columnHeaderTemplate;
                var rowTemplate = this.options.rowHeaderTemplate;
                var dataTemplate = this.options.dataCellTemplate;
                var kpiStatusTemplate = this.options.kpiStatusTemplate;
                var kpiTrendTemplate = this.options.kpiTrendTemplate;
                this._columnBuilder.template = kendo.template(columnTemplate || HEADER_TEMPLATE, { useWithBlock: !!columnTemplate });
                this._contentBuilder.dataTemplate = kendo.template(dataTemplate || DATACELL_TEMPLATE, { useWithBlock: !!dataTemplate });
                this._contentBuilder.kpiStatusTemplate = kendo.template(kpiStatusTemplate || KPISTATUS_TEMPLATE, { useWithBlock: !!kpiStatusTemplate });
                this._contentBuilder.kpiTrendTemplate = kendo.template(kpiTrendTemplate || KPITREND_TEMPLATE, { useWithBlock: !!kpiTrendTemplate });
                this._rowBuilder.template = kendo.template(rowTemplate || HEADER_TEMPLATE, { useWithBlock: !!rowTemplate });
            },
            _bindConfigurator: function () {
                var configurator = this.options.configurator;
                if (configurator) {
                    $(configurator).kendoPivotConfigurator('setDataSource', this.dataSource);
                }
            },
            cellInfoByElement: function (element) {
                element = $(element);
                return this.cellInfo(element.index(), element.parent('tr').index());
            },
            cellInfo: function (columnIndex, rowIndex) {
                var contentBuilder = this._contentBuilder;
                var columnInfo = contentBuilder.columnIndexes[columnIndex || 0];
                var rowInfo = contentBuilder.rowIndexes[rowIndex || 0];
                var dataIndex;
                if (!columnInfo || !rowInfo) {
                    return null;
                }
                dataIndex = rowInfo.index * contentBuilder.rowLength + columnInfo.index;
                return {
                    columnTuple: columnInfo.tuple,
                    rowTuple: rowInfo.tuple,
                    measure: columnInfo.measure || rowInfo.measure,
                    dataItem: this.dataSource.view()[dataIndex]
                };
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                if (this.measuresTarget) {
                    this.measuresTarget.setDataSource(dataSource);
                }
                if (this.rowsTarget) {
                    this.rowsTarget.setDataSource(dataSource);
                }
                if (this.columnsTarget) {
                    this.columnsTarget.setDataSource(dataSource);
                }
                this._bindConfigurator();
                if (this.options.autoBind) {
                    dataSource.fetch();
                }
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._templates();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                clearTimeout(this._headerReflowTimeout);
            },
            _dataSource: function () {
                var that = this;
                var dataSource = that.options.dataSource;
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                if (that.dataSource && this._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(STATERESET, that._stateResetHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler);
                } else {
                    that._refreshHandler = $.proxy(that.refresh, that);
                    that._progressHandler = $.proxy(that._requestStart, that);
                    that._stateResetHandler = $.proxy(that._stateReset, that);
                    that._errorHandler = $.proxy(that._error, that);
                }
                that.dataSource = kendo.data.PivotDataSource.create(dataSource).bind(CHANGE, that._refreshHandler).bind(PROGRESS, that._progressHandler).bind(STATERESET, that._stateResetHandler).bind(ERROR, that._errorHandler);
            },
            _error: function () {
                this._progress(false);
            },
            _requestStart: function () {
                this._progress(true);
            },
            _stateReset: function () {
                this._columnBuilder.reset();
                this._rowBuilder.reset();
            },
            _wrapper: function () {
                var height = this.options.height;
                this.wrapper = this.element.addClass('k-widget k-pivot');
                if (height) {
                    this.wrapper.css('height', height);
                }
            },
            _measureFields: function () {
                this.measureFields = $(DIV).addClass('k-pivot-toolbar k-header k-settings-measures');
                this.measuresTarget = this._createSettingTarget(this.measureFields, {
                    setting: 'measures',
                    messages: { empty: this.options.messages.measureFields }
                });
            },
            _createSettingTarget: function (element, options) {
                var template = '<span tabindex="0" class="k-button" data-' + kendo.ns + 'name="${data.name}">${data.name}';
                var sortable = options.sortable;
                var icons = '';
                if (sortable) {
                    icons += '#if (data.sortIcon) {#';
                    icons += '<span class="k-icon ${data.sortIcon}-sm"></span>';
                    icons += '#}#';
                }
                if (options.filterable || sortable) {
                    icons += '<span class="k-icon k-i-more-vertical k-setting-fieldmenu"></span>';
                }
                if (this.options.reorderable) {
                    icons += '<span class="k-icon k-i-close k-setting-delete"></span>';
                }
                if (icons) {
                    template += '<span class="k-field-actions">' + icons + '</span>';
                }
                template += '</span>';
                return new kendo.ui.PivotSettingTarget(element, $.extend({
                    template: template,
                    emptyTemplate: '<span class="k-empty">${data}</span>',
                    enabled: this.options.reorderable,
                    dataSource: this.dataSource
                }, options));
            },
            _initSettingTargets: function () {
                this.columnsTarget = this._createSettingTarget(this.columnFields, {
                    connectWith: this.rowFields,
                    setting: 'columns',
                    filterable: this.options.filterable,
                    sortable: this.options.sortable,
                    messages: {
                        empty: this.options.messages.columnFields,
                        fieldMenu: this.options.messages.fieldMenu
                    }
                });
                this.rowsTarget = this._createSettingTarget(this.rowFields, {
                    connectWith: this.columnFields,
                    setting: 'rows',
                    filterable: this.options.filterable,
                    sortable: this.options.sortable,
                    messages: {
                        empty: this.options.messages.rowFields,
                        fieldMenu: this.options.messages.fieldMenu
                    }
                });
            },
            _createLayout: function () {
                var that = this;
                var layoutTable = $(LAYOUT_TABLE);
                var leftContainer = layoutTable.find('.k-pivot-rowheaders');
                var rightContainer = layoutTable.find('.k-pivot-table');
                var gridWrapper = $(DIV).addClass('k-grid k-widget');
                that._measureFields();
                that.columnFields = $(DIV).addClass('k-pivot-toolbar k-header k-settings-columns');
                that.rowFields = $(DIV).addClass('k-pivot-toolbar k-header k-settings-rows');
                that.columnsHeader = $('<div class="k-grid-header-wrap" />').wrap('<div class="k-grid-header" />');
                that.columnsHeader.parent().css('padding-right', kendo.support.scrollbar());
                that.rowsHeader = $('<div class="k-grid k-widget k-alt"/>');
                that.content = $('<div class="k-grid-content" />');
                leftContainer.append(that.measureFields);
                leftContainer.append(that.rowFields);
                leftContainer.append(that.rowsHeader);
                gridWrapper.append(that.columnsHeader.parent());
                gridWrapper.append(that.content);
                rightContainer.append(that.columnFields);
                rightContainer.append(gridWrapper);
                that.wrapper.append(layoutTable);
                that.columnsHeaderTree = new kendo.dom.Tree(that.columnsHeader[0]);
                that.rowsHeaderTree = new kendo.dom.Tree(that.rowsHeader[0]);
                that.contentTree = new kendo.dom.Tree(that.content[0]);
                that._initSettingTargets();
            },
            _progress: function (toggle) {
                kendo.ui.progress(this.wrapper, toggle);
            },
            _resize: function () {
                if (this.content[0].firstChild) {
                    this._setSectionsWidth();
                    this._setSectionsHeight();
                    this._setContentWidth();
                    this._setContentHeight();
                    this._columnHeaderReflow();
                }
            },
            _columnHeaderReflow: function () {
                var columnTable = this.columnsHeader.children('table');
                if (!kendo.support.browser.mozilla) {
                    return;
                }
                clearTimeout(this._headerReflowTimeout);
                columnTable.css('table-layout', 'auto');
                this._headerReflowTimeout = setTimeout(function () {
                    columnTable.css('table-layout', '');
                });
            },
            _setSectionsWidth: function () {
                var rowsHeader = this.rowsHeader;
                var leftColumn = rowsHeader.parent('.k-pivot-rowheaders').width(AUTO);
                var width;
                width = Math.max(outerWidth(this.measureFields), outerWidth(this.rowFields));
                width = Math.max(rowsHeader.children('table').width(), width);
                leftColumn.width(width);
            },
            _setSectionsHeight: function () {
                var measureFieldsHeight = this.measureFields.height(AUTO).height();
                var columnFieldsHeight = this.columnFields.height(AUTO).height();
                var rowFieldsHeight = this.rowFields.height(AUTO).innerHeight();
                var columnsHeight = this.columnsHeader.height(AUTO).innerHeight();
                var padding = rowFieldsHeight - this.rowFields.height();
                var firstRowHeight = columnFieldsHeight > measureFieldsHeight ? columnFieldsHeight : measureFieldsHeight;
                var secondRowHeight = columnsHeight > rowFieldsHeight ? columnsHeight : rowFieldsHeight;
                this.measureFields.height(firstRowHeight);
                this.columnFields.height(firstRowHeight);
                this.rowFields.height(secondRowHeight - padding);
                this.columnsHeader.height(secondRowHeight);
            },
            _setContentWidth: function () {
                var contentTable = this.content.find('table');
                var columnTable = this.columnsHeader.children('table');
                var rowLength = contentTable.children('colgroup').children().length;
                var calculatedWidth = rowLength * this.options.columnWidth;
                var minWidth = Math.ceil(calculatedWidth / this.content.width() * 100);
                if (minWidth < 100) {
                    minWidth = 100;
                }
                contentTable.add(columnTable).css('width', minWidth + '%');
                this._resetColspan(columnTable);
            },
            _setContentHeight: function () {
                var that = this;
                var content = that.content;
                var rowsHeader = that.rowsHeader;
                var innerHeight = that.wrapper.innerHeight();
                var scrollbar = kendo.support.scrollbar();
                var skipScrollbar = content[0].offsetHeight === content[0].clientHeight;
                var height = that.options.height;
                if (that.wrapper.is(':visible')) {
                    if (!innerHeight || !height) {
                        if (skipScrollbar) {
                            scrollbar = 0;
                        }
                        content.height('auto');
                        rowsHeader.height(content.height() - scrollbar);
                        return;
                    }
                    innerHeight -= outerHeight(that.columnFields);
                    innerHeight -= outerHeight(that.columnsHeader.parent());
                    if (innerHeight <= scrollbar * 2) {
                        innerHeight = scrollbar * 2 + 1;
                        if (!skipScrollbar) {
                            innerHeight += scrollbar;
                        }
                    }
                    content.height(innerHeight);
                    if (skipScrollbar) {
                        scrollbar = 0;
                    }
                    rowsHeader.height(innerHeight - scrollbar);
                }
            },
            _resetColspan: function (columnTable) {
                var that = this;
                var cell = columnTable.children('tbody').children(':first').children(':first');
                if (that._colspan === undefined) {
                    that._colspan = cell.attr('colspan');
                }
                cell.attr('colspan', 1);
                clearTimeout(that._layoutTimeout);
                that._layoutTimeout = setTimeout(function () {
                    cell.attr('colspan', that._colspan);
                    that._colspan = undefined;
                });
            },
            _axisMeasures: function (axis) {
                var result = [];
                var dataSource = this.dataSource;
                var measures = dataSource.measures();
                var hasMeasure = measures.length > 1 || measures[0] && measures[0].type;
                if (dataSource.measuresAxis() === axis) {
                    if (dataSource[axis]().length === 0 || hasMeasure) {
                        result = measures;
                    }
                }
                return result;
            },
            items: function () {
                return [];
            },
            refresh: function () {
                var that = this;
                var dataSource = that.dataSource;
                var axes = dataSource.axes();
                var columns = (axes.columns || {}).tuples || [];
                var rows = (axes.rows || {}).tuples || [];
                var columnBuilder = that._columnBuilder;
                var rowBuilder = that._rowBuilder;
                var columnAxis = {};
                var rowAxis = {};
                if (that.trigger(DATABINDING, { action: 'rebind' })) {
                    return;
                }
                columnBuilder.measures = that._axisMeasures(AXIS_COLUMNS);
                rowBuilder.measures = that._axisMeasures(AXIS_ROWS);
                that.columnsHeaderTree.render(columnBuilder.build(columns));
                that.rowsHeaderTree.render(rowBuilder.build(rows));
                columnAxis = {
                    indexes: columnBuilder._indexes,
                    measures: columnBuilder.measures,
                    metadata: columnBuilder.metadata
                };
                rowAxis = {
                    indexes: rowBuilder._indexes,
                    measures: rowBuilder.measures,
                    metadata: rowBuilder.metadata
                };
                that.contentTree.render(that._contentBuilder.build(dataSource.view(), columnAxis, rowAxis));
                that._resize();
                if (that.touchScroller) {
                    that.touchScroller.contentResized();
                } else {
                    var touchScroller = kendo.touchScroller(that.content);
                    if (touchScroller && touchScroller.movable) {
                        that.touchScroller = touchScroller;
                        touchScroller.movable.bind('change', function (e) {
                            that.columnsHeader.scrollLeft(-e.sender.x);
                            that.rowsHeader.scrollTop(-e.sender.y);
                        });
                    }
                }
                that._progress(false);
                that.trigger(DATABOUND);
            },
            _scrollable: function () {
                var that = this;
                var columnsHeader = that.columnsHeader;
                var rowsHeader = that.rowsHeader;
                that.content.scroll(function () {
                    columnsHeader.scrollLeft(this.scrollLeft);
                    rowsHeader.scrollTop(this.scrollTop);
                });
                rowsHeader.bind('DOMMouseScroll' + NS + ' mousewheel' + NS, $.proxy(that._wheelScroll, that));
            },
            _wheelScroll: function (e) {
                if (e.ctrlKey) {
                    return;
                }
                var delta = kendo.wheelDeltaY(e);
                var scrollTop = this.content.scrollTop();
                if (delta) {
                    e.preventDefault();
                    $(e.currentTarget).one('wheel' + NS, false);
                    this.rowsHeader.scrollTop(scrollTop + -delta);
                    this.content.scrollTop(scrollTop + -delta);
                }
            }
        });
        var element = kendo.dom.element;
        var htmlNode = kendo.dom.html;
        var createMetadata = function (levelNum, memberIdx) {
            return {
                maxChildren: 0,
                children: 0,
                maxMembers: 0,
                members: 0,
                measures: 1,
                levelNum: levelNum,
                parentMember: memberIdx !== 0
            };
        };
        var buildPath = function (tuple, index) {
            var path = [];
            var idx = 0;
            for (; idx <= index; idx++) {
                path.push(tuple.members[idx].name);
            }
            return path;
        };
        var tupleName = function (tuple, index) {
            var name = '';
            var idx = 0;
            for (; idx <= index; idx++) {
                name += tuple.members[idx].name;
            }
            return name;
        };
        var ColumnBuilder = Class.extend({
            init: function () {
                this.measures = 1;
                this.metadata = {};
            },
            build: function (tuples) {
                var tbody = this._tbody(tuples);
                var colgroup = this._colGroup();
                return [element('table', null, [
                        colgroup,
                        tbody
                    ])];
            },
            reset: function () {
                this.metadata = {};
            },
            _colGroup: function () {
                var length = this._rowLength();
                var children = [];
                var idx = 0;
                for (; idx < length; idx++) {
                    children.push(element('col', null));
                }
                return element('colgroup', null, children);
            },
            _tbody: function (tuples) {
                var root = tuples[0];
                this.map = {};
                this.rows = [];
                this.rootTuple = root;
                this._indexes = [];
                if (root) {
                    this._buildRows(root, 0);
                    this._normalize();
                } else {
                    this.rows.push(element('tr', null, [element('th', null, [htmlNode('&nbsp;')])]));
                }
                return element('tbody', null, this.rows);
            },
            _normalize: function () {
                var rows = this.rows;
                var rowsLength = rows.length;
                var rowIdx = 0;
                var row;
                var cellsLength;
                var cellIdx;
                var cells;
                var cell;
                for (; rowIdx < rowsLength; rowIdx++) {
                    row = rows[rowIdx];
                    if (row.rowSpan === 1) {
                        continue;
                    }
                    cells = row.children;
                    cellIdx = 0;
                    cellsLength = cells.length;
                    for (; cellIdx < cellsLength; cellIdx++) {
                        cell = cells[cellIdx];
                        if (cell.tupleAll) {
                            cell.attr.rowSpan = row.rowSpan;
                        }
                    }
                }
            },
            _rowIndex: function (row) {
                var rows = this.rows;
                var length = rows.length;
                var idx = 0;
                for (; idx < length; idx++) {
                    if (rows[idx] === row) {
                        break;
                    }
                }
                return idx;
            },
            _rowLength: function () {
                var cells = this.rows[0] ? this.rows[0].children : [];
                var length = cells.length;
                var rowLength = 0;
                var idx = 0;
                if (length) {
                    for (; idx < length; idx++) {
                        rowLength += cells[idx].attr.colSpan || 1;
                    }
                }
                if (!rowLength) {
                    rowLength = this.measures;
                }
                return rowLength;
            },
            _row: function (tuple, memberIdx, parentMember) {
                var rootName = this.rootTuple.members[memberIdx].name;
                var levelNum = tuple.members[memberIdx].levelNum;
                var rowKey = rootName + levelNum;
                var map = this.map;
                var parentRow;
                var children;
                var row = map[rowKey];
                if (!row) {
                    row = element('tr', null, []);
                    row.parentMember = parentMember;
                    row.collapsed = 0;
                    row.colSpan = 0;
                    row.rowSpan = 1;
                    map[rowKey] = row;
                    parentRow = map[rootName + (Number(levelNum) - 1)];
                    if (parentRow) {
                        children = parentRow.children;
                        if (children[1] && children[1].attr.className.indexOf('k-alt') === -1) {
                            row.notFirst = true;
                        } else {
                            row.notFirst = parentRow.notFirst;
                        }
                    }
                    this.rows.splice(this._rowIndex(parentRow) + 1, 0, row);
                } else {
                    row.notFirst = false;
                    if (!row.parentMember || row.parentMember !== parentMember) {
                        row.parentMember = parentMember;
                        row.collapsed = 0;
                        row.colSpan = 0;
                    }
                }
                return row;
            },
            _measures: function (measures, tuple, className) {
                var map = this.map;
                var row = map.measureRow;
                var measure;
                if (!row) {
                    row = element('tr', null, []);
                    map.measureRow = row;
                    this.rows.push(row);
                }
                for (var idx = 0, length = measures.length; idx < length; idx++) {
                    measure = measures[idx];
                    row.children.push(this._cell(className || '', [this._content(measure, tuple)], measure));
                }
                return length;
            },
            _content: function (member, tuple) {
                return htmlNode(this.template({
                    member: member,
                    tuple: tuple
                }));
            },
            _cell: function (className, children, member) {
                var cell = element('th', { className: 'k-header' + className }, children);
                cell.value = member.caption || member.name;
                return cell;
            },
            _buildRows: function (tuple, memberIdx, parentMember) {
                var members = tuple.members;
                var member = members[memberIdx];
                var nextMember = members[memberIdx + 1];
                var row, childRow, children, childrenLength;
                var cell, allCell, cellAttr;
                var cellChildren = [];
                var path;
                var idx = 0;
                var metadata;
                var colSpan;
                var collapsed = 0;
                var memberCollapsed = 0;
                if (member.measure) {
                    this._measures(member.children, tuple);
                    return;
                }
                path = kendo.stringify(buildPath(tuple, memberIdx));
                row = this._row(tuple, memberIdx, parentMember);
                children = member.children;
                childrenLength = children.length;
                metadata = this.metadata[path];
                if (!metadata) {
                    this.metadata[path] = metadata = createMetadata(Number(member.levelNum), memberIdx);
                    metadata.rootLevelNum = Number(this.rootTuple.members[memberIdx].levelNum);
                }
                this._indexes.push({
                    path: path,
                    tuple: tuple
                });
                if (member.hasChildren) {
                    if (metadata.expanded === false) {
                        collapsed = metadata.maxChildren;
                        row.collapsed += collapsed;
                        metadata.children = 0;
                        childrenLength = 0;
                    }
                    cellAttr = { className: 'k-icon ' + (childrenLength ? STATE_EXPANDED : STATE_COLLAPSED) };
                    cellAttr[kendo.attr('path')] = path;
                    cellChildren.push(element('span', cellAttr));
                }
                cellChildren.push(this._content(member, tuple));
                cell = this._cell(row.notFirst ? ' k-first' : '', cellChildren, member);
                row.children.push(cell);
                row.colSpan += 1;
                if (childrenLength) {
                    allCell = this._cell(' k-alt', [this._content(member, tuple)], member);
                    row.children.push(allCell);
                    for (; idx < childrenLength; idx++) {
                        childRow = this._buildRows(children[idx], memberIdx, member);
                    }
                    colSpan = childRow.colSpan;
                    collapsed = childRow.collapsed;
                    cell.attr.colSpan = colSpan;
                    metadata.children = colSpan;
                    metadata.members = 1;
                    row.colSpan += colSpan;
                    row.collapsed += collapsed;
                    row.rowSpan = childRow.rowSpan + 1;
                    if (nextMember) {
                        if (nextMember.measure) {
                            colSpan = this._measures(nextMember.children, tuple, ' k-alt');
                        } else {
                            childRow = this._buildRows(tuple, memberIdx + 1);
                            colSpan = childRow.colSpan;
                            row.collapsed += childRow.collapsed;
                            memberCollapsed = childRow.collapsed;
                        }
                        allCell.attr.colSpan = colSpan;
                        colSpan -= 1;
                        metadata.members += colSpan;
                        row.colSpan += colSpan;
                    }
                } else if (nextMember) {
                    if (nextMember.measure) {
                        colSpan = this._measures(nextMember.children, tuple);
                    } else {
                        childRow = this._buildRows(tuple, memberIdx + 1);
                        colSpan = childRow.colSpan;
                        row.collapsed += childRow.collapsed;
                        memberCollapsed = childRow.collapsed;
                    }
                    metadata.members = colSpan;
                    if (colSpan > 1) {
                        cell.attr.colSpan = colSpan;
                        row.colSpan += colSpan - 1;
                    }
                }
                if (metadata.maxMembers < metadata.members + memberCollapsed) {
                    metadata.maxMembers = metadata.members + memberCollapsed;
                }
                children = metadata.children + collapsed;
                if (metadata.maxChildren < children) {
                    metadata.maxChildren = children;
                }
                (allCell || cell).tupleAll = true;
                return row;
            }
        });
        var RowBuilder = Class.extend({
            init: function () {
                this.metadata = {};
            },
            build: function (tuples) {
                var tbody = this._tbody(tuples);
                var colgroup = this._colGroup();
                return [element('table', null, [
                        colgroup,
                        tbody
                    ])];
            },
            reset: function () {
                this.metadata = {};
            },
            _rowLength: function () {
                var children = this.rows[0].children;
                var length = 0;
                var idx = 0;
                var cell = children[idx];
                while (cell) {
                    length += cell.attr.colSpan || 1;
                    cell = children[++idx];
                }
                return length;
            },
            _colGroup: function () {
                var length = this._rowLength();
                var children = [];
                var idx = 0;
                for (; idx < length; idx++) {
                    children.push(element('col', null));
                }
                return element('colgroup', null, children);
            },
            _tbody: function (tuples) {
                var root = tuples[0];
                this.rootTuple = root;
                this.rows = [];
                this.map = {};
                this._indexes = [];
                if (root) {
                    this._buildRows(root, 0);
                    this._normalize();
                } else {
                    this.rows.push(element('tr', null, [element('td', null, [htmlNode('&nbsp;')])]));
                }
                return element('tbody', null, this.rows);
            },
            _normalize: function () {
                var rows = this.rows;
                var rowsLength = rows.length;
                var rowIdx = 0;
                var members = this.rootTuple.members;
                var firstMemberName = members[0].name;
                var membersLength = members.length;
                var memberIdx = 0;
                var row;
                var cell;
                var maxcolSpan;
                var map = this.map;
                var allRow;
                for (; rowIdx < rowsLength; rowIdx++) {
                    row = rows[rowIdx];
                    for (memberIdx = 0; memberIdx < membersLength; memberIdx++) {
                        maxcolSpan = this[members[memberIdx].name];
                        cell = row.colSpan['dim' + memberIdx];
                        if (cell && cell.colSpan < maxcolSpan) {
                            cell.attr.colSpan = maxcolSpan - cell.colSpan + 1;
                        }
                    }
                }
                row = map[firstMemberName];
                allRow = map[firstMemberName + 'all'];
                if (row) {
                    row.children[0].attr.className = 'k-first';
                }
                if (allRow) {
                    allRow.children[0].attr.className += ' k-first';
                }
            },
            _row: function (children) {
                var row = element('tr', null, children);
                row.rowSpan = 1;
                row.colSpan = {};
                this.rows.push(row);
                return row;
            },
            _content: function (member, tuple) {
                return htmlNode(this.template({
                    member: member,
                    tuple: tuple
                }));
            },
            _cell: function (className, children, member) {
                var cell = element('td', { className: className }, children);
                cell.value = member.caption || member.name;
                return cell;
            },
            _buildRows: function (tuple, memberIdx) {
                var map = this.map;
                var path;
                var members = tuple.members;
                var member = members[memberIdx];
                var nextMember = members[memberIdx + 1];
                var children = member.children;
                var childrenLength = children.length;
                var levelNum = Number(member.levelNum);
                var rootName = this.rootTuple.members[memberIdx].name;
                var tuplePath = buildPath(tuple, memberIdx - 1).join('');
                var rootLevelNum = Number(this.rootTuple.members[memberIdx].levelNum);
                var parentName = tuplePath + (rootLevelNum === levelNum ? '' : member.parentName || '');
                var row = map[parentName + 'all'] || map[parentName];
                var colSpan = levelNum + 1;
                var cell, allCell;
                var childRow, allRow;
                var metadata;
                var className;
                var cellChildren = [];
                var expandIconAttr;
                var idx;
                if (!row || row.hasChild) {
                    row = this._row();
                } else {
                    row.hasChild = true;
                }
                if (member.measure) {
                    className = row.allCell ? 'k-grid-footer' : '';
                    row.children.push(this._cell(className, [this._content(children[0], tuple)], children[0]));
                    row.rowSpan = childrenLength;
                    for (idx = 1; idx < childrenLength; idx++) {
                        this._row([this._cell(className, [this._content(children[idx], tuple)], children[idx])]);
                    }
                    return row;
                }
                map[tuplePath + member.name] = row;
                path = kendo.stringify(buildPath(tuple, memberIdx));
                metadata = this.metadata[path];
                if (!metadata) {
                    this.metadata[path] = metadata = createMetadata(levelNum, memberIdx);
                    metadata.rootLevelNum = rootLevelNum;
                }
                this._indexes.push({
                    path: path,
                    tuple: tuple
                });
                if (member.hasChildren) {
                    if (metadata.expanded === false) {
                        childrenLength = 0;
                        metadata.children = 0;
                    }
                    expandIconAttr = { className: 'k-icon ' + (childrenLength ? STATE_EXPANDED : STATE_COLLAPSED) };
                    expandIconAttr[kendo.attr('path')] = path;
                    cellChildren.push(element('span', expandIconAttr));
                }
                cellChildren.push(this._content(member, tuple));
                className = row.allCell && !childrenLength ? 'k-grid-footer' : '';
                cell = this._cell(className, cellChildren, member);
                cell.colSpan = colSpan;
                row.children.push(cell);
                row.colSpan['dim' + memberIdx] = cell;
                if (!this[rootName] || this[rootName] < colSpan) {
                    this[rootName] = colSpan;
                }
                if (childrenLength) {
                    row.allCell = false;
                    row.hasChild = false;
                    for (idx = 0; idx < childrenLength; idx++) {
                        childRow = this._buildRows(children[idx], memberIdx);
                        if (row !== childRow) {
                            row.rowSpan += childRow.rowSpan;
                        }
                    }
                    if (row.rowSpan > 1) {
                        cell.attr.rowSpan = row.rowSpan;
                    }
                    metadata.children = row.rowSpan;
                    allCell = this._cell('k-grid-footer', [this._content(member, tuple)], member);
                    allCell.colSpan = colSpan;
                    allRow = this._row([allCell]);
                    allRow.colSpan['dim' + memberIdx] = allCell;
                    allRow.allCell = true;
                    map[tuplePath + member.name + 'all'] = allRow;
                    if (nextMember) {
                        childRow = this._buildRows(tuple, memberIdx + 1);
                        allCell.attr.rowSpan = childRow.rowSpan;
                    }
                    row.rowSpan += allRow.rowSpan;
                    metadata.members = allRow.rowSpan;
                } else if (nextMember) {
                    row.hasChild = false;
                    this._buildRows(tuple, memberIdx + 1);
                    (allCell || cell).attr.rowSpan = row.rowSpan;
                    metadata.members = row.rowSpan;
                }
                if (metadata.maxChildren < metadata.children) {
                    metadata.maxChildren = metadata.children;
                }
                if (metadata.maxMembers < metadata.members) {
                    metadata.maxMembers = metadata.members;
                }
                return row;
            }
        });
        var ContentBuilder = Class.extend({
            init: function () {
                this.columnAxis = {};
                this.rowAxis = {};
            },
            build: function (data, columnAxis, rowAxis) {
                var index = columnAxis.indexes[0];
                var metadata = columnAxis.metadata[index ? index.path : undefined];
                this.columnAxis = columnAxis;
                this.rowAxis = rowAxis;
                this.data = data;
                this.rowLength = metadata ? metadata.maxChildren + metadata.maxMembers : columnAxis.measures.length || 1;
                if (!this.rowLength) {
                    this.rowLength = 1;
                }
                var tbody = this._tbody();
                var colgroup = this._colGroup();
                return [element('table', null, [
                        colgroup,
                        tbody
                    ])];
            },
            _colGroup: function () {
                var length = this.columnAxis.measures.length || 1;
                var children = [];
                var idx = 0;
                if (this.rows[0]) {
                    length = this.rows[0].children.length;
                }
                for (; idx < length; idx++) {
                    children.push(element('col', null));
                }
                return element('colgroup', null, children);
            },
            _tbody: function () {
                this.rows = [];
                if (this.data[0]) {
                    this.columnIndexes = this._indexes(this.columnAxis, this.rowLength);
                    this.rowIndexes = this._indexes(this.rowAxis, Math.ceil(this.data.length / this.rowLength));
                    this._buildRows();
                } else {
                    this.rows.push(element('tr', null, [element('td', null, [htmlNode('&nbsp;')])]));
                }
                return element('tbody', null, this.rows);
            },
            _indexes: function (axisInfo, total) {
                var result = [];
                var axisInfoMember;
                var indexes = axisInfo.indexes;
                var metadata = axisInfo.metadata;
                var measures = axisInfo.measures;
                var measuresLength = measures.length || 1;
                var current;
                var dataIdx = 0;
                var firstEmpty = 0;
                var idx = 0;
                var length = indexes.length;
                var measureIdx;
                var index;
                var children;
                var skipChildren;
                if (!length) {
                    for (measureIdx = 0; measureIdx < measuresLength; measureIdx++) {
                        result[measureIdx] = {
                            index: measureIdx,
                            measure: measures[measureIdx],
                            tuple: null
                        };
                    }
                    return result;
                }
                for (; idx < length; idx++) {
                    axisInfoMember = indexes[idx];
                    current = metadata[axisInfoMember.path];
                    children = current.children + current.members;
                    skipChildren = 0;
                    if (children) {
                        children -= measuresLength;
                    }
                    if (current.expanded === false && current.children !== current.maxChildren) {
                        skipChildren = current.maxChildren;
                    }
                    if (current.parentMember && current.levelNum === current.rootLevelNum) {
                        children = -1;
                    }
                    if (children > -1) {
                        for (measureIdx = 0; measureIdx < measuresLength; measureIdx++) {
                            index = children + measureIdx;
                            if (!current.children) {
                                index += firstEmpty;
                            }
                            result[children + firstEmpty + measureIdx] = {
                                children: children,
                                index: dataIdx,
                                measure: measures[measureIdx],
                                tuple: axisInfoMember.tuple
                            };
                            dataIdx += 1;
                        }
                        while (result[firstEmpty] !== undefined) {
                            firstEmpty += 1;
                        }
                    }
                    if (firstEmpty === total) {
                        break;
                    }
                    dataIdx += skipChildren;
                }
                return result;
            },
            _buildRows: function () {
                var rowIndexes = this.rowIndexes;
                var length = rowIndexes.length;
                var idx = 0;
                for (; idx < length; idx++) {
                    var rowIndex = rowIndexes[idx];
                    if (rowIndex) {
                        this.rows.push(this._buildRow(rowIndex));
                    }
                }
            },
            _buildRow: function (rowInfo) {
                var startIdx = rowInfo.index * this.rowLength;
                var columnIndexes = this.columnIndexes;
                var length = columnIndexes.length;
                var columnInfo;
                var cells = [];
                var idx = 0;
                var templateInfo;
                var cell, cellContent;
                var attr, dataItem, measure;
                for (; idx < length; idx++) {
                    columnInfo = columnIndexes[idx];
                    if (columnInfo === undefined) {
                        continue;
                    }
                    attr = {};
                    if (columnInfo.children) {
                        attr.className = 'k-alt';
                    }
                    cellContent = '';
                    dataItem = this.data[startIdx + columnInfo.index];
                    measure = columnInfo.measure || rowInfo.measure;
                    templateInfo = {
                        columnTuple: columnInfo.tuple,
                        rowTuple: rowInfo.tuple,
                        measure: measure,
                        dataItem: dataItem
                    };
                    if (dataItem.value !== '' && measure && measure.type) {
                        if (measure.type === 'status') {
                            cellContent = this.kpiStatusTemplate(templateInfo);
                        } else if (measure.type === 'trend') {
                            cellContent = this.kpiTrendTemplate(templateInfo);
                        }
                    }
                    if (!cellContent) {
                        cellContent = this.dataTemplate(templateInfo);
                    }
                    cell = element('td', attr, [htmlNode(cellContent)]);
                    cell.value = dataItem.value;
                    cells.push(cell);
                }
                attr = {};
                if (rowInfo.children) {
                    attr.className = 'k-grid-footer';
                }
                return element('tr', attr, cells);
            }
        });
        ui.plugin(PivotGrid);
        kendo.PivotExcelExporter = kendo.Class.extend({
            init: function (options) {
                this.options = options;
                this.widget = options.widget;
                this.dataSource = this.widget.dataSource;
            },
            _columns: function () {
                var columnHeaderTable = this.widget.columnsHeaderTree.children[0];
                var rowHeaderTable = this.widget.rowsHeaderTree.children[0];
                var columnHeaderLength = columnHeaderTable.children[0].children.length;
                var rowHeaderLength = rowHeaderTable.children[0].children.length;
                var width = this.widget.options.columnWidth;
                var result = [];
                var idx;
                if (rowHeaderLength && this.dataSource.data()[0]) {
                    for (idx = 0; idx < rowHeaderLength; idx++) {
                        result.push({ autoWidth: true });
                    }
                }
                for (idx = 0; idx < columnHeaderLength; idx++) {
                    result.push({
                        autoWidth: false,
                        width: width
                    });
                }
                return result;
            },
            _cells: function (rows, type, callback) {
                var result = [];
                var i = 0;
                var length = rows.length;
                var cellsLength;
                var row, cells;
                var j, cell;
                for (; i < length; i++) {
                    row = [];
                    cells = rows[i].children;
                    cellsLength = cells.length;
                    for (j = 0; j < cellsLength; j++) {
                        cell = cells[j];
                        row.push({
                            background: '#7a7a7a',
                            color: '#fff',
                            value: cell.value,
                            colSpan: cell.attr.colSpan || 1,
                            rowSpan: cell.attr.rowSpan || 1
                        });
                    }
                    if (callback) {
                        callback(row, i);
                    }
                    result.push({
                        cells: row,
                        type: type
                    });
                }
                return result;
            },
            _rows: function () {
                var columnHeaderTable = this.widget.columnsHeaderTree.children[0];
                var rowHeaderTable = this.widget.rowsHeaderTree.children[0];
                var columnHeaderLength = columnHeaderTable.children[0].children.length;
                var rowHeaderLength = rowHeaderTable.children[0].children.length;
                var columnHeaderRows = columnHeaderTable.children[1].children;
                var rowHeaderRows = rowHeaderTable.children[1].children;
                var contentRows = this.widget.contentTree.children[0].children[1].children;
                var columnRows = this._cells(columnHeaderRows, 'header');
                if (rowHeaderLength) {
                    columnRows[0].cells.splice(0, 0, {
                        background: '#7a7a7a',
                        color: '#fff',
                        value: '',
                        colSpan: rowHeaderLength,
                        rowSpan: columnHeaderRows.length
                    });
                }
                var dataCallback = function (row, index) {
                    var j = 0;
                    var cell, value;
                    var cells = contentRows[index].children;
                    for (; j < columnHeaderLength; j++) {
                        cell = cells[j];
                        value = Number(cell.value);
                        if (isNaN(value)) {
                            value = cell.value;
                        }
                        row.push({
                            background: '#dfdfdf',
                            color: '#333',
                            value: value,
                            colSpan: 1,
                            rowSpan: 1
                        });
                    }
                };
                var rowRows = this._cells(rowHeaderRows, 'data', dataCallback);
                return columnRows.concat(rowRows);
            },
            _freezePane: function () {
                var columnHeaderTable = this.widget.columnsHeaderTree.children[0];
                var rowHeaderTable = this.widget.rowsHeaderTree.children[0];
                var rowHeaderLength = rowHeaderTable.children[0].children.length;
                var columnHeaderRows = columnHeaderTable.children[1].children;
                return {
                    colSplit: rowHeaderLength,
                    rowSplit: columnHeaderRows.length
                };
            },
            workbook: function () {
                var promise;
                if (this.dataSource.view()[0]) {
                    promise = $.Deferred();
                    promise.resolve();
                } else {
                    promise = this.dataSource.fetch();
                }
                return promise.then($.proxy(function () {
                    return {
                        sheets: [{
                                columns: this._columns(),
                                rows: this._rows(),
                                freezePane: this._freezePane(),
                                filter: null
                            }]
                    };
                }, this));
            }
        });
        var PivotExcelMixin = {
            extend: function (proto) {
                proto.events.push('excelExport');
                proto.options.excel = $.extend(proto.options.excel, this.options);
                proto.saveAsExcel = this.saveAsExcel;
            },
            options: {
                proxyURL: '',
                filterable: false,
                fileName: 'Export.xlsx'
            },
            saveAsExcel: function () {
                var excel = this.options.excel || {};
                var exporter = new kendo.PivotExcelExporter({ widget: this });
                exporter.workbook().then($.proxy(function (book) {
                    if (!this.trigger('excelExport', { workbook: book })) {
                        var workbook = new kendo.ooxml.Workbook(book);
                        workbook.toDataURLAsync().then(function (dataURI) {
                            kendo.saveAs({
                                dataURI: dataURI,
                                fileName: book.fileName || excel.fileName,
                                proxyURL: excel.proxyURL,
                                forceProxy: excel.forceProxy
                            });
                        });
                    }
                }, this));
            }
        };
        kendo.PivotExcelMixin = PivotExcelMixin;
        if (kendo.ooxml && kendo.ooxml.Workbook) {
            PivotExcelMixin.extend(PivotGrid.prototype);
        }
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(PivotGrid.prototype);
            PivotGrid.fn._drawPDF = function () {
                return this._drawPDFShadow({ width: this.wrapper.width() }, { avoidLinks: this.options.pdf.avoidLinks });
            };
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pivot.fieldmenu', [
        'kendo.pivotgrid',
        'kendo.menu',
        'kendo.window',
        'kendo.treeview',
        'kendo.dropdownlist'
    ], f);
}(function () {
    var __meta__ = {
        id: 'pivot.fieldmenu',
        name: 'PivotFieldMenu',
        category: 'web',
        description: 'The PivotFieldMenu widget allows the user to filter on fields displayed in PivotGrid',
        depends: [
            'menu',
            'window',
            'treeview',
            'dropdownlist'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var ui = kendo.ui;
        var MENU = 'kendoContextMenu';
        var proxy = $.proxy;
        var NS = '.kendoPivotFieldMenu';
        var Widget = ui.Widget;
        var FILTER_ITEM = 'k-filter-item';
        var ARIA_LABEL = 'aria-label';
        var PivotFieldMenu = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this._dataSource();
                this._layout();
                kendo.notify(this);
            },
            events: [],
            options: {
                name: 'PivotFieldMenu',
                filter: null,
                filterable: true,
                sortable: true,
                messages: {
                    info: 'Show items with value that:',
                    sortAscending: 'Sort Ascending',
                    sortDescending: 'Sort Descending',
                    filterFields: 'Fields Filter',
                    filter: 'Filter',
                    include: 'Include Fields...',
                    title: 'Fields to include',
                    clear: 'Clear',
                    ok: 'OK',
                    cancel: 'Cancel',
                    operators: {
                        contains: 'Contains',
                        doesnotcontain: 'Does not contain',
                        startswith: 'Starts with',
                        endswith: 'Ends with',
                        eq: 'Is equal to',
                        neq: 'Is not equal to'
                    }
                }
            },
            _layout: function () {
                var options = this.options;
                this.wrapper = $(kendo.template(MENUTEMPLATE)({
                    ns: kendo.ns,
                    filterable: options.filterable,
                    sortable: options.sortable,
                    messages: options.messages
                }));
                this.menu = this.wrapper[MENU]({
                    filter: options.filter,
                    target: this.element,
                    orientation: 'vertical',
                    showOn: 'click',
                    closeOnClick: false,
                    open: proxy(this._menuOpen, this),
                    select: proxy(this._select, this),
                    copyAnchorStyles: false
                }).data(MENU);
                this._createWindow();
                if (options.filterable) {
                    this._initFilterForm();
                }
            },
            _initFilterForm: function () {
                var filterForm = this.menu.element.find('.' + FILTER_ITEM);
                var filterProxy = proxy(this._filter, this);
                this._filterOperator = new kendo.ui.DropDownList(filterForm.find('select'));
                this._filterValue = filterForm.find('.k-textbox');
                this._updateFilterAriaLabel();
                filterForm.on('submit' + NS, filterProxy).on('click' + NS, '.k-button-filter', filterProxy).on('click' + NS, '.k-button-clear', proxy(this._reset, this));
            },
            _setFilterForm: function (expression) {
                var filterOperator = this._filterOperator;
                var operator = '';
                var value = '';
                if (expression) {
                    operator = expression.operator;
                    value = expression.value;
                }
                filterOperator.value(operator);
                if (!filterOperator.value()) {
                    filterOperator.select(0);
                }
                this._filterValue.val(value);
            },
            _clearFilters: function (member) {
                var filter = this.dataSource.filter() || {};
                var expressions;
                var idx = 0;
                var length;
                filter.filters = filter.filters || [];
                expressions = findFilters(filter, member);
                for (length = expressions.length; idx < length; idx++) {
                    filter.filters.splice(filter.filters.indexOf(expressions[idx]), 1);
                }
                return filter;
            },
            _convert: function (value) {
                var schema = this.dataSource.options.schema;
                var field = ((schema.model || {}).fields || {})[this.currentMember];
                if (field) {
                    if (field.type === 'number') {
                        value = parseFloat(value);
                    } else if (field.type === 'boolean') {
                        value = Boolean($.parseJSON(value));
                    }
                }
                return value;
            },
            _filter: function (e) {
                var that = this;
                var value = that._convert(that._filterValue.val());
                e.preventDefault();
                if (value === '') {
                    that.menu.close();
                    return;
                }
                var expression = {
                    field: that.currentMember,
                    operator: that._filterOperator.value(),
                    value: value
                };
                var filter = that._clearFilters(that.currentMember);
                filter.filters.push(expression);
                that.dataSource.filter(filter);
                that.menu.close();
            },
            _updateFilterAriaLabel: function () {
                var filterForm = this.menu.element.find('.' + FILTER_ITEM);
                var selectedOperator = this._filterOperator.value();
                var selectedOperatorName = this.options.messages.operators[selectedOperator];
                filterForm.find('select').attr(ARIA_LABEL, selectedOperatorName);
            },
            _reset: function (e) {
                var that = this;
                var filter = that._clearFilters(that.currentMember);
                e.preventDefault();
                if (!filter.filters[0]) {
                    filter = {};
                }
                that.dataSource.filter(filter);
                that._setFilterForm(null);
                that.menu.close();
            },
            _sort: function (dir) {
                var field = this.currentMember;
                var expressions = this.dataSource.sort() || [];
                expressions = removeExpr(expressions, field);
                expressions.push({
                    field: field,
                    dir: dir
                });
                this.dataSource.sort(expressions);
                this.menu.close();
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
            },
            _dataSource: function () {
                this.dataSource = kendo.data.PivotDataSource.create(this.options.dataSource);
            },
            _createWindow: function () {
                var messages = this.options.messages;
                this.includeWindow = $(kendo.template(WINDOWTEMPLATE)({ messages: messages })).on('click' + NS, '.k-button-ok', proxy(this._applyIncludes, this)).on('click' + NS, '.k-button-cancel', proxy(this._closeWindow, this));
                this.includeWindow = new ui.Window(this.includeWindow, {
                    title: messages.title,
                    visible: false,
                    resizable: false,
                    open: proxy(this._windowOpen, this)
                });
            },
            _applyIncludes: function (e) {
                var checkedNodes = [];
                var resultExpression;
                var view = this.treeView.dataSource.view();
                var rootChecked = view[0].checked;
                var filter = this.dataSource.filter();
                var existingExpression = findFilters(filter, this.currentMember, 'in')[0];
                checkedNodeIds(view, checkedNodes);
                if (existingExpression) {
                    if (rootChecked) {
                        filter.filters.splice(filter.filters.indexOf(existingExpression), 1);
                        if (!filter.filters.length) {
                            filter = {};
                        }
                    } else {
                        existingExpression.value = checkedNodes.join(',');
                    }
                    resultExpression = filter;
                }
                if (checkedNodes.length) {
                    if (!resultExpression && !rootChecked) {
                        resultExpression = {
                            field: this.currentMember,
                            operator: 'in',
                            value: checkedNodes.join(',')
                        };
                        if (filter) {
                            filter.filters.push(resultExpression);
                            resultExpression = filter;
                        }
                    }
                }
                if (resultExpression) {
                    this.dataSource.filter(resultExpression);
                }
                this._closeWindow(e);
            },
            _closeWindow: function (e) {
                e.preventDefault();
                this.includeWindow.close();
            },
            _treeViewDataSource: function () {
                var that = this;
                return kendo.data.HierarchicalDataSource.create({
                    schema: {
                        model: {
                            id: 'uniqueName',
                            hasChildren: function (item) {
                                return parseInt(item.childrenCardinality, 10) > 0;
                            }
                        }
                    },
                    transport: {
                        read: function (options) {
                            var restrictions = {};
                            var node = that.treeView.dataSource.get(options.data.uniqueName);
                            var name = options.data.uniqueName;
                            if (!name) {
                                restrictions.levelUniqueName = that.currentMember + '.[(ALL)]';
                            } else {
                                restrictions.memberUniqueName = node.uniqueName.replace(/\&/g, '&amp;');
                                restrictions.treeOp = 1;
                            }
                            that.dataSource.schemaMembers(restrictions).done(function (data) {
                                checkNodes(that.dataSource.filter(), that.currentMember, data);
                                options.success(data);
                            }).fail(options.error);
                        }
                    }
                });
            },
            _createTreeView: function (element) {
                var that = this;
                that.treeView = new ui.TreeView(element, {
                    autoBind: false,
                    dataSource: that._treeViewDataSource(),
                    dataTextField: 'caption',
                    template: '#: data.item.caption || data.item.name #',
                    checkboxes: { checkChildren: true },
                    dataBound: function () {
                        ui.progress(that.includeWindow.element, false);
                    }
                });
            },
            _menuOpen: function (e) {
                if (!e.event) {
                    return;
                }
                var attr = kendo.attr('name');
                this.currentMember = $(e.event.target).closest('[' + attr + ']').attr(attr);
                if (this.options.filterable) {
                    this._setFilterForm(findFilters(this.dataSource.filter(), this.currentMember)[0]);
                }
            },
            _select: function (e) {
                var item = $(e.item);
                $('.k-pivot-filter-window').not(this.includeWindow.element).kendoWindow('close');
                if (item.hasClass('k-include-item')) {
                    this.includeWindow.center().open();
                } else if (item.hasClass('k-sort-asc')) {
                    this._sort('asc');
                } else if (item.hasClass('k-sort-desc')) {
                    this._sort('desc');
                } else if (item.hasClass(FILTER_ITEM)) {
                    this._updateFilterAriaLabel();
                }
            },
            _windowOpen: function () {
                if (!this.treeView) {
                    this._createTreeView(this.includeWindow.element.find('.k-treeview'));
                }
                ui.progress(this.includeWindow.element, true);
                this.treeView.dataSource.read();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (this.menu) {
                    this.menu.destroy();
                    this.menu = null;
                }
                if (this.treeView) {
                    this.treeView.destroy();
                    this.treeView = null;
                }
                if (this.includeWindow) {
                    this.includeWindow.destroy();
                    this.includeWindow = null;
                }
                this.wrapper = null;
                this.element = null;
            }
        });
        function removeExpr(expressions, name) {
            var result = [];
            for (var idx = 0, length = expressions.length; idx < length; idx++) {
                if (expressions[idx].field !== name) {
                    result.push(expressions[idx]);
                }
            }
            return result;
        }
        function findFilters(filter, member, operator) {
            if (!filter) {
                return [];
            }
            filter = filter.filters;
            var idx = 0;
            var result = [];
            var length = filter.length;
            var filterOperator;
            for (; idx < length; idx++) {
                filterOperator = filter[idx].operator;
                if ((!operator && filterOperator !== 'in' || filterOperator === operator) && filter[idx].field === member) {
                    result.push(filter[idx]);
                }
            }
            return result;
        }
        function checkNodes(filter, member, nodes) {
            var values, idx = 0, length = nodes.length;
            filter = findFilters(filter, member, 'in')[0];
            if (!filter) {
                for (; idx < length; idx++) {
                    nodes[idx].checked = true;
                }
            } else {
                values = filter.value.split(',');
                for (; idx < length; idx++) {
                    nodes[idx].checked = $.inArray(nodes[idx].uniqueName, values) >= 0;
                }
            }
        }
        function checkedNodeIds(nodes, checkedNodes) {
            var idx, length = nodes.length;
            for (idx = 0; idx < length; idx++) {
                if (nodes[idx].checked && nodes[idx].level() !== 0) {
                    checkedNodes.push(nodes[idx].uniqueName);
                }
                if (nodes[idx].hasChildren) {
                    checkedNodeIds(nodes[idx].children.view(), checkedNodes);
                }
            }
        }
        var LABELMENUTEMPLATE = '<div class="k-filterable k-content" tabindex="-1" data-role="fieldmenu">' + '<form class="k-filter-menu">' + '<div>' + '<div class="k-filter-help-text">#=messages.info#</div>' + '<select>' + '#for(var op in messages.operators){#' + '<option value="#=op#">#=messages.operators[op]#</option>' + '#}#' + '</select>' + '<input class="k-textbox" type="text" ' + ARIA_LABEL + '="#=messages.filter#" />' + '<div>' + '<a class="k-button k-primary k-button-filter" href="\\#">#=messages.filter#</a>' + '<a class="k-button k-button-clear" href="\\#">#=messages.clear#</a>' + '</div>' + '</div>' + '</form>' + '</div>';
        var MENUTEMPLATE = '<ul class="k-pivot-fieldmenu">' + '# if (sortable) {#' + '<li class="k-item k-sort-asc">' + '<span class="k-link">' + '<span class="k-icon k-i-sort-asc-sm"></span>' + '${messages.sortAscending}' + '</span>' + '</li>' + '<li class="k-item k-sort-desc">' + '<span class="k-link">' + '<span class="k-icon k-i-sort-desc-sm"></span>' + '${messages.sortDescending}' + '</span>' + '</li>' + '# if (filterable) {#' + '<li class="k-separator"></li>' + '# } #' + '# } #' + '# if (filterable) {#' + '<li class="k-item k-include-item">' + '<span class="k-link">' + '<span class="k-icon k-i-filter"></span>' + '${messages.include}' + '</span>' + '</li>' + '<li class="k-separator"></li>' + '<li class="k-item ' + FILTER_ITEM + '">' + '<span class="k-link">' + '<span class="k-icon k-i-filter"></span>' + '${messages.filterFields}' + '</span>' + '<ul>' + '<li>' + LABELMENUTEMPLATE + '</li>' + '</ul>' + '</li>' + '# } #' + '</ul>';
        var WINDOWTEMPLATE = '<div class="k-popup-edit-form k-pivot-filter-window"><div class="k-edit-form-container">' + '<div class="k-treeview"></div>' + '<div class="k-edit-buttons k-state-default">' + '<a class="k-button k-primary k-button-ok" href="\\#">' + '${messages.ok}' + '</a>' + '<a class="k-button k-button-cancel" href="\\#">' + '${messages.cancel}' + '</a>' + '</div></div>';
        ui.plugin(PivotFieldMenu);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.filtercell', [
        'kendo.autocomplete',
        'kendo.datepicker',
        'kendo.numerictextbox',
        'kendo.combobox',
        'kendo.dropdownlist'
    ], f);
}(function () {
    var __meta__ = {
        id: 'filtercell',
        name: 'Row filter',
        category: 'framework',
        depends: ['autocomplete'],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, DataSource = kendo.data.DataSource, Widget = ui.Widget, CHANGE = 'change', BOOL = 'boolean', ENUM = 'enums', STRING = 'string', EQ = 'Is equal to', NEQ = 'Is not equal to', proxy = $.proxy, nonValueOperators = [
                'isnull',
                'isnotnull',
                'isempty',
                'isnotempty',
                'isnullorempty',
                'isnotnullorempty'
            ];
        function isNonValueFilter(filter) {
            var operator = typeof filter === 'string' ? filter : filter.operator;
            return $.inArray(operator, nonValueOperators) > -1;
        }
        function findFilterForField(filter, field) {
            var filters = [];
            if ($.isPlainObject(filter)) {
                if (filter.hasOwnProperty('filters')) {
                    filters = filter.filters;
                } else if (filter.field == field) {
                    return filter;
                }
            }
            if ($.isArray(filter)) {
                filters = filter;
            }
            for (var i = 0; i < filters.length; i++) {
                var result = findFilterForField(filters[i], field);
                if (result) {
                    return result;
                }
            }
        }
        function removeFiltersForField(expression, field) {
            if (expression.filters) {
                expression.filters = $.grep(expression.filters, function (filter) {
                    removeFiltersForField(filter, field);
                    if (filter.filters) {
                        return filter.filters.length;
                    } else {
                        return filter.field != field;
                    }
                });
            }
        }
        function removeDuplicates(dataSelector, dataTextField) {
            var getter = kendo.getter(dataTextField, true);
            return function (e) {
                var items = dataSelector(e), result = [], index = 0, seen = {};
                while (index < items.length) {
                    var item = items[index++], text = getter(item);
                    if (!seen.hasOwnProperty(text)) {
                        result.push(item);
                        seen[text] = true;
                    }
                }
                return result;
            };
        }
        var FilterCell = Widget.extend({
            init: function (element, options) {
                element = $(element).addClass('k-filtercell');
                var wrapper = this.wrapper = $('<span/>').appendTo(element);
                var that = this, dataSource, viewModel, passedOptions = options, first, type, operators = that.operators = options.operators || {}, input = that.input = $('<input/>').attr(kendo.attr('bind'), 'value: value').appendTo(wrapper);
                var suggestDataSource = options ? options.suggestDataSource : null;
                if (suggestDataSource) {
                    options = $.extend({}, options, { suggestDataSource: {} });
                }
                Widget.fn.init.call(that, element[0], options);
                if (suggestDataSource) {
                    that.options.suggestDataSource = suggestDataSource;
                }
                options = that.options;
                dataSource = that.dataSource = options.dataSource;
                that.model = dataSource.reader.model;
                type = options.type = STRING;
                var fields = kendo.getter('reader.model.fields', true)(dataSource) || {};
                var target = fields[options.field];
                if (target && target.type) {
                    type = options.type = target.type;
                }
                if (options.values) {
                    options.type = type = ENUM;
                }
                operators = operators[type] || options.operators[type];
                if (!passedOptions.operator) {
                    for (first in operators) {
                        options.operator = first;
                        break;
                    }
                }
                that._parse = function (value) {
                    return value != null ? value + '' : value;
                };
                if (that.model && that.model.fields) {
                    var field = that.model.fields[options.field];
                    if (field) {
                        if (field.parse) {
                            that._parse = proxy(field.parse, field);
                        }
                    }
                }
                that.defaultOperator = options.operator;
                that.viewModel = viewModel = kendo.observable({
                    operator: options.operator,
                    value: null,
                    operatorVisible: function () {
                        var val = this.get('value');
                        return val !== null && val !== undefined && val != 'undefined' || isNonValueFilter(this.get('operator')) && !that._clearInProgress;
                    }
                });
                viewModel.bind(CHANGE, proxy(that.updateDsFilter, that));
                if (type == STRING) {
                    that.initSuggestDataSource(options);
                }
                if (options.inputWidth !== null) {
                    input.addClass('k-sized-input');
                    input.width(options.inputWidth);
                }
                input.attr('aria-label', that._getColumnTitle());
                that._setInputType(options, type);
                if (type != BOOL && options.showOperators !== false) {
                    that._createOperatorDropDown(operators);
                } else {
                    $('<div unselectable="on" />').css('display', 'none').text('eq').appendTo(wrapper);
                    wrapper.addClass('k-operator-hidden');
                }
                that._createClearIcon();
                kendo.bind(this.wrapper, viewModel);
                if (type == STRING) {
                    if (!options.template) {
                        that.setAutoCompleteSource();
                    }
                }
                if (type == ENUM) {
                    that.setComboBoxSource(that.options.values);
                }
                that._refreshUI();
                that._refreshHandler = proxy(that._refreshUI, that);
                that.dataSource.bind(CHANGE, that._refreshHandler);
            },
            _setInputType: function (options, type) {
                var that = this, input = that.input;
                if (typeof options.template == 'function') {
                    options.template.call(that.viewModel, {
                        element: that.input,
                        dataSource: that.suggestDataSource
                    });
                    that._angularItems('compile');
                } else if (type == STRING) {
                    input.attr(kendo.attr('role'), 'autocomplete').attr(kendo.attr('text-field'), options.dataTextField || options.field).attr(kendo.attr('filter'), options.suggestionOperator).attr(kendo.attr('delay'), options.delay).attr(kendo.attr('min-length'), options.minLength).attr(kendo.attr('value-primitive'), true);
                } else if (type == 'date') {
                    input.attr(kendo.attr('role'), 'datepicker');
                } else if (type == BOOL) {
                    input.remove();
                    var radioInput = $('<input type=\'radio\'/>');
                    var wrapper = that.wrapper;
                    var inputName = kendo.guid();
                    var labelTrue = $('<label/>').text(options.messages.isTrue).append(radioInput);
                    radioInput.attr(kendo.attr('bind'), 'checked:value').attr('name', inputName).val('true');
                    var labelFalse = labelTrue.clone().text(options.messages.isFalse);
                    radioInput.clone().val('false').appendTo(labelFalse);
                    wrapper.append([
                        labelTrue,
                        labelFalse
                    ]);
                } else if (type == 'number') {
                    input.attr(kendo.attr('role'), 'numerictextbox').attr('title', that._getColumnTitle());
                } else if (type == ENUM) {
                    input.attr(kendo.attr('role'), 'combobox').attr(kendo.attr('text-field'), 'text').attr(kendo.attr('suggest'), true).attr(kendo.attr('filter'), 'contains').attr(kendo.attr('value-field'), 'value').attr(kendo.attr('value-primitive'), true);
                }
            },
            _getColumnTitle: function () {
                var column = this.options.column;
                return column ? column.title || column.field : '';
            },
            _createOperatorDropDown: function (operators) {
                var items = [], viewModel = this.viewModel;
                for (var prop in operators) {
                    items.push({
                        text: operators[prop],
                        value: prop
                    });
                }
                var dropdown = $('<input class="k-dropdown-operator" ' + kendo.attr('bind') + '="value: operator"/>').appendTo(this.wrapper);
                this.operatorDropDown = dropdown.kendoDropDownList({
                    dataSource: items,
                    dataTextField: 'text',
                    dataValueField: 'value',
                    open: function () {
                        this.popup.element.width(150);
                    },
                    valuePrimitive: true
                }).data('kendoDropDownList');
                viewModel.bind('change', function () {
                    var ariaLabel = operators[viewModel.operator];
                    dropdown.attr('aria-label', ariaLabel);
                });
                this.operatorDropDown.wrapper.find('.k-i-arrow-60-down').removeClass('k-i-arrow-60-down').addClass('k-i-filter');
            },
            initSuggestDataSource: function (options) {
                var suggestDataSource = options.suggestDataSource;
                if (!(suggestDataSource instanceof DataSource)) {
                    if (!options.customDataSource && suggestDataSource) {
                        suggestDataSource.group = undefined;
                    }
                    suggestDataSource = this.suggestDataSource = DataSource.create(suggestDataSource);
                }
                if (!options.customDataSource) {
                    suggestDataSource._pageSize = undefined;
                    suggestDataSource.reader.data = removeDuplicates(suggestDataSource.reader.data, this.options.field);
                }
                this.suggestDataSource = suggestDataSource;
            },
            setAutoCompleteSource: function () {
                var autoComplete = this.input.data('kendoAutoComplete');
                if (autoComplete) {
                    autoComplete.setDataSource(this.suggestDataSource);
                }
            },
            setComboBoxSource: function (values) {
                var dataSource = DataSource.create({ data: values });
                var comboBox = this.input.data('kendoComboBox');
                if (comboBox) {
                    comboBox.setDataSource(dataSource);
                }
            },
            _refreshUI: function () {
                var that = this, filter = findFilterForField(that.dataSource.filter(), this.options.field) || {}, viewModel = that.viewModel;
                that.manuallyUpdatingVM = true;
                filter = $.extend(true, {}, filter);
                if (that.options.type == BOOL) {
                    if (viewModel.value !== filter.value) {
                        that.wrapper.find(':radio').prop('checked', false);
                    }
                }
                if (filter.operator) {
                    viewModel.set('operator', filter.operator);
                }
                viewModel.set('value', filter.value);
                that.manuallyUpdatingVM = false;
            },
            updateDsFilter: function (e) {
                var that = this, model = that.viewModel;
                if (that.manuallyUpdatingVM || e.field == 'operator' && model.value === undefined && !isNonValueFilter(model) || e.field == 'operator' && that._clearInProgress && model.value !== null) {
                    return;
                }
                var currentFilter = $.extend({}, that.viewModel.toJSON(), { field: that.options.field });
                var expression = {
                    logic: 'and',
                    filters: []
                };
                var prevented = false;
                if (currentFilter.value !== undefined && currentFilter.value !== null || isNonValueFilter(currentFilter) && !this._clearInProgress) {
                    expression.filters.push(currentFilter);
                    prevented = that.trigger(CHANGE, {
                        filter: expression,
                        field: that.options.field
                    });
                }
                if (that._clearInProgress || currentFilter.value === null) {
                    prevented = that.trigger(CHANGE, {
                        filter: null,
                        field: that.options.field
                    });
                }
                if (prevented) {
                    return;
                }
                var mergeResult = that._merge(expression);
                if (mergeResult.filters.length) {
                    that.dataSource.filter(mergeResult);
                } else {
                    that.dataSource.filter({});
                }
            },
            _merge: function (expression) {
                var that = this, logic = expression.logic || 'and', filters = expression.filters, filter, result = that.dataSource.filter() || {
                        filters: [],
                        logic: 'and'
                    }, idx, length;
                removeFiltersForField(result, that.options.field);
                for (idx = 0, length = filters.length; idx < length; idx++) {
                    filter = filters[idx];
                    filter.value = that._parse(filter.value);
                }
                filters = $.grep(filters, function (filter) {
                    return filter.value !== '' && filter.value !== null || isNonValueFilter(filter);
                });
                if (filters.length) {
                    if (result.filters.length) {
                        expression.filters = filters;
                        if (result.logic !== 'and') {
                            result.filters = [{
                                    logic: result.logic,
                                    filters: result.filters
                                }];
                            result.logic = 'and';
                        }
                        if (filters.length > 1) {
                            result.filters.push(expression);
                        } else {
                            result.filters.push(filters[0]);
                        }
                    } else {
                        result.filters = filters;
                        result.logic = logic;
                    }
                }
                return result;
            },
            _createClearIcon: function () {
                var that = this;
                $('<button type=\'button\' class=\'k-button k-button-icon\' title = ' + that.options.messages.clear + '/>').attr('aria-label', that.options.messages.clear).attr(kendo.attr('bind'), 'visible:operatorVisible').html('<span class=\'k-icon k-i-filter-clear\'/>').click(proxy(that.clearFilter, that)).appendTo(that.wrapper);
            },
            clearFilter: function () {
                this._clearInProgress = true;
                if (isNonValueFilter(this.viewModel.operator)) {
                    this.viewModel.set('operator', this.defaultOperator);
                }
                this.viewModel.set('value', null);
                this._clearInProgress = false;
            },
            _angularItems: function (action) {
                var elements = this.wrapper.closest('th').get();
                var column = this.options.column;
                this.angular(action, function () {
                    return {
                        elements: elements,
                        data: [{ column: column }]
                    };
                });
            },
            destroy: function () {
                var that = this;
                that.filterModel = null;
                that.operatorDropDown = null;
                that._angularItems('cleanup');
                if (that._refreshHandler) {
                    that.dataSource.bind(CHANGE, that._refreshHandler);
                    that._refreshHandler = null;
                }
                kendo.unbind(that.element);
                Widget.fn.destroy.call(that);
                kendo.destroy(that.element);
            },
            events: [CHANGE],
            options: {
                name: 'FilterCell',
                delay: 200,
                minLength: 1,
                inputWidth: null,
                values: undefined,
                customDataSource: false,
                field: '',
                dataTextField: '',
                type: 'string',
                suggestDataSource: null,
                suggestionOperator: 'startswith',
                operator: 'eq',
                showOperators: true,
                template: null,
                messages: {
                    isTrue: 'is true',
                    isFalse: 'is false',
                    filter: 'Filter',
                    clear: 'Clear',
                    operator: 'Operator'
                },
                operators: {
                    string: {
                        eq: EQ,
                        neq: NEQ,
                        startswith: 'Starts with',
                        contains: 'Contains',
                        doesnotcontain: 'Does not contain',
                        endswith: 'Ends with',
                        isnull: 'Is null',
                        isnotnull: 'Is not null',
                        isempty: 'Is empty',
                        isnotempty: 'Is not empty',
                        isnullorempty: 'Has no value',
                        isnotnullorempty: 'Has value'
                    },
                    number: {
                        eq: EQ,
                        neq: NEQ,
                        gte: 'Is greater than or equal to',
                        gt: 'Is greater than',
                        lte: 'Is less than or equal to',
                        lt: 'Is less than',
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    },
                    date: {
                        eq: EQ,
                        neq: NEQ,
                        gte: 'Is after or equal to',
                        gt: 'Is after',
                        lte: 'Is before or equal to',
                        lt: 'Is before',
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    },
                    enums: {
                        eq: EQ,
                        neq: NEQ,
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    }
                }
            }
        });
        ui.plugin(FilterCell);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.panelbar', ['kendo.data'], f);
}(function () {
    var __meta__ = {
        id: 'panelbar',
        name: 'PanelBar',
        category: 'web',
        description: 'The PanelBar widget displays hierarchical data as a multi-level expandable panel bar.',
        depends: [
            'core',
            'data',
            'data.odata'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, keys = kendo.keys, extend = $.extend, proxy = $.proxy, each = $.each, isArray = $.isArray, template = kendo.template, Widget = ui.Widget, HierarchicalDataSource = kendo.data.HierarchicalDataSource, excludedNodesRegExp = /^(ul|a|div)$/i, NS = '.kendoPanelBar', IMG = 'img', HREF = 'href', LAST = 'k-last', LINK = 'k-link', LINKSELECTOR = '.' + LINK, ERROR = 'error', ITEM = '.k-item', GROUP = '.k-group', VISIBLEGROUP = GROUP + ':visible', IMAGE = 'k-image', FIRST = 'k-first', CHANGE = 'change', EXPAND = 'expand', SELECT = 'select', CONTENT = 'k-content', ACTIVATE = 'activate', COLLAPSE = 'collapse', DATABOUND = 'dataBound', MOUSEENTER = 'mouseenter', MOUSELEAVE = 'mouseleave', CONTENTLOAD = 'contentLoad', UNDEFINED = 'undefined', ACTIVECLASS = 'k-state-active', GROUPS = '> .k-panel', CONTENTS = '> .k-content', STRING = 'string', FOCUSEDCLASS = 'k-state-focused', DISABLEDCLASS = 'k-state-disabled', SELECTEDCLASS = 'k-state-selected', SELECTEDSELECTOR = '.' + SELECTEDCLASS, HIGHLIGHTCLASS = 'k-state-highlight', ACTIVEITEMSELECTOR = ITEM + ':not(.k-state-disabled)', clickableItems = '> ' + ACTIVEITEMSELECTOR + ' > ' + LINKSELECTOR + ', .k-panel > ' + ACTIVEITEMSELECTOR + ' > ' + LINKSELECTOR, disabledItems = ITEM + '.k-state-disabled > .k-link', selectableItems = '> li > ' + SELECTEDSELECTOR + ', .k-panel > li > ' + SELECTEDSELECTOR, defaultState = 'k-state-default', ARIA_DISABLED = 'aria-disabled', ARIA_EXPANDED = 'aria-expanded', ARIA_HIDDEN = 'aria-hidden', ARIA_SELECTED = 'aria-selected', VISIBLE = ':visible', EMPTY = ':empty', SINGLE = 'single', bindings = {
                text: 'dataTextField',
                url: 'dataUrlField',
                spriteCssClass: 'dataSpriteCssClassField',
                imageUrl: 'dataImageUrlField'
            }, itemIcon, rendering = {
                aria: function (item) {
                    var attr = '';
                    if (item.items || item.content || item.contentUrl || item.expanded) {
                        attr += ARIA_EXPANDED + '=\'' + (item.expanded ? 'true' : 'false') + '\' ';
                    }
                    if (item.enabled === false) {
                        attr += ARIA_DISABLED + '=\'true\'';
                    }
                    return attr;
                },
                wrapperCssClass: function (group, item) {
                    var result = 'k-item', index = item.index;
                    if (item.enabled === false) {
                        result += ' ' + DISABLEDCLASS;
                    } else if (item.expanded === true) {
                        result += ' ' + ACTIVECLASS;
                    } else {
                        result += ' k-state-default';
                    }
                    if (index === 0) {
                        result += ' k-first';
                    }
                    if (index == group.length - 1) {
                        result += ' k-last';
                    }
                    if (item.cssClass) {
                        result += ' ' + item.cssClass;
                    }
                    return result;
                },
                textClass: function (item, group) {
                    var result = LINK;
                    if (group.firstLevel) {
                        result += ' k-header';
                    }
                    if (item.selected) {
                        result += ' ' + SELECTEDCLASS;
                    }
                    return result;
                },
                textAttributes: function (url) {
                    return url ? ' href=\'' + url + '\'' : '';
                },
                arrowClass: function (item) {
                    var result = 'k-icon';
                    result += item.expanded ? ' k-panelbar-collapse k-i-arrow-60-up' : ' k-panelbar-expand k-i-arrow-60-down';
                    return result;
                },
                text: function (item) {
                    return item.encoded === false ? item.text : kendo.htmlEncode(item.text);
                },
                groupAttributes: function (group) {
                    return group.expanded !== true ? ' style=\'display:none\'' : '';
                },
                ariaHidden: function (group) {
                    return group.expanded !== true;
                },
                groupCssClass: function () {
                    return 'k-group k-panel';
                },
                contentAttributes: function (content) {
                    return content.item.expanded !== true ? ' style=\'display:none\'' : '';
                },
                content: function (item) {
                    return item.content ? item.content : item.contentUrl ? '' : '&nbsp;';
                },
                contentUrl: function (item) {
                    return item.contentUrl ? 'href="' + item.contentUrl + '"' : '';
                }
            };
        function updateFirstLast(items) {
            items = $(items);
            items.filter('.k-first:not(:first-child)').removeClass(FIRST);
            items.filter('.k-last:not(:last-child)').removeClass(LAST);
            items.filter(':first-child').addClass(FIRST);
            items.filter(':last-child').addClass(LAST);
        }
        function updateItemHtml(item) {
            var wrapper = item, group = item.children('ul'), toggleButton = wrapper.children('.k-link').children('.k-icon');
            if (item.hasClass('k-panelbar')) {
                return;
            }
            if (!toggleButton.length && group.length) {
                toggleButton = $('<span class=\'k-icon\' />').appendTo(wrapper);
            } else if (!group.length || !group.children().length) {
                toggleButton.remove();
                group.remove();
            }
        }
        itemIcon = function (item) {
            return item.children('span').children('.k-icon');
        };
        var PanelBar = kendo.ui.DataBoundWidget.extend({
            init: function (element, options) {
                var that = this, content, hasDataSource;
                if (isArray(options)) {
                    options = { dataSource: options };
                }
                hasDataSource = options && !!options.dataSource;
                Widget.fn.init.call(that, element, options);
                element = that.wrapper = that.element.addClass('k-widget k-reset k-header k-panelbar');
                options = that.options;
                if (element[0].id) {
                    that._itemId = element[0].id + '_pb_active';
                }
                that._tabindex();
                that._accessors();
                that._dataSource();
                that._templates();
                that._initData(hasDataSource);
                that._updateClasses();
                that._animations(options);
                element.on('click' + NS, clickableItems, function (e) {
                    if (that._click($(e.currentTarget))) {
                        e.preventDefault();
                    }
                }).on(MOUSEENTER + NS + ' ' + MOUSELEAVE + NS, clickableItems, that._toggleHover).on('click' + NS, disabledItems, false).on('click' + NS, '.k-request-retry', proxy(that._retryRequest, that)).on('keydown' + NS, $.proxy(that._keydown, that)).on('focus' + NS, function () {
                    var item = that.select();
                    that._current(item[0] ? item : that._first());
                }).on('blur' + NS, function () {
                    that._current(null);
                }).attr('role', 'menu');
                content = element.find('li.' + ACTIVECLASS + ' > .' + CONTENT);
                if (content[0]) {
                    that.expand(content.parent(), false);
                }
                if (!options.dataSource) {
                    that._angularCompile();
                }
                kendo.notify(that);
            },
            events: [
                EXPAND,
                COLLAPSE,
                SELECT,
                ACTIVATE,
                CHANGE,
                ERROR,
                DATABOUND,
                CONTENTLOAD
            ],
            options: {
                name: 'PanelBar',
                dataSource: {},
                animation: {
                    expand: {
                        effects: 'expand:vertical',
                        duration: 200
                    },
                    collapse: { duration: 200 }
                },
                messages: {
                    loading: 'Loading...',
                    requestFailed: 'Request failed.',
                    retry: 'Retry'
                },
                autoBind: true,
                loadOnDemand: true,
                expandMode: 'multiple',
                template: '',
                dataTextField: null
            },
            _angularCompile: function () {
                var that = this;
                that.angular('compile', function () {
                    return {
                        elements: that.element.children('li'),
                        data: [{ dataItem: that.options.$angular }]
                    };
                });
            },
            _angularCompileElements: function (html, items) {
                var that = this;
                that.angular('compile', function () {
                    return {
                        elements: html,
                        data: $.map(items, function (item) {
                            return [{ dataItem: item }];
                        })
                    };
                });
            },
            _angularCleanup: function () {
                var that = this;
                that.angular('cleanup', function () {
                    return { elements: that.element.children('li') };
                });
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.element.off(NS);
                this._angularCleanup();
                kendo.destroy(this.element);
            },
            _initData: function (hasDataSource) {
                var that = this;
                if (hasDataSource) {
                    that.element.empty();
                    if (that.options.autoBind) {
                        that._progress(true);
                        that.dataSource.fetch();
                    }
                }
            },
            _templates: function () {
                var that = this, options = that.options, fieldAccessor = proxy(that._fieldAccessor, that);
                if (options.template && typeof options.template == STRING) {
                    options.template = template(options.template);
                } else if (!options.template) {
                    options.template = template('# var text = ' + fieldAccessor('text') + '(data.item); #' + '# if (typeof data.item.encoded != \'undefined\' && data.item.encoded === false) {#' + '#= text #' + '# } else { #' + '#: text #' + '# } #');
                }
                that.templates = {
                    content: template('<div role=\'region\' class=\'k-content\'#= contentAttributes(data) #>#= content(item) #</div>'),
                    group: template('<ul role=\'group\' aria-hidden=\'#= ariaHidden(group) #\' class=\'#= groupCssClass(group) #\'#= groupAttributes(group) #>' + '#= renderItems(data) #' + '</ul>'),
                    itemWrapper: template('# var url = ' + fieldAccessor('url') + '(item); #' + '# var imageUrl = ' + fieldAccessor('imageUrl') + '(item); #' + '# var spriteCssClass = ' + fieldAccessor('spriteCssClass') + '(item); #' + '# var contentUrl = contentUrl(item); #' + '# var tag = url||contentUrl ? \'a\' : \'span\'; #' + '<#= tag # class=\'#= textClass(item, group) #\' #= contentUrl ##= textAttributes(url) #>' + '# if (imageUrl) { #' + '<img class=\'k-image\' alt=\'\' src=\'#= imageUrl #\' />' + '# } #' + '# if (spriteCssClass) { #' + '<span class=\'k-sprite #= spriteCssClass #\'></span>' + '# } #' + '#= data.panelBar.options.template(data) #' + '#= arrow(data) #' + '</#= tag #>'),
                    item: template('<li role=\'menuitem\' #=aria(item)#class=\'#= wrapperCssClass(group, item) #\'' + kendo.attr('uid') + '=\'#= item.uid #\'>' + '#= itemWrapper(data) #' + '# if (item.items && item.items.length > 0) { #' + '#= subGroup({ items: item.items, panelBar: panelBar, group: { expanded: item.expanded } }) #' + '# } else if (item.content || item.contentUrl) { #' + '#= renderContent(data) #' + '# } #' + '</li>'),
                    loading: template('<div class=\'k-item\'><span class=\'k-icon k-i-loading\'></span> #: data.messages.loading #</div>'),
                    retry: template('#: data.messages.requestFailed # ' + '<button class=\'k-button k-request-retry\'>#: data.messages.retry #</button>'),
                    arrow: template('<span class=\'#= arrowClass(item) #\'></span>'),
                    empty: template('')
                };
            },
            setOptions: function (options) {
                var animation = this.options.animation;
                this._animations(options);
                options.animation = extend(true, animation, options.animation);
                if ('dataSource' in options) {
                    this.setDataSource(options.dataSource);
                }
                Widget.fn.setOptions.call(this, options);
            },
            expand: function (element, useAnimation) {
                var that = this, animBackup = {};
                element = this.element.find(element);
                if (that._animating && element.find('ul').is(':visible')) {
                    that.one('complete', function () {
                        setTimeout(function () {
                            that.expand(element);
                        });
                    });
                    return;
                }
                that._animating = true;
                useAnimation = useAnimation !== false;
                element.each(function (index, item) {
                    item = $(item);
                    var wrapper = element.children('.k-group,.k-content');
                    if (!wrapper.length) {
                        wrapper = that._addGroupElement(element);
                    }
                    var groups = wrapper.add(item.find(CONTENTS));
                    if (!item.hasClass(DISABLEDCLASS) && groups.length > 0) {
                        if (that.options.expandMode == SINGLE && that._collapseAllExpanded(item)) {
                            return that;
                        }
                        element.find('.' + HIGHLIGHTCLASS).removeClass(HIGHLIGHTCLASS);
                        item.addClass(HIGHLIGHTCLASS);
                        if (!useAnimation) {
                            animBackup = that.options.animation;
                            that.options.animation = {
                                expand: { effects: {} },
                                collapse: {
                                    hide: true,
                                    effects: {}
                                }
                            };
                        }
                        if (!that._triggerEvent(EXPAND, item)) {
                            that._toggleItem(item, false, false);
                        }
                        if (!useAnimation) {
                            that.options.animation = animBackup;
                        }
                    }
                });
                return that;
            },
            collapse: function (element, useAnimation) {
                var that = this, animBackup = {};
                that._animating = true;
                useAnimation = useAnimation !== false;
                element = that.element.find(element);
                element.each(function (index, item) {
                    item = $(item);
                    var groups = item.find(GROUPS).add(item.find(CONTENTS));
                    if (!item.hasClass(DISABLEDCLASS) && groups.is(VISIBLE)) {
                        item.removeClass(HIGHLIGHTCLASS);
                        if (!useAnimation) {
                            animBackup = that.options.animation;
                            that.options.animation = {
                                expand: { effects: {} },
                                collapse: {
                                    hide: true,
                                    effects: {}
                                }
                            };
                        }
                        if (!that._triggerEvent(COLLAPSE, item)) {
                            that._toggleItem(item, true);
                        }
                        if (!useAnimation) {
                            that.options.animation = animBackup;
                        }
                    }
                });
                return that;
            },
            updateArrow: function (items) {
                var that = this;
                items = $(items);
                items.children(LINKSELECTOR).children('.k-panelbar-collapse, .k-panelbar-expand').remove();
                items.filter(function () {
                    var dataItem = that.dataItem(this);
                    if (!dataItem) {
                        return $(this).find('.k-panel').length > 0 || $(this).find('.k-content').length > 0;
                    }
                    return dataItem.hasChildren || dataItem.content || dataItem.contentUrl;
                }).children('.k-link:not(:has([class*=k-i-arrow]))').each(function () {
                    var item = $(this), parent = item.parent();
                    item.append('<span class=\'k-icon ' + (parent.hasClass(ACTIVECLASS) ? ' k-panelbar-collapse k-i-arrow-60-up' : ' k-panelbar-expand k-i-arrow-60-down') + '\'/>');
                });
            },
            _accessors: function () {
                var that = this, options = that.options, i, field, textField, element = that.element;
                for (i in bindings) {
                    field = options[bindings[i]];
                    textField = element.attr(kendo.attr(i + '-field'));
                    if (!field && textField) {
                        field = textField;
                    }
                    if (!field) {
                        field = i;
                    }
                    if (!isArray(field)) {
                        field = [field];
                    }
                    options[bindings[i]] = field;
                }
            },
            _progress: function (item, showProgress) {
                var element = this.element;
                var loadingText = this.templates.loading({ messages: this.options.messages });
                if (arguments.length == 1) {
                    showProgress = item;
                    if (showProgress) {
                        element.html(loadingText);
                    } else {
                        element.empty();
                    }
                } else {
                    itemIcon(item).toggleClass('k-i-loading', showProgress).removeClass('k-i-refresh');
                }
            },
            _refreshRoot: function (items) {
                var that = this;
                var parent = that.element;
                var groupData = {
                    firstLevel: true,
                    expanded: true,
                    length: parent.children().length
                };
                this.element.empty();
                var rootItemsHtml = $.map(items, function (value, idx) {
                    if (typeof value === 'string') {
                        return $(value);
                    } else {
                        value.items = [];
                        return $(that.renderItem({
                            group: groupData,
                            item: extend(value, { index: idx })
                        }));
                    }
                });
                this.element.append(rootItemsHtml);
                var elements = this.element.children('.k-item');
                for (var i = 0; i < items.length; i++) {
                    this.trigger('itemChange', {
                        item: elements.eq(i).find('.k-link').first(),
                        data: items[i],
                        ns: ui
                    });
                }
                this._angularCompileElements(rootItemsHtml, items);
            },
            _refreshChildren: function (item, parentNode) {
                var i, children, child;
                parentNode.children('.k-group').empty();
                var items = item.children.data();
                if (!items.length) {
                    updateItemHtml(parentNode);
                    children = parentNode.children('.k-group').children('li');
                    this._angularCompileElements(children, items);
                } else {
                    this.append(item.children, parentNode);
                    if (this.options.loadOnDemand) {
                        this._toggleGroup(parentNode.children('.k-group'), false);
                    }
                    children = parentNode.children('.k-group').children('li');
                    for (i = 0; i < children.length; i++) {
                        child = children.eq(i);
                        this.trigger('itemChange', {
                            item: child.find('.k-link').first(),
                            data: this.dataItem(child),
                            ns: ui
                        });
                    }
                }
            },
            findByUid: function (uid) {
                var items = this.element.find('.k-item');
                var uidAttr = kendo.attr('uid');
                var result;
                for (var i = 0; i < items.length; i++) {
                    if (items[i].getAttribute(uidAttr) == uid) {
                        result = items[i];
                        break;
                    }
                }
                return $(result);
            },
            refresh: function (e) {
                var options = this.options;
                var node = e.node;
                var action = e.action;
                var items = e.items;
                var parentNode = this.wrapper;
                var loadOnDemand = options.loadOnDemand;
                if (e.field) {
                    if (!items[0] || !items[0].level) {
                        return;
                    }
                    return this._updateItems(items, e.field);
                }
                if (node) {
                    parentNode = this.findByUid(node.uid);
                    this._progress(parentNode, false);
                }
                if (action == 'add') {
                    this._appendItems(e.index, items, parentNode);
                } else if (action == 'remove') {
                    this.remove(this.findByUid(items[0].uid));
                } else if (action == 'itemchange') {
                    this._updateItems(items);
                } else if (action == 'itemloaded') {
                    this._refreshChildren(node, parentNode);
                } else {
                    this._refreshRoot(items);
                }
                if (action != 'remove') {
                    for (var k = 0; k < items.length; k++) {
                        if (!loadOnDemand || items[k].expanded) {
                            var tempItem = items[k];
                            if (this._hasChildItems(tempItem)) {
                                tempItem.load();
                            }
                        }
                    }
                }
                this.trigger(DATABOUND, { node: node ? parentNode : undefined });
            },
            _error: function (e) {
                var node = e.node && this.findByUid(e.node.uid);
                var retryHtml = this.templates.retry({ messages: this.options.messages });
                if (node) {
                    this._progress(node, false);
                    this._expanded(node, false);
                    itemIcon(node).addClass('k-i-refresh');
                    e.node.loaded(false);
                } else {
                    this._progress(false);
                    this.element.html(retryHtml);
                }
            },
            _retryRequest: function (e) {
                e.preventDefault();
                this.dataSource.fetch();
            },
            items: function () {
                return this.element.find('.k-item > span:first-child');
            },
            setDataSource: function (dataSource) {
                var options = this.options;
                options.dataSource = dataSource;
                this._dataSource();
                if (this.options.autoBind) {
                    this._progress(true);
                    this.dataSource.fetch();
                }
            },
            _bindDataSource: function () {
                this._refreshHandler = proxy(this.refresh, this);
                this._errorHandler = proxy(this._error, this);
                this.dataSource.bind(CHANGE, this._refreshHandler);
                this.dataSource.bind(ERROR, this._errorHandler);
            },
            _unbindDataSource: function () {
                var dataSource = this.dataSource;
                if (dataSource) {
                    dataSource.unbind(CHANGE, this._refreshHandler);
                    dataSource.unbind(ERROR, this._errorHandler);
                }
            },
            _fieldAccessor: function (fieldName) {
                var fieldBindings = this.options[bindings[fieldName]] || [], count = fieldBindings.length, result = '(function(item) {';
                if (count === 0) {
                    result += 'return item[\'' + fieldName + '\'];';
                } else {
                    result += 'var levels = [' + $.map(fieldBindings, function (x) {
                        return 'function(d){ return ' + kendo.expr(x) + '}';
                    }).join(',') + '];';
                    result += 'if(item.level){return levels[Math.min(item.level(), ' + count + '-1)](item);}else';
                    result += '{return levels[' + count + '-1](item)}';
                }
                result += '})';
                return result;
            },
            _dataSource: function () {
                var that = this, options = that.options, dataSource = options.dataSource;
                if (!dataSource) {
                    return;
                }
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                that._unbindDataSource();
                if (!dataSource.fields) {
                    dataSource.fields = [
                        { field: 'text' },
                        { field: 'url' },
                        { field: 'spriteCssClass' },
                        { field: 'imageUrl' }
                    ];
                }
                that.dataSource = HierarchicalDataSource.create(dataSource);
                that._bindDataSource();
            },
            _appendItems: function (index, items, parentNode) {
                var that = this, children, wrapper;
                if (parentNode.hasClass('k-panelbar')) {
                    children = parentNode.children('li');
                    wrapper = parentNode;
                } else {
                    wrapper = parentNode.children('.k-group');
                    if (!wrapper.length) {
                        wrapper = that._addGroupElement(parentNode);
                    }
                    children = wrapper.children('li');
                }
                var groupData = {
                    firstLevel: parentNode.hasClass('k-panelbar'),
                    expanded: true,
                    length: children.length
                };
                var itemsHtml = $.map(items, function (value, idx) {
                    if (typeof value === 'string') {
                        return $(value);
                    } else {
                        return $(that.renderItem({
                            group: groupData,
                            item: extend(value, { index: idx })
                        }));
                    }
                });
                if (typeof index == UNDEFINED) {
                    index = children.length;
                }
                for (var i = 0; i < itemsHtml.length; i++) {
                    if (children.length === 0 || index === 0) {
                        wrapper.append(itemsHtml[i]);
                    } else {
                        itemsHtml[i].insertAfter(children[index - 1]);
                    }
                }
                that._angularCompileElements(itemsHtml, items);
                if (that.dataItem(parentNode)) {
                    that.dataItem(parentNode).hasChildren = true;
                    that.updateArrow(parentNode);
                }
            },
            _updateItems: function (items, field) {
                var that = this;
                var i, node, nodeWrapper, item;
                var context = {
                    panelBar: that.options,
                    item: item,
                    group: {}
                };
                var render = field != 'expanded';
                if (field == 'selected') {
                    if (items[0][field]) {
                        var currentNode = that.findByUid(items[0].uid);
                        if (!currentNode.hasClass(DISABLEDCLASS)) {
                            that.select(currentNode, true);
                        }
                    } else {
                        that.clearSelection();
                    }
                } else {
                    var elements = $.map(items, function (item) {
                        return that.findByUid(item.uid);
                    });
                    if (render) {
                        that.angular('cleanup', function () {
                            return { elements: elements };
                        });
                    }
                    for (i = 0; i < items.length; i++) {
                        context.item = item = items[i];
                        context.panelBar = that;
                        nodeWrapper = elements[i];
                        node = nodeWrapper.parent();
                        if (render) {
                            context.group = {
                                firstLevel: node.hasClass('k-panelbar'),
                                expanded: nodeWrapper.parent().hasClass(ACTIVECLASS),
                                length: nodeWrapper.children().length
                            };
                            nodeWrapper.children('.k-link').remove();
                            nodeWrapper.prepend(that.templates.itemWrapper(extend(context, { arrow: item.hasChildren || item.content || item.contentUrl ? that.templates.arrow : that.templates.empty }, rendering)));
                        }
                        if (field == 'expanded') {
                            that._toggleItem(nodeWrapper, !item[field], item[field] ? 'true' : true);
                        } else if (field == 'enabled') {
                            that.enable(nodeWrapper, item[field]);
                            if (!item[field]) {
                                if (item.selected) {
                                    item.set('selected', false);
                                }
                            }
                        }
                        if (nodeWrapper.length) {
                            this.trigger('itemChange', {
                                item: nodeWrapper.find('.k-link').first(),
                                data: item,
                                ns: ui
                            });
                        }
                    }
                    if (render) {
                        that.angular('compile', function () {
                            return {
                                elements: elements,
                                data: $.map(items, function (item) {
                                    return [{ dataItem: item }];
                                })
                            };
                        });
                    }
                }
            },
            _toggleDisabled: function (element, enable) {
                element = this.element.find(element);
                element.toggleClass(defaultState, enable).toggleClass(DISABLEDCLASS, !enable).attr(ARIA_DISABLED, !enable);
            },
            dataItem: function (item) {
                var uid = $(item).closest(ITEM).attr(kendo.attr('uid')), dataSource = this.dataSource;
                return dataSource && dataSource.getByUid(uid);
            },
            select: function (element, skipChange) {
                var that = this;
                if (element === undefined) {
                    return that.element.find(selectableItems).parent();
                }
                element = that.element.find(element);
                if (!element.length) {
                    this._updateSelected(element);
                } else {
                    element.each(function () {
                        var item = $(this), link = item.children(LINKSELECTOR);
                        if (item.hasClass(DISABLEDCLASS)) {
                            return that;
                        }
                        that._updateSelected(link, skipChange);
                    });
                }
                return that;
            },
            clearSelection: function () {
                this.select($());
            },
            enable: function (element, state) {
                this._toggleDisabled(element, state !== false);
                return this;
            },
            disable: function (element) {
                this._toggleDisabled(element, false);
                return this;
            },
            append: function (item, referenceItem) {
                referenceItem = this.element.find(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.length ? referenceItem.find(GROUPS) : null);
                each(inserted.items, function () {
                    inserted.group.append(this);
                    updateFirstLast(this);
                });
                this.updateArrow(referenceItem);
                updateFirstLast(inserted.group.find('.k-first, .k-last'));
                inserted.group.height('auto');
                return this;
            },
            insertBefore: function (item, referenceItem) {
                referenceItem = this.element.find(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.parent());
                each(inserted.items, function () {
                    referenceItem.before(this);
                    updateFirstLast(this);
                });
                updateFirstLast(referenceItem);
                inserted.group.height('auto');
                return this;
            },
            insertAfter: function (item, referenceItem) {
                referenceItem = this.element.find(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.parent());
                each(inserted.items, function () {
                    referenceItem.after(this);
                    updateFirstLast(this);
                });
                updateFirstLast(referenceItem);
                inserted.group.height('auto');
                return this;
            },
            remove: function (element) {
                element = this.element.find(element);
                var that = this, parent = element.parentsUntil(that.element, ITEM), group = element.parent('ul');
                element.remove();
                if (group && !group.hasClass('k-panelbar') && !group.children(ITEM).length) {
                    group.remove();
                }
                if (parent.length) {
                    parent = parent.eq(0);
                    that.updateArrow(parent);
                    updateFirstLast(parent);
                }
                return that;
            },
            reload: function (element) {
                var that = this;
                element = that.element.find(element);
                element.each(function () {
                    var item = $(this);
                    that._ajaxRequest(item, item.children('.' + CONTENT), !item.is(VISIBLE));
                });
            },
            _first: function () {
                return this.element.children(ACTIVEITEMSELECTOR).first();
            },
            _last: function () {
                var item = this.element.children(ACTIVEITEMSELECTOR).last(), group = item.children(VISIBLEGROUP);
                if (group[0]) {
                    return group.children(ACTIVEITEMSELECTOR).last();
                }
                return item;
            },
            _current: function (candidate) {
                var that = this, focused = that._focused, id = that._itemId;
                if (candidate === undefined) {
                    return focused;
                }
                that.element.removeAttr('aria-activedescendant');
                if (focused && focused.length) {
                    if (focused[0].id === id) {
                        focused.removeAttr('id');
                    }
                    focused.children(LINKSELECTOR).removeClass(FOCUSEDCLASS);
                }
                if ($(candidate).length) {
                    id = candidate[0].id || id;
                    candidate.attr('id', id).children(LINKSELECTOR).addClass(FOCUSEDCLASS);
                    that.element.attr('aria-activedescendant', id);
                }
                that._focused = candidate;
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, current = that._current();
                if (e.target != e.currentTarget) {
                    return;
                }
                if (key == keys.DOWN || key == keys.RIGHT) {
                    that._current(that._nextItem(current));
                    e.preventDefault();
                } else if (key == keys.UP || key == keys.LEFT) {
                    that._current(that._prevItem(current));
                    e.preventDefault();
                } else if (key == keys.ENTER || key == keys.SPACEBAR) {
                    that._click(current.children(LINKSELECTOR));
                    e.preventDefault();
                } else if (key == keys.HOME) {
                    that._current(that._first());
                    e.preventDefault();
                } else if (key == keys.END) {
                    that._current(that._last());
                    e.preventDefault();
                }
            },
            _nextItem: function (item) {
                if (!item) {
                    return this._first();
                }
                var group = item.children(VISIBLEGROUP), next = item.nextAll(':visible').first();
                if (group[0]) {
                    next = group.children('.' + FIRST);
                }
                if (!next[0]) {
                    next = item.parent(VISIBLEGROUP).parent(ITEM).next();
                }
                if (!next[0]) {
                    next = this._first();
                }
                if (next.hasClass(DISABLEDCLASS)) {
                    next = this._nextItem(next);
                }
                return next;
            },
            _prevItem: function (item) {
                if (!item) {
                    return this._last();
                }
                var prev = item.prevAll(':visible').first(), result;
                if (!prev[0]) {
                    prev = item.parent(VISIBLEGROUP).parent(ITEM);
                    if (!prev[0]) {
                        prev = this._last();
                    }
                } else {
                    result = prev;
                    while (result[0]) {
                        result = result.children(VISIBLEGROUP).children('.' + LAST);
                        if (result[0]) {
                            prev = result;
                        }
                    }
                }
                if (prev.hasClass(DISABLEDCLASS)) {
                    prev = this._prevItem(prev);
                }
                return prev;
            },
            _insert: function (item, referenceItem, parent) {
                var that = this, items, plain = $.isPlainObject(item), isReferenceItem = referenceItem && referenceItem[0], groupData;
                if (!isReferenceItem) {
                    parent = that.element;
                }
                groupData = {
                    firstLevel: parent.hasClass('k-panelbar'),
                    expanded: $(referenceItem).hasClass(ACTIVECLASS),
                    length: parent.children().length
                };
                if (isReferenceItem && !parent.length) {
                    parent = $(that.renderGroup({
                        group: groupData,
                        options: that.options
                    })).appendTo(referenceItem);
                }
                if (plain || $.isArray(item) || item instanceof HierarchicalDataSource) {
                    if (item instanceof HierarchicalDataSource) {
                        item = item.data();
                    }
                    items = $.map(plain ? [item] : item, function (value, idx) {
                        if (typeof value === 'string') {
                            return $(value);
                        } else {
                            return $(that.renderItem({
                                group: groupData,
                                item: extend(value, { index: idx })
                            }));
                        }
                    });
                    if (isReferenceItem) {
                        var dataItem = that.dataItem(referenceItem);
                        if (dataItem) {
                            dataItem.hasChildren = true;
                            referenceItem.attr(ARIA_EXPANDED, dataItem.expanded).not('.' + ACTIVECLASS).children('ul').attr(ARIA_HIDDEN, !dataItem.expanded);
                        } else {
                            referenceItem.attr(ARIA_EXPANDED, false);
                        }
                    }
                } else {
                    if (typeof item == 'string' && item.charAt(0) != '<') {
                        items = that.element.find(item);
                    } else {
                        items = $(item);
                    }
                    that._updateItemsClasses(items);
                }
                if (!item.length) {
                    item = [item];
                }
                that._angularCompileElements(items, item);
                return {
                    items: items,
                    group: parent
                };
            },
            _toggleHover: function (e) {
                var target = $(e.currentTarget);
                if (!target.parents('li.' + DISABLEDCLASS).length) {
                    target.toggleClass('k-state-hover', e.type == MOUSEENTER);
                }
            },
            _updateClasses: function () {
                var that = this, panels, items, expanded, panelsParent, dataItem;
                panels = that.element.find('li > ul').not(function () {
                    return $(this).parentsUntil('.k-panelbar', 'div').length;
                }).addClass('k-group k-panel').attr('role', 'group');
                panelsParent = panels.parent();
                dataItem = that.dataItem(panelsParent);
                expanded = dataItem && dataItem.expanded || false;
                panels.parent().attr(ARIA_EXPANDED, expanded).not('.' + ACTIVECLASS).children('ul').attr(ARIA_HIDDEN, !expanded).hide();
                items = that.element.add(panels).children();
                that._updateItemsClasses(items);
                that.updateArrow(items);
                updateFirstLast(items);
            },
            _updateItemsClasses: function (items) {
                var length = items.length, idx = 0;
                for (; idx < length; idx++) {
                    this._updateItemClasses(items[idx], idx);
                }
            },
            _updateItemClasses: function (item, index) {
                var selected = this._selected, contentUrls = this.options.contentUrls, url = contentUrls && contentUrls[index], root = this.element[0], wrapElement, link;
                item = $(item).addClass('k-item').attr('role', 'menuitem');
                if (kendo.support.browser.msie) {
                    item.css('list-style-position', 'inside').css('list-style-position', '');
                }
                item.children(IMG).addClass(IMAGE);
                link = item.children('a').addClass(LINK);
                if (link[0]) {
                    link.attr('href', url);
                    link.children(IMG).addClass(IMAGE);
                }
                item.filter(':not([disabled]):not([class*=k-state])').addClass('k-state-default');
                item.filter('li[disabled]').addClass('k-state-disabled').attr(ARIA_DISABLED, true).removeAttr('disabled');
                item.children('div').addClass(CONTENT).attr('role', 'region').attr(ARIA_HIDDEN, true).hide().parent().attr(ARIA_EXPANDED, false);
                link = item.children(SELECTEDSELECTOR);
                if (link[0]) {
                    if (selected) {
                        selected.removeAttr(ARIA_SELECTED).children(SELECTEDSELECTOR).removeClass(SELECTEDCLASS);
                    }
                    link.addClass(SELECTEDCLASS);
                    this._selected = item.attr(ARIA_SELECTED, true);
                }
                if (!item.children(LINKSELECTOR)[0]) {
                    wrapElement = '<span class=\'' + LINK + '\'/>';
                    if (contentUrls && contentUrls[index] && item[0].parentNode == root) {
                        wrapElement = '<a class="k-link k-header" href="' + contentUrls[index] + '"/>';
                    }
                    item.contents().filter(function () {
                        return !this.nodeName.match(excludedNodesRegExp) && !(this.nodeType == 3 && !$.trim(this.nodeValue));
                    }).wrapAll(wrapElement);
                }
                if (item.parent('.k-panelbar')[0]) {
                    item.children(LINKSELECTOR).addClass('k-header');
                }
            },
            _click: function (target) {
                var that = this, element = that.element, prevent, contents, href, isAnchor;
                if (target.parents('li.' + DISABLEDCLASS).length) {
                    return;
                }
                if (target.closest('.k-widget')[0] != element[0]) {
                    return;
                }
                var link = target.closest(LINKSELECTOR), item = link.closest(ITEM);
                that._updateSelected(link);
                var wrapper = item.children('.k-group,.k-content');
                var dataItem = this.dataItem(item);
                if (!wrapper.length && (that.options.loadOnDemand && dataItem && dataItem.hasChildren || this._hasChildItems(item) || item.content || item.contentUrl)) {
                    wrapper = that._addGroupElement(item);
                }
                contents = item.find(GROUPS).add(item.find(CONTENTS));
                href = link.attr(HREF);
                isAnchor = href && (href.charAt(href.length - 1) == '#' || href.indexOf('#' + that.element[0].id + '-') != -1);
                prevent = !!(isAnchor || contents.length);
                if (contents.data('animating')) {
                    return prevent;
                }
                if (that._triggerEvent(SELECT, item)) {
                    prevent = true;
                }
                if (prevent === false) {
                    return;
                }
                if (that.options.expandMode == SINGLE) {
                    if (that._collapseAllExpanded(item)) {
                        return prevent;
                    }
                }
                if (contents.length) {
                    var visibility = contents.is(VISIBLE);
                    if (!that._triggerEvent(!visibility ? EXPAND : COLLAPSE, item)) {
                        prevent = that._toggleItem(item, visibility);
                    }
                }
                return prevent;
            },
            _hasChildItems: function (item) {
                return item.items && item.items.length > 0 || item.hasChildren;
            },
            _toggleItem: function (element, isVisible, expanded) {
                var that = this, childGroup = element.find(GROUPS), link = element.find(LINKSELECTOR), url = link.attr(HREF), prevent, content, dataItem = that.dataItem(element), notVisible = !isVisible;
                var loaded = dataItem && dataItem.loaded();
                if (dataItem && !expanded && dataItem.expanded !== notVisible) {
                    dataItem.set('expanded', notVisible);
                    prevent = dataItem.hasChildren || !!dataItem.content || !!dataItem.contentUrl;
                    return prevent;
                }
                if (dataItem && (!expanded || expanded === 'true') && !loaded && !dataItem.content && !dataItem.contentUrl) {
                    if (that.options.loadOnDemand) {
                        this._progress(element, true);
                    }
                    element.children('.k-group,.k-content').remove();
                    prevent = dataItem.hasChildren;
                    dataItem.load();
                } else {
                    if (childGroup.length) {
                        this._toggleGroup(childGroup, isVisible);
                        prevent = true;
                    } else {
                        content = element.children('.' + CONTENT);
                        if (content.length) {
                            prevent = true;
                            if (!content.is(EMPTY) || url === undefined) {
                                that._toggleGroup(content, isVisible);
                            } else {
                                that._ajaxRequest(element, content, isVisible);
                            }
                        }
                    }
                }
                return prevent;
            },
            _toggleGroup: function (element, visibility) {
                var that = this, animationSettings = that.options.animation, animation = animationSettings.expand, hasCollapseAnimation = animationSettings.collapse && 'effects' in animationSettings.collapse, collapse = extend({}, animationSettings.expand, animationSettings.collapse);
                if (!hasCollapseAnimation) {
                    collapse = extend(collapse, { reverse: true });
                }
                if (element.is(VISIBLE) != visibility) {
                    that._animating = false;
                    return;
                }
                element.attr(ARIA_HIDDEN, !!visibility);
                element.parent().attr(ARIA_EXPANDED, !visibility).toggleClass(ACTIVECLASS, !visibility).find('> .k-link > .k-panelbar-collapse,> .k-link > .k-panelbar-expand').toggleClass('k-i-arrow-60-up', !visibility).toggleClass('k-panelbar-collapse', !visibility).toggleClass('k-i-arrow-60-down', visibility).toggleClass('k-panelbar-expand', visibility);
                if (visibility) {
                    animation = extend(collapse, { hide: true });
                    animation.complete = function () {
                        that._animationCallback();
                    };
                } else {
                    animation = extend({
                        complete: function (element) {
                            that._triggerEvent(ACTIVATE, element.closest(ITEM));
                            that._animationCallback();
                        }
                    }, animation);
                }
                element.kendoStop(true, true).kendoAnimate(animation);
            },
            _animationCallback: function () {
                var that = this;
                that.trigger('complete');
                that._animating = false;
            },
            _addGroupElement: function (element) {
                var group = $('<ul role="group" aria-hidden="true" class="k-group k-panel" style="display:none"></ul>');
                element.append(group);
                return group;
            },
            _collapseAllExpanded: function (item) {
                var that = this, children, stopExpand = false;
                var groups = item.find(GROUPS).add(item.find(CONTENTS));
                if (groups.is(VISIBLE)) {
                    stopExpand = true;
                }
                if (!(groups.is(VISIBLE) || groups.length === 0)) {
                    children = item.siblings();
                    children.find(GROUPS).add(children.find(CONTENTS)).filter(function () {
                        return $(this).is(VISIBLE);
                    }).each(function (index, content) {
                        content = $(content);
                        stopExpand = that._triggerEvent(COLLAPSE, content.closest(ITEM));
                        if (!stopExpand) {
                            that._toggleGroup(content, true);
                        }
                    });
                    that.one('complete', function () {
                        setTimeout(function () {
                            children.each(function (index, child) {
                                var dataItem = that.dataItem(child);
                                if (dataItem) {
                                    dataItem.set('expanded', false);
                                }
                            });
                        });
                    });
                }
                return stopExpand;
            },
            _ajaxRequest: function (element, contentElement, isVisible) {
                var that = this, statusIcon = element.find('.k-panelbar-collapse, .k-panelbar-expand'), link = element.find(LINKSELECTOR), loadingIconTimeout = setTimeout(function () {
                        statusIcon.addClass('k-i-loading');
                    }, 100), data = {}, url = link.attr(HREF);
                $.ajax({
                    type: 'GET',
                    cache: false,
                    url: url,
                    dataType: 'html',
                    data: data,
                    error: function (xhr, status) {
                        statusIcon.removeClass('k-i-loading');
                        if (that.trigger(ERROR, {
                                xhr: xhr,
                                status: status
                            })) {
                            this.complete();
                        }
                    },
                    complete: function () {
                        clearTimeout(loadingIconTimeout);
                        statusIcon.removeClass('k-i-loading');
                    },
                    success: function (data) {
                        function getElements() {
                            return { elements: contentElement.get() };
                        }
                        try {
                            that.angular('cleanup', getElements);
                            contentElement.html(data);
                            that.angular('compile', getElements);
                        } catch (e) {
                            var console = window.console;
                            if (console && console.error) {
                                console.error(e.name + ': ' + e.message + ' in ' + url);
                            }
                            this.error(this.xhr, 'error');
                        }
                        that._toggleGroup(contentElement, isVisible);
                        that.trigger(CONTENTLOAD, {
                            item: element[0],
                            contentElement: contentElement[0]
                        });
                    }
                });
            },
            _triggerEvent: function (eventName, element) {
                var that = this;
                return that.trigger(eventName, { item: element[0] });
            },
            _updateSelected: function (link, skipChange) {
                var that = this, element = that.element, item = link.parent(ITEM), selected = that._selected, dataItem = that.dataItem(item);
                if (selected) {
                    selected.removeAttr(ARIA_SELECTED);
                }
                that._selected = item.attr(ARIA_SELECTED, true);
                element.find(selectableItems).removeClass(SELECTEDCLASS);
                element.find('> .' + HIGHLIGHTCLASS + ', .k-panel > .' + HIGHLIGHTCLASS).removeClass(HIGHLIGHTCLASS);
                link.addClass(SELECTEDCLASS);
                link.parentsUntil(element, ITEM).filter(':has(.k-header)').addClass(HIGHLIGHTCLASS);
                that._current(item[0] ? item : null);
                if (dataItem) {
                    dataItem.set('selected', true);
                }
                if (!skipChange) {
                    that.trigger(CHANGE);
                }
            },
            _animations: function (options) {
                if (options && 'animation' in options && !options.animation) {
                    options.animation = {
                        expand: { effects: {} },
                        collapse: {
                            hide: true,
                            effects: {}
                        }
                    };
                }
            },
            renderItem: function (options) {
                var that = this;
                options = extend({
                    panelBar: that,
                    group: {}
                }, options);
                var empty = that.templates.empty, item = options.item;
                return that.templates.item(extend(options, {
                    itemWrapper: that.templates.itemWrapper,
                    renderContent: that.renderContent,
                    arrow: that._hasChildItems(item) || item.content || item.contentUrl ? that.templates.arrow : empty,
                    subGroup: !options.loadOnDemand || item.expanded ? that.renderGroup : empty
                }, rendering));
            },
            renderGroup: function (options) {
                var that = this;
                var templates = that.templates || options.panelBar.templates;
                return templates.group(extend({
                    renderItems: function (options) {
                        var html = '', i = 0, items = options.items, len = items ? items.length : 0, group = extend({ length: len }, options.group);
                        for (; i < len; i++) {
                            html += options.panelBar.renderItem(extend(options, {
                                group: group,
                                item: extend({ index: i }, items[i])
                            }));
                        }
                        return html;
                    }
                }, options, rendering));
            },
            renderContent: function (options) {
                return options.panelBar.templates.content(extend(options, rendering));
            }
        });
        kendo.ui.plugin(PanelBar);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.responsivepanel', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'responsive-panel',
        name: 'Responsive Panel',
        category: 'web',
        description: 'The Responsive Panel widget allows a panel of content to be hidden on mobile devices, available through a toggle button.',
        depends: ['core']
    };
    (function ($, undefined) {
        var proxy = $.proxy;
        var NS = '.kendoResponsivePanel';
        var OPEN = 'open';
        var CLOSE = 'close';
        var ACTIVATE_EVENTS = 'click' + NS + ' touchstart' + NS + ' touchend' + NS;
        var Widget = kendo.ui.Widget;
        var ResponsivePanel = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this._guid = '_' + kendo.guid();
                this._toggleHandler = proxy(this._toggleButtonClick, this);
                this._closeHandler = proxy(this._close, this);
                $(document.documentElement).on(ACTIVATE_EVENTS, this.options.toggleButton, this._toggleHandler);
                this._registerBreakpoint();
                this.element.addClass('k-rpanel k-rpanel-' + this.options.orientation + ' ' + this._guid);
                this._resizeHandler = proxy(this.resize, this, true);
                $(window).on('resize' + NS, this._resizeHandler);
            },
            _mediaQuery: '@media (max-width: #= breakpoint-1 #px) {' + '.#= guid #.k-rpanel-animate.k-rpanel-left,' + '.#= guid #.k-rpanel-animate.k-rpanel-right {' + '-webkit-transition: -webkit-transform .2s ease-out;' + '-ms-transition: -ms-transform .2s ease-out;' + 'transition: transform .2s ease-out;' + '} ' + '.#= guid #.k-rpanel-top {' + 'overflow: hidden;' + '}' + '.#= guid #.k-rpanel-animate.k-rpanel-top {' + '-webkit-transition: max-height .2s linear;' + '-ms-transition: max-height .2s linear;' + 'transition: max-height .2s linear;' + '}' + '} ' + '@media (min-width: #= breakpoint #px) {' + '#= toggleButton # { display: none; } ' + '.#= guid #.k-rpanel-left { float: left; } ' + '.#= guid #.k-rpanel-right { float: right; } ' + '.#= guid #.k-rpanel-left, .#= guid #.k-rpanel-right {' + 'position: relative;' + '-webkit-transform: translateX(0);' + '-ms-transform: translateX(0);' + 'transform: translateX(0);' + '-webkit-transform: translateX(0) translateZ(0);' + '-ms-transform: translateX(0) translateZ(0);' + 'transform: translateX(0) translateZ(0);' + '} ' + '.k-ie9 .#= guid #.k-rpanel-left { left: 0; } ' + '.#= guid #.k-rpanel-top { max-height: none; }' + '}',
            _registerBreakpoint: function () {
                var options = this.options;
                this._registerStyle(kendo.template(this._mediaQuery)({
                    breakpoint: options.breakpoint,
                    toggleButton: options.toggleButton,
                    guid: this._guid
                }));
            },
            _registerStyle: function (cssText) {
                var head = $('head,body')[0];
                var style = document.createElement('style');
                head.appendChild(style);
                if (style.styleSheet) {
                    style.styleSheet.cssText = cssText;
                } else {
                    style.appendChild(document.createTextNode(cssText));
                }
            },
            options: {
                name: 'ResponsivePanel',
                orientation: 'left',
                toggleButton: '.k-rpanel-toggle',
                breakpoint: 640,
                autoClose: true
            },
            events: [
                OPEN,
                CLOSE
            ],
            _resize: function () {
                this.element.removeClass('k-rpanel-animate k-rpanel-expanded');
                $(document.documentElement).off(ACTIVATE_EVENTS, this._closeHandler);
            },
            _toggleButtonClick: function (e) {
                e.preventDefault();
                if (e.type == 'touchend') {
                    return;
                }
                if (this.element.hasClass('k-rpanel-expanded')) {
                    this.close();
                } else {
                    this.open();
                }
            },
            open: function () {
                if (!this.trigger(OPEN)) {
                    this.element.addClass('k-rpanel-animate k-rpanel-expanded');
                    if (this.options.autoClose) {
                        $(document.documentElement).on(ACTIVATE_EVENTS, this._closeHandler);
                    }
                }
            },
            close: function () {
                if (!this.trigger(CLOSE)) {
                    this.element.addClass('k-rpanel-animate').removeClass('k-rpanel-expanded');
                    $(document.documentElement).off(ACTIVATE_EVENTS, this._closeHandler);
                }
            },
            _close: function (e) {
                var prevented = e.isDefaultPrevented();
                var container = $(e.target).closest(this.options.toggleButton + ',.k-rpanel');
                if (!container.length && !prevented) {
                    this.close();
                }
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                $(window).off('resize' + NS, this._resizeHandler);
                $(document.documentElement).off(ACTIVATE_EVENTS, this._closeHandler);
            }
        });
        kendo.ui.plugin(ResponsivePanel);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.timepicker', [
        'kendo.popup',
        'kendo.dateinput'
    ], f);
}(function () {
    var __meta__ = {
        id: 'timepicker',
        name: 'TimePicker',
        category: 'web',
        description: 'The TimePicker widget allows the end user to select a value from a list of predefined values or to type a new value.',
        depends: ['popup']
    };
    (function ($, undefined) {
        var kendo = window.kendo, keys = kendo.keys, parse = kendo.parseDate, activeElement = kendo._activeElement, extractFormat = kendo._extractFormat, support = kendo.support, browser = support.browser, ui = kendo.ui, Widget = ui.Widget, OPEN = 'open', CLOSE = 'close', CHANGE = 'change', ns = '.kendoTimePicker', CLICK = 'click' + ns, DEFAULT = 'k-state-default', DISABLED = 'disabled', READONLY = 'readonly', LI = 'li', SPAN = '<span/>', FOCUSED = 'k-state-focused', HOVER = 'k-state-hover', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, MOUSEDOWN = 'mousedown' + ns, MS_PER_MINUTE = 60000, MS_PER_DAY = 86400000, SELECTED = 'k-state-selected', STATEDISABLED = 'k-state-disabled', ARIA_SELECTED = 'aria-selected', ARIA_EXPANDED = 'aria-expanded', ARIA_HIDDEN = 'aria-hidden', ARIA_DISABLED = 'aria-disabled', ARIA_ACTIVEDESCENDANT = 'aria-activedescendant', ID = 'id', isArray = $.isArray, extend = $.extend, proxy = $.proxy, DATE = Date, TODAY = new DATE();
        TODAY = new DATE(TODAY.getFullYear(), TODAY.getMonth(), TODAY.getDate(), 0, 0, 0);
        var TimeView = function (options) {
            var that = this, id = options.id;
            that.options = options;
            that._dates = [];
            that.ul = $('<ul tabindex="-1" role="listbox" aria-hidden="true" unselectable="on" class="k-list k-reset"/>').css({ overflow: support.kineticScrollNeeded ? '' : 'auto' }).on(CLICK, LI, proxy(that._click, that)).on('mouseenter' + ns, LI, function () {
                $(this).addClass(HOVER);
            }).on('mouseleave' + ns, LI, function () {
                $(this).removeClass(HOVER);
            });
            that.list = $('<div class=\'k-list-container k-list-scroller\' unselectable=\'on\'/>').append(that.ul).on(MOUSEDOWN, preventDefault);
            if (id) {
                that._timeViewID = id + '_timeview';
                that._optionID = id + '_option_selected';
                that.ul.attr(ID, that._timeViewID);
            }
            that._popup();
            that._heightHandler = proxy(that._height, that);
            that.template = kendo.template('<li tabindex="-1" role="option" class="k-item" unselectable="on">#=data#</li>', { useWithBlock: false });
        };
        TimeView.prototype = {
            current: function (candidate) {
                var that = this, active = that.options.active;
                if (candidate !== undefined) {
                    if (that._current) {
                        that._current.removeClass(SELECTED);
                        if (that._current && that._current.length) {
                            that._current[0].removeAttribute(ID);
                            that._current[0].removeAttribute(ARIA_SELECTED);
                        }
                    }
                    if (candidate) {
                        candidate = $(candidate).addClass(SELECTED).attr(ID, that._optionID).attr(ARIA_SELECTED, true);
                        that.scroll(candidate[0]);
                    }
                    that._current = candidate;
                    if (active) {
                        active(candidate);
                    }
                } else {
                    return that._current;
                }
            },
            close: function () {
                this.popup.close();
            },
            destroy: function () {
                var that = this;
                that.ul.off(ns);
                that.list.off(ns);
                that.popup.destroy();
            },
            open: function () {
                var that = this;
                var popupHovered;
                if (!that.ul[0].firstChild) {
                    that.bind();
                }
                popupHovered = that.popup._hovered;
                that.popup._hovered = true;
                that.popup.open();
                setTimeout(function () {
                    that.popup._hovered = popupHovered;
                }, 1);
                if (that._current) {
                    that.scroll(that._current[0]);
                }
            },
            dataBind: function (dates) {
                var that = this, options = that.options, format = options.format, toString = kendo.toString, template = that.template, length = dates.length, idx = 0, date, html = '';
                for (; idx < length; idx++) {
                    date = dates[idx];
                    if (isInRange(date, options.min, options.max)) {
                        html += template(toString(date, format, options.culture));
                    }
                }
                that._html(html);
            },
            refresh: function () {
                var that = this, options = that.options, format = options.format, offset = dst(), ignoreDST = offset < 0, min = options.min, max = options.max, msMin = getMilliseconds(min), msMax = getMilliseconds(max), msLastTime = getMilliseconds(lastTimeOption(options.interval)), msInterval = options.interval * MS_PER_MINUTE, toString = kendo.toString, template = that.template, start = new DATE(+min), startDate = new DATE(start), msStart, lastIdx, idx = 0, length, html = '';
                if (ignoreDST) {
                    length = (MS_PER_DAY + offset * MS_PER_MINUTE) / msInterval;
                } else {
                    length = MS_PER_DAY / msInterval;
                }
                if (msMin != msMax || msLastTime === msMax) {
                    if (msMin > msMax) {
                        msMax += MS_PER_DAY;
                    }
                    length = (msMax - msMin) / msInterval + 1;
                }
                lastIdx = parseInt(length, 10);
                for (; idx < length; idx++) {
                    if (idx) {
                        setTime(start, msInterval, ignoreDST);
                    }
                    if (msMax && lastIdx == idx) {
                        msStart = getMilliseconds(start);
                        if (startDate < start) {
                            msStart += MS_PER_DAY;
                        }
                        if (msStart > msMax) {
                            start = new DATE(+max);
                        }
                    }
                    that._dates.push(getMilliseconds(start));
                    html += template(toString(start, format, options.culture));
                }
                that._html(html);
            },
            bind: function () {
                var that = this, dates = that.options.dates;
                if (dates && dates[0]) {
                    that.dataBind(dates);
                } else {
                    that.refresh();
                }
            },
            _html: function (html) {
                var that = this;
                that.ul[0].innerHTML = html;
                that.popup.unbind(OPEN, that._heightHandler);
                that.popup.one(OPEN, that._heightHandler);
                that.current(null);
                that.select(that._value);
            },
            scroll: function (item) {
                if (!item) {
                    return;
                }
                var content = this.list[0], itemOffsetTop = item.offsetTop, itemOffsetHeight = item.offsetHeight, contentScrollTop = content.scrollTop, contentOffsetHeight = content.clientHeight, bottomDistance = itemOffsetTop + itemOffsetHeight;
                if (contentScrollTop > itemOffsetTop) {
                    contentScrollTop = itemOffsetTop;
                } else if (bottomDistance > contentScrollTop + contentOffsetHeight) {
                    contentScrollTop = bottomDistance - contentOffsetHeight;
                }
                content.scrollTop = contentScrollTop;
            },
            select: function (li) {
                var that = this, options = that.options, current = that._current, selection;
                if (li instanceof Date) {
                    li = kendo.toString(li, options.format, options.culture);
                }
                if (typeof li === 'string') {
                    if (!current || current.text() !== li) {
                        li = $.grep(that.ul[0].childNodes, function (node) {
                            return (node.textContent || node.innerText) == li;
                        });
                        li = li[0] ? li : null;
                    } else {
                        li = current;
                    }
                }
                selection = that._distinctSelection(li);
                that.current(selection);
            },
            _distinctSelection: function (selection) {
                var that = this, currentValue, selectionIndex;
                if (selection && selection.length > 1) {
                    currentValue = getMilliseconds(that._value);
                    selectionIndex = $.inArray(currentValue, that._dates);
                    selection = that.ul.children()[selectionIndex];
                }
                return selection;
            },
            setOptions: function (options) {
                var old = this.options;
                options.min = parse(options.min);
                options.max = parse(options.max);
                this.options = extend(old, options, {
                    active: old.active,
                    change: old.change,
                    close: old.close,
                    open: old.open
                });
                this.bind();
            },
            toggle: function () {
                var that = this;
                if (that.popup.visible()) {
                    that.close();
                } else {
                    that.open();
                }
            },
            value: function (value) {
                var that = this;
                that._value = value;
                if (that.ul[0].firstChild) {
                    that.select(value);
                }
            },
            _click: function (e) {
                var that = this, li = $(e.currentTarget), date = li.text(), dates = that.options.dates;
                if (dates && dates.length > 0) {
                    date = dates[li.index()];
                }
                if (!e.isDefaultPrevented()) {
                    that.select(li);
                    that.options.change(date, true);
                    that.close();
                }
            },
            _height: function () {
                var that = this;
                var list = that.list;
                var parent = list.parent('.k-animation-container');
                var height = that.options.height;
                if (that.ul[0].children.length) {
                    list.add(parent).show().height(that.ul[0].scrollHeight > height ? height : 'auto').hide();
                }
            },
            _parse: function (value) {
                var that = this, options = that.options, min = getMilliseconds(options.min) != getMilliseconds(TODAY) ? options.min : null, max = getMilliseconds(options.max) != getMilliseconds(TODAY) ? options.max : null, current = that._value || min || max || TODAY;
                if (value instanceof DATE) {
                    return value;
                }
                value = parse(value, options.parseFormats, options.culture);
                if (value) {
                    value = new DATE(current.getFullYear(), current.getMonth(), current.getDate(), value.getHours(), value.getMinutes(), value.getSeconds(), value.getMilliseconds());
                }
                return value;
            },
            _adjustListWidth: function () {
                var list = this.list, width = list[0].style.width, wrapper = this.options.anchor, computedStyle, computedWidth, outerWidth = kendo._outerWidth;
                if (!list.data('width') && width) {
                    return;
                }
                computedStyle = window.getComputedStyle ? window.getComputedStyle(wrapper[0], null) : 0;
                computedWidth = computedStyle ? parseFloat(computedStyle.width) : outerWidth(wrapper);
                if (computedStyle && (browser.mozilla || browser.msie)) {
                    computedWidth += parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) + parseFloat(computedStyle.borderLeftWidth) + parseFloat(computedStyle.borderRightWidth);
                }
                width = computedWidth - (outerWidth(list) - list.width());
                list.css({
                    fontFamily: wrapper.css('font-family'),
                    width: width
                }).data('width', width);
            },
            _popup: function () {
                var that = this, list = that.list, options = that.options, anchor = options.anchor;
                that.popup = new ui.Popup(list, extend(options.popup, {
                    anchor: anchor,
                    open: options.open,
                    close: options.close,
                    animation: options.animation,
                    isRtl: support.isRtl(options.anchor)
                }));
            },
            move: function (e) {
                var that = this, key = e.keyCode, ul = that.ul[0], current = that._current, down = key === keys.DOWN;
                if (key === keys.UP || down) {
                    if (e.altKey) {
                        that.toggle(down);
                        return;
                    } else if (down) {
                        current = current ? current[0].nextSibling : ul.firstChild;
                    } else {
                        current = current ? current[0].previousSibling : ul.lastChild;
                    }
                    if (current) {
                        that.select(current);
                    }
                    that.options.change(that._current.text());
                    e.preventDefault();
                } else if (key === keys.ENTER || key === keys.TAB || key === keys.ESC) {
                    e.preventDefault();
                    if (current) {
                        that.options.change(current.text(), true);
                    }
                    that.close();
                }
            }
        };
        function setTime(date, time, ignoreDST) {
            var offset = date.getTimezoneOffset(), offsetDiff;
            date.setTime(date.getTime() + time);
            if (!ignoreDST) {
                offsetDiff = date.getTimezoneOffset() - offset;
                date.setTime(date.getTime() + offsetDiff * MS_PER_MINUTE);
            }
        }
        function dst() {
            var today = new DATE(), midnight = new DATE(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0), noon = new DATE(today.getFullYear(), today.getMonth(), today.getDate(), 12, 0, 0);
            return -1 * (midnight.getTimezoneOffset() - noon.getTimezoneOffset());
        }
        function getMilliseconds(date) {
            return date.getHours() * 60 * MS_PER_MINUTE + date.getMinutes() * MS_PER_MINUTE + date.getSeconds() * 1000 + date.getMilliseconds();
        }
        function lastTimeOption(interval) {
            var date = new Date(2100, 0, 1);
            date.setMinutes(-interval);
            return date;
        }
        function isInRange(value, min, max) {
            var msMin = getMilliseconds(min), msMax = getMilliseconds(max), msValue;
            if (!value || msMin == msMax) {
                return true;
            }
            msValue = getMilliseconds(value);
            if (msMin > msValue) {
                msValue += MS_PER_DAY;
            }
            if (msMax < msMin) {
                msMax += MS_PER_DAY;
            }
            return msValue >= msMin && msValue <= msMax;
        }
        TimeView.getMilliseconds = getMilliseconds;
        kendo.TimeView = TimeView;
        var TimePicker = Widget.extend({
            init: function (element, options) {
                var that = this, ul, timeView, disabled;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.min = parse(element.attr('min')) || parse(options.min);
                options.max = parse(element.attr('max')) || parse(options.max);
                normalize(options);
                that._initialOptions = extend({}, options);
                that._wrapper();
                that.timeView = timeView = new TimeView(extend({}, options, {
                    id: element.attr(ID),
                    anchor: that.wrapper,
                    format: options.format,
                    change: function (value, trigger) {
                        if (trigger) {
                            that._change(value);
                        } else {
                            element.val(value);
                        }
                    },
                    open: function (e) {
                        that.timeView._adjustListWidth();
                        if (that.trigger(OPEN)) {
                            e.preventDefault();
                        } else {
                            element.attr(ARIA_EXPANDED, true);
                            ul.attr(ARIA_HIDDEN, false);
                        }
                    },
                    close: function (e) {
                        if (that.trigger(CLOSE)) {
                            e.preventDefault();
                        } else {
                            element.attr(ARIA_EXPANDED, false);
                            ul.attr(ARIA_HIDDEN, true);
                        }
                    },
                    active: function (current) {
                        if (element && element.length) {
                            element[0].removeAttribute(ARIA_ACTIVEDESCENDANT);
                        }
                        if (current) {
                            element.attr(ARIA_ACTIVEDESCENDANT, timeView._optionID);
                        }
                    }
                }));
                ul = timeView.ul;
                that._icon();
                that._reset();
                try {
                    element[0].setAttribute('type', 'text');
                } catch (e) {
                    element[0].type = 'text';
                }
                element.addClass('k-input').attr({
                    'role': 'combobox',
                    'aria-expanded': false,
                    'aria-owns': timeView._timeViewID,
                    'autocomplete': 'off'
                });
                disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                if (options.dateInput) {
                    var min = options.min;
                    var max = options.max;
                    var today = new DATE();
                    if (getMilliseconds(min) == getMilliseconds(max)) {
                        min = new DATE(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0);
                        max = new DATE(today.getFullYear(), today.getMonth(), today.getDate(), 24, 0, 0);
                    }
                    that._dateInput = new ui.DateInput(element, {
                        culture: options.culture,
                        format: options.format,
                        min: min,
                        max: max,
                        value: options.value
                    });
                }
                that._old = that._update(options.value || that.element.val());
                that._oldText = element.val();
                kendo.notify(that);
            },
            options: {
                name: 'TimePicker',
                min: TODAY,
                max: TODAY,
                format: '',
                dates: [],
                parseFormats: [],
                value: null,
                interval: 30,
                height: 200,
                animation: {},
                dateInput: false
            },
            events: [
                OPEN,
                CLOSE,
                CHANGE
            ],
            setOptions: function (options) {
                var that = this;
                var value = that._value;
                Widget.fn.setOptions.call(that, options);
                options = that.options;
                normalize(options);
                that.timeView.setOptions(options);
                if (value) {
                    that.element.val(kendo.toString(value, options.format, options.culture));
                }
            },
            dataBind: function (dates) {
                if (isArray(dates)) {
                    this.timeView.dataBind(dates);
                }
            },
            _editable: function (options) {
                var that = this, disable = options.disable, readonly = options.readonly, arrow = that._arrow.off(ns), element = that.element.off(ns), wrapper = that._inputWrapper.off(ns);
                if (that._dateInput) {
                    that._dateInput._unbindInput();
                }
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    if (element && element.length) {
                        element[0].removeAttribute(DISABLED);
                        element[0].removeAttribute(READONLY);
                    }
                    element.attr(ARIA_DISABLED, false).on('keydown' + ns, proxy(that._keydown, that)).on('focusout' + ns, proxy(that._blur, that)).on('focus' + ns, function () {
                        that._inputWrapper.addClass(FOCUSED);
                    });
                    if (that._dateInput) {
                        that._dateInput._bindInput();
                    }
                    arrow.on(CLICK, proxy(that._click, that)).on(MOUSEDOWN, preventDefault);
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    element.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.timeView.destroy();
                that.element.off(ns);
                that._arrow.off(ns);
                that._inputWrapper.off(ns);
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
            },
            close: function () {
                this.timeView.close();
            },
            open: function () {
                this.timeView.open();
            },
            min: function (value) {
                return this._option('min', value);
            },
            max: function (value) {
                return this._option('max', value);
            },
            value: function (value) {
                var that = this;
                if (value === undefined) {
                    return that._value;
                }
                that._old = that._update(value);
                if (that._old === null) {
                    that.element.val('');
                }
                that._oldText = that.element.val();
            },
            _blur: function () {
                var that = this, value = that.element.val();
                that.close();
                if (value !== that._oldText) {
                    that._change(value);
                }
                that._inputWrapper.removeClass(FOCUSED);
            },
            _click: function () {
                var that = this, element = that.element;
                that.timeView.toggle();
                if (!support.touch && element[0] !== activeElement()) {
                    element.trigger('focus');
                }
            },
            _change: function (value) {
                var that = this, oldValue = that.element.val(), dateChanged;
                value = that._update(value);
                dateChanged = !kendo.calendar.isEqualDate(that._old, value);
                var valueUpdated = dateChanged && !that._typing;
                var textFormatted = oldValue !== that.element.val();
                if (valueUpdated || textFormatted) {
                    that.element.trigger(CHANGE);
                }
                if (dateChanged) {
                    that._old = value;
                    that._oldText = that.element.val();
                    that.trigger(CHANGE);
                }
                that._typing = false;
            },
            _icon: function () {
                var that = this, element = that.element, arrow;
                arrow = element.next('span.k-select');
                if (!arrow[0]) {
                    arrow = $('<span unselectable="on" class="k-select" aria-label="select"><span class="k-icon k-i-clock"></span></span>').insertAfter(element);
                }
                that._arrow = arrow.attr({
                    'role': 'button',
                    'aria-controls': that.timeView._timeViewID
                });
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, timeView = that.timeView, value = that.element.val();
                if (timeView.popup.visible() || e.altKey) {
                    timeView.move(e);
                    if (that._dateInput && e.stopImmediatePropagation) {
                        e.stopImmediatePropagation();
                    }
                } else if (key === keys.ENTER && value !== that._oldText) {
                    that._change(value);
                } else {
                    that._typing = true;
                }
            },
            _option: function (option, value) {
                var that = this, options = that.options;
                if (value === undefined) {
                    return options[option];
                }
                value = that.timeView._parse(value);
                if (!value) {
                    return;
                }
                value = new DATE(+value);
                options[option] = value;
                that.timeView.options[option] = value;
                that.timeView.bind();
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _update: function (value) {
                var that = this, options = that.options, timeView = that.timeView, date = timeView._parse(value);
                if (!isInRange(date, options.min, options.max)) {
                    date = null;
                }
                that._value = date;
                if (that._dateInput && date) {
                    that._dateInput.value(date || value);
                } else {
                    that.element.val(kendo.toString(date || value, options.format, options.culture));
                }
                timeView.value(date);
                return date;
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper;
                wrapper = element.parents('.k-timepicker');
                if (!wrapper[0]) {
                    wrapper = element.wrap(SPAN).parent().addClass('k-picker-wrap k-state-default');
                    wrapper = wrapper.wrap(SPAN).parent();
                }
                wrapper[0].style.cssText = element[0].style.cssText;
                that.wrapper = wrapper.addClass('k-widget k-timepicker').addClass(element[0].className);
                element.css({
                    width: '100%',
                    height: element[0].style.height
                });
                that._inputWrapper = $(wrapper[0].firstChild);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        that.value(element[0].defaultValue);
                        that.max(that._initialOptions.max);
                        that.min(that._initialOptions.min);
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            }
        });
        function normalize(options) {
            var parseFormats = options.parseFormats;
            options.format = extractFormat(options.format || kendo.getCulture(options.culture).calendars.standard.patterns.t);
            parseFormats = isArray(parseFormats) ? parseFormats : [parseFormats];
            parseFormats.splice(0, 0, options.format);
            options.parseFormats = parseFormats;
        }
        function preventDefault(e) {
            e.preventDefault();
        }
        ui.plugin(TimePicker);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.datetimepicker', [
        'kendo.datepicker',
        'kendo.timepicker'
    ], f);
}(function () {
    var __meta__ = {
        id: 'datetimepicker',
        name: 'DateTimePicker',
        category: 'web',
        description: 'The DateTimePicker allows the end user to select a value from a calendar or a time drop-down list.',
        depends: [
            'datepicker',
            'timepicker'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, TimeView = kendo.TimeView, parse = kendo.parseDate, support = kendo.support, activeElement = kendo._activeElement, extractFormat = kendo._extractFormat, calendar = kendo.calendar, isInRange = calendar.isInRange, restrictValue = calendar.restrictValue, isEqualDatePart = calendar.isEqualDatePart, getMilliseconds = TimeView.getMilliseconds, ui = kendo.ui, Widget = ui.Widget, OPEN = 'open', CLOSE = 'close', CHANGE = 'change', ns = '.kendoDateTimePicker', CLICK = 'click' + ns, UP = support.mouseAndTouchPresent ? kendo.applyEventMap('up', ns.slice(1)) : CLICK, DISABLED = 'disabled', READONLY = 'readonly', DEFAULT = 'k-state-default', FOCUSED = 'k-state-focused', HOVER = 'k-state-hover', STATEDISABLED = 'k-state-disabled', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, MOUSEDOWN = 'mousedown' + ns, MONTH = 'month', SPAN = '<span/>', ARIA_ACTIVEDESCENDANT = 'aria-activedescendant', ARIA_EXPANDED = 'aria-expanded', ARIA_HIDDEN = 'aria-hidden', ARIA_OWNS = 'aria-owns', ARIA_DISABLED = 'aria-disabled', DATE = Date, MIN = new DATE(1800, 0, 1), MAX = new DATE(2099, 11, 31), dateViewParams = { view: 'date' }, timeViewParams = { view: 'time' }, extend = $.extend;
        var DateTimePicker = Widget.extend({
            init: function (element, options) {
                var that = this, disabled;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.disableDates = kendo.calendar.disabled(options.disableDates);
                options.min = parse(element.attr('min')) || parse(options.min);
                options.max = parse(element.attr('max')) || parse(options.max);
                normalize(options);
                that._initialOptions = extend({}, options);
                that._wrapper();
                that._views();
                that._icons();
                that._reset();
                that._template();
                try {
                    element[0].setAttribute('type', 'text');
                } catch (e) {
                    element[0].type = 'text';
                }
                element.addClass('k-input').attr({
                    'role': 'combobox',
                    'aria-expanded': false,
                    'autocomplete': 'off'
                });
                that._midnight = that._calculateMidnight(options.min, options.max);
                disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                that._createDateInput(options);
                that._old = that._update(options.value || that.element.val());
                that._oldText = element.val();
                kendo.notify(that);
            },
            options: {
                name: 'DateTimePicker',
                value: null,
                format: '',
                timeFormat: '',
                culture: '',
                parseFormats: [],
                dates: [],
                disableDates: null,
                min: new DATE(MIN),
                max: new DATE(MAX),
                interval: 30,
                height: 200,
                footer: '',
                start: MONTH,
                depth: MONTH,
                animation: {},
                month: {},
                ARIATemplate: 'Current focused date is #=kendo.toString(data.current, "d")#',
                dateButtonText: 'Open the date view',
                timeButtonText: 'Open the time view',
                dateInput: false,
                weekNumber: false
            },
            events: [
                OPEN,
                CLOSE,
                CHANGE
            ],
            setOptions: function (options) {
                var that = this, value = that._value, min, max, currentValue;
                Widget.fn.setOptions.call(that, options);
                options = that.options;
                options.min = min = parse(options.min);
                options.max = max = parse(options.max);
                normalize(options);
                that._midnight = that._calculateMidnight(options.min, options.max);
                currentValue = options.value || that._value || that.dateView._current;
                if (min && !isEqualDatePart(min, currentValue)) {
                    min = new DATE(MIN);
                }
                if (max && !isEqualDatePart(max, currentValue)) {
                    max = new DATE(MAX);
                }
                that.dateView.setOptions(options);
                that.timeView.setOptions(extend({}, options, {
                    format: options.timeFormat,
                    min: min,
                    max: max
                }));
                that._createDateInput(options);
                if (!that._dateInput) {
                    that.element.val(kendo.toString(value, options.format, options.culture));
                }
                if (value) {
                    that._updateARIA(value);
                }
            },
            _editable: function (options) {
                var that = this, element = that.element.off(ns), dateIcon = that._dateIcon.off(ns), timeIcon = that._timeIcon.off(ns), wrapper = that._inputWrapper.off(ns), readonly = options.readonly, disable = options.disable;
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    if (element && element.length) {
                        element[0].removeAttribute(DISABLED);
                        element[0].removeAttribute(READONLY, false);
                        element[0].removeAttribute(ARIA_DISABLED, false);
                    }
                    element.on('keydown' + ns, $.proxy(that._keydown, that)).on('focus' + ns, function () {
                        that._inputWrapper.addClass(FOCUSED);
                    }).on('focusout' + ns, function () {
                        that._inputWrapper.removeClass(FOCUSED);
                        if (element.val() !== that._oldText) {
                            that._change(element.val());
                        }
                        that.close('date');
                        that.close('time');
                    });
                    dateIcon.on(MOUSEDOWN, preventDefault).on(UP, function (e) {
                        that.toggle('date');
                        that._focusElement(e.type);
                    });
                    timeIcon.on(MOUSEDOWN, preventDefault).on(UP, function (e) {
                        that.toggle('time');
                        that._focusElement(e.type);
                    });
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    element.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
            },
            _focusElement: function (eventType) {
                var element = this.element;
                if ((!support.touch || support.mouseAndTouchPresent && !(eventType || '').match(/touch/i)) && element[0] !== activeElement()) {
                    element.trigger('focus');
                }
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.dateView.destroy();
                that.timeView.destroy();
                that.element.off(ns);
                that._dateIcon.off(ns);
                that._timeIcon.off(ns);
                that._inputWrapper.off(ns);
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
            },
            close: function (view) {
                if (view !== 'time') {
                    view = 'date';
                }
                this[view + 'View'].close();
            },
            open: function (view) {
                if (view !== 'time') {
                    view = 'date';
                }
                this[view + 'View'].open();
            },
            min: function (value) {
                return this._option('min', value);
            },
            max: function (value) {
                return this._option('max', value);
            },
            toggle: function (view) {
                var secondView = 'timeView';
                if (view !== 'time') {
                    view = 'date';
                } else {
                    secondView = 'dateView';
                }
                this[view + 'View'].toggle();
                this[secondView].close();
            },
            value: function (value) {
                var that = this;
                if (value === undefined) {
                    return that._value;
                }
                that._old = that._update(value);
                if (that._old === null) {
                    that.element.val('');
                }
                that._oldText = that.element.val();
            },
            _change: function (value) {
                var that = this, oldValue = that.element.val(), dateChanged;
                value = that._update(value);
                dateChanged = +that._old != +value;
                var valueUpdated = dateChanged && !that._typing;
                var textFormatted = oldValue !== that.element.val();
                if (valueUpdated || textFormatted) {
                    that.element.trigger(CHANGE);
                }
                if (dateChanged) {
                    that._old = value;
                    that._oldText = that.element.val();
                    that.trigger(CHANGE);
                }
                that._typing = false;
            },
            _option: function (option, value) {
                var that = this;
                var options = that.options;
                var timeView = that.timeView;
                var timeViewOptions = timeView.options;
                var current = that._value || that._old;
                var minDateEqual;
                var maxDateEqual;
                if (value === undefined) {
                    return options[option];
                }
                value = parse(value, options.parseFormats, options.culture);
                if (!value) {
                    return;
                }
                if (options.min.getTime() === options.max.getTime()) {
                    timeViewOptions.dates = [];
                }
                options[option] = new DATE(value.getTime());
                that.dateView[option](value);
                that._midnight = that._calculateMidnight(options.min, options.max);
                if (current) {
                    minDateEqual = isEqualDatePart(options.min, current);
                    maxDateEqual = isEqualDatePart(options.max, current);
                }
                if (minDateEqual || maxDateEqual) {
                    timeViewOptions[option] = value;
                    if (minDateEqual && !maxDateEqual) {
                        timeViewOptions.max = lastTimeOption(options.interval);
                    }
                    if (maxDateEqual) {
                        if (that._midnight) {
                            timeView.dataBind([MAX]);
                            return;
                        } else if (!minDateEqual) {
                            timeViewOptions.min = MIN;
                        }
                    }
                } else {
                    timeViewOptions.max = MAX;
                    timeViewOptions.min = MIN;
                }
                timeView.bind();
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _update: function (value) {
                var that = this, options = that.options, min = options.min, max = options.max, dates = options.dates, timeView = that.timeView, current = that._value, date = parse(value, options.parseFormats, options.culture), isSameType = date === null && current === null || date instanceof Date && current instanceof Date, rebind, timeViewOptions, old, skip, formattedValue;
                if (options.disableDates && options.disableDates(date)) {
                    date = null;
                    if (!that._old && !that.element.val()) {
                        value = null;
                    }
                }
                if (+date === +current && isSameType) {
                    formattedValue = kendo.toString(date, options.format, options.culture);
                    if (formattedValue !== value) {
                        that.element.val(date === null ? value : formattedValue);
                        if (value instanceof String) {
                            that.element.trigger(CHANGE);
                        }
                    }
                    return date;
                }
                if (date !== null && isEqualDatePart(date, min)) {
                    date = restrictValue(date, min, max);
                } else if (!isInRange(date, min, max)) {
                    date = null;
                }
                that._value = date;
                timeView.value(date);
                that.dateView.value(date);
                if (date) {
                    old = that._old;
                    timeViewOptions = timeView.options;
                    if (dates[0]) {
                        dates = $.grep(dates, function (d) {
                            return isEqualDatePart(date, d);
                        });
                        if (dates[0]) {
                            timeView.dataBind(dates);
                            skip = true;
                        }
                    }
                    if (!skip) {
                        if (isEqualDatePart(date, min)) {
                            timeViewOptions.min = min;
                            timeViewOptions.max = lastTimeOption(options.interval);
                            rebind = true;
                        }
                        if (isEqualDatePart(date, max)) {
                            if (that._midnight) {
                                timeView.dataBind([MAX]);
                                skip = true;
                            } else {
                                timeViewOptions.max = max;
                                if (!rebind) {
                                    timeViewOptions.min = MIN;
                                }
                                rebind = true;
                            }
                        }
                    }
                    if (!skip && (!old && rebind || old && !isEqualDatePart(old, date))) {
                        if (!rebind) {
                            timeViewOptions.max = MAX;
                            timeViewOptions.min = MIN;
                        }
                        timeView.bind();
                    }
                }
                if (that._dateInput && date) {
                    that._dateInput.value(date || value);
                } else {
                    that.element.val(kendo.toString(date || value, options.format, options.culture));
                }
                that._updateARIA(date);
                return date;
            },
            _keydown: function (e) {
                var that = this, dateView = that.dateView, timeView = that.timeView, value = that.element.val(), isDateViewVisible = dateView.popup.visible();
                var stopPropagation = that._dateInput && e.stopImmediatePropagation;
                if (e.altKey && e.keyCode === kendo.keys.DOWN) {
                    that.toggle(isDateViewVisible ? 'time' : 'date');
                } else if (isDateViewVisible) {
                    dateView.move(e);
                    that._updateARIA(dateView._current);
                } else if (timeView.popup.visible()) {
                    timeView.move(e);
                } else if (e.keyCode === kendo.keys.ENTER && value !== that._oldText) {
                    that._change(value);
                } else {
                    that._typing = true;
                    stopPropagation = false;
                }
                if (stopPropagation) {
                    e.stopImmediatePropagation();
                }
            },
            _views: function () {
                var that = this, element = that.element, options = that.options, id = element.attr('id'), dateView, timeView, div, ul, msMin, date;
                that.dateView = dateView = new kendo.DateView(extend({}, options, {
                    id: id,
                    anchor: that.wrapper,
                    change: function () {
                        var value = dateView.calendar.value(), msValue = +value, msMin = +options.min, msMax = +options.max, current, adjustedDate;
                        if (msValue === msMin || msValue === msMax) {
                            current = msValue === msMin ? msMin : msMax;
                            current = new DATE(that._value || current);
                            current.setFullYear(value.getFullYear(), value.getMonth(), value.getDate());
                            if (isInRange(current, msMin, msMax)) {
                                value = current;
                            }
                        }
                        if (that._value) {
                            adjustedDate = kendo.date.setHours(new Date(value), that._value);
                            if (isInRange(adjustedDate, msMin, msMax)) {
                                value = adjustedDate;
                            }
                        }
                        that._change(value);
                        that.close('date');
                    },
                    close: function (e) {
                        if (that.trigger(CLOSE, dateViewParams)) {
                            e.preventDefault();
                        } else {
                            element.attr(ARIA_EXPANDED, false);
                            div.attr(ARIA_HIDDEN, true);
                            if (!timeView.popup.visible()) {
                                if (element && element.length) {
                                    element[0].removeAttribute(ARIA_OWNS);
                                }
                            }
                        }
                    },
                    open: function (e) {
                        if (that.trigger(OPEN, dateViewParams)) {
                            e.preventDefault();
                        } else {
                            if (element.val() !== that._oldText) {
                                date = parse(element.val(), options.parseFormats, options.culture);
                                that.dateView[date ? 'current' : 'value'](date);
                            }
                            div.attr(ARIA_HIDDEN, false);
                            element.attr(ARIA_EXPANDED, true).attr(ARIA_OWNS, dateView._dateViewID);
                            that._updateARIA(date);
                        }
                    }
                }));
                div = dateView.div;
                msMin = options.min.getTime();
                that.timeView = timeView = new TimeView({
                    id: id,
                    value: options.value,
                    anchor: that.wrapper,
                    animation: options.animation,
                    format: options.timeFormat,
                    culture: options.culture,
                    height: options.height,
                    interval: options.interval,
                    min: new DATE(MIN),
                    max: new DATE(MAX),
                    dates: msMin === options.max.getTime() ? [new Date(msMin)] : [],
                    parseFormats: options.parseFormats,
                    change: function (value, trigger) {
                        value = timeView._parse(value);
                        if (value < options.min) {
                            value = new DATE(+options.min);
                            timeView.options.min = value;
                        } else if (value > options.max) {
                            value = new DATE(+options.max);
                            timeView.options.max = value;
                        }
                        if (trigger) {
                            that._timeSelected = true;
                            that._change(value);
                        } else {
                            element.val(kendo.toString(value, options.format, options.culture));
                            dateView.value(value);
                            that._updateARIA(value);
                        }
                    },
                    close: function (e) {
                        if (that.trigger(CLOSE, timeViewParams)) {
                            e.preventDefault();
                        } else {
                            ul.attr(ARIA_HIDDEN, true);
                            element.attr(ARIA_EXPANDED, false);
                            if (!dateView.popup.visible()) {
                                if (element && element.length) {
                                    element[0].removeAttribute(ARIA_OWNS);
                                }
                            }
                        }
                    },
                    open: function (e) {
                        timeView._adjustListWidth();
                        if (that.trigger(OPEN, timeViewParams)) {
                            e.preventDefault();
                        } else {
                            if (element.val() !== that._oldText) {
                                date = parse(element.val(), options.parseFormats, options.culture);
                                that.timeView.value(date);
                            }
                            ul.attr(ARIA_HIDDEN, false);
                            element.attr(ARIA_EXPANDED, true).attr(ARIA_OWNS, timeView._timeViewID);
                            timeView.options.active(timeView.current());
                        }
                    },
                    active: function (current) {
                        if (element && element.length) {
                            element[0].removeAttribute(ARIA_ACTIVEDESCENDANT);
                        }
                        if (current) {
                            element.attr(ARIA_ACTIVEDESCENDANT, timeView._optionID);
                        }
                    }
                });
                ul = timeView.ul;
            },
            _icons: function () {
                var that = this;
                var element = that.element;
                var options = that.options;
                var icons;
                icons = element.next('span.k-select');
                if (!icons[0]) {
                    icons = $('<span unselectable="on" class="k-select">' + '<span class="k-link k-link-date" aria-label="' + options.dateButtonText + '"><span unselectable="on" class="k-icon k-i-calendar"></span></span>' + '<span class="k-link k-link-time" aria-label="' + options.timeButtonText + '"><span unselectable="on" class="k-icon k-i-clock"></span></span>' + '</span>').insertAfter(element);
                }
                icons = icons.children();
                that._dateIcon = icons.eq(0).attr('aria-controls', that.dateView._dateViewID);
                that._timeIcon = icons.eq(1).attr('aria-controls', that.timeView._timeViewID);
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper;
                wrapper = element.parents('.k-datetimepicker');
                if (!wrapper[0]) {
                    wrapper = element.wrap(SPAN).parent().addClass('k-picker-wrap k-state-default');
                    wrapper = wrapper.wrap(SPAN).parent();
                }
                wrapper[0].style.cssText = element[0].style.cssText;
                element.css({
                    width: '100%',
                    height: element[0].style.height
                });
                that.wrapper = wrapper.addClass('k-widget k-datetimepicker').addClass(element[0].className);
                that._inputWrapper = $(wrapper[0].firstChild);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        that.value(element[0].defaultValue);
                        that.max(that._initialOptions.max);
                        that.min(that._initialOptions.min);
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            },
            _template: function () {
                this._ariaTemplate = kendo.template(this.options.ARIATemplate);
            },
            _createDateInput: function (options) {
                if (this._dateInput) {
                    this._dateInput.destroy();
                    this._dateInput = null;
                }
                if (options.dateInput) {
                    this._dateInput = new ui.DateInput(this.element, {
                        culture: options.culture,
                        format: options.format,
                        min: options.min,
                        max: options.max
                    });
                }
            },
            _calculateMidnight: function (min, max) {
                return getMilliseconds(min) + getMilliseconds(max) === 0;
            },
            _updateARIA: function (date) {
                var cell;
                var that = this;
                var calendar = that.dateView.calendar;
                if (that.element && that.element.length) {
                    that.element[0].removeAttribute(ARIA_ACTIVEDESCENDANT);
                }
                if (calendar) {
                    cell = calendar._cell;
                    cell.attr('aria-label', that._ariaTemplate({ current: date || calendar.current() }));
                    that.element.attr(ARIA_ACTIVEDESCENDANT, cell.attr('id'));
                }
            }
        });
        function lastTimeOption(interval) {
            var date = new Date(2100, 0, 1);
            date.setMinutes(-interval);
            return date;
        }
        function preventDefault(e) {
            e.preventDefault();
        }
        function normalize(options) {
            var patterns = kendo.getCulture(options.culture).calendars.standard.patterns, parseFormats = !options.parseFormats.length, timeFormat;
            options.format = extractFormat(options.format || patterns.g);
            options.timeFormat = timeFormat = extractFormat(options.timeFormat || patterns.t);
            kendo.DateView.normalize(options);
            if (parseFormats) {
                options.parseFormats.unshift('yyyy-MM-ddTHH:mm:ss');
            }
            if ($.inArray(timeFormat, options.parseFormats) === -1) {
                options.parseFormats.push(timeFormat);
            }
        }
        ui.plugin(DateTimePicker);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.daterangepicker', [
        'kendo.core',
        'kendo.multiviewcalendar',
        'kendo.datepicker'
    ], f);
}(function () {
    var __meta__ = {
        id: 'daterangepicker',
        name: 'DateRangePicker',
        category: 'web',
        description: 'Date range picker.',
        depends: [
            'core',
            'multiviewcalendar',
            'datepicker'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, keys = kendo.keys, Widget = ui.Widget, MONTH = 'month', OPEN = 'open', CLOSE = 'close', CHANGE = 'change', DIV = '<div />', MIN = 'min', MAX = 'max', template = kendo.template, extend = $.extend, ID = 'id', support = kendo.support, mobileOS = support.mobileOS, SELECTED = 'k-state-selected', ARIA_EXPANDED = 'aria-expanded', ARIA_DISABLED = 'aria-disabled', STATEDISABLED = 'k-state-disabled', DISABLED = 'disabled', READONLY = 'readonly', DEFAULT = 'k-state-default', ARIA_HIDDEN = 'aria-hidden', ns = '.kendoDateRangePicker', CLICK = 'click' + ns, MOUSEDOWN = 'mousedown' + ns, UP = support.mouseAndTouchPresent ? kendo.applyEventMap('up', ns.slice(1)) : CLICK, proxy = $.proxy, parse = kendo.parseDate;
        var DateRangeView = function (options) {
            kendo.DateView.call(this, options);
        };
        DateRangeView.prototype = Object.create(kendo.DateView.prototype);
        function preventDefault(e) {
            e.preventDefault();
        }
        DateRangeView.prototype._calendar = function () {
            var that = this;
            var calendar = that.calendar;
            var options = that.options;
            var div;
            if (!calendar) {
                div = $(DIV).attr(ID, kendo.guid()).appendTo(that.popup.element).on(MOUSEDOWN, preventDefault).on(CLICK, 'td:has(.k-link)', proxy(that._click, that));
                that.calendar = calendar = new ui.MultiViewCalendar(div);
                that._setOptions(options);
                kendo.calendar.makeUnselectable(calendar.element);
                calendar.navigate(that._value || that._current, options.start);
                that.calendar.selectRange(that._range || options.range || {});
            }
        };
        DateRangeView.prototype._setOptions = function (options) {
            this.calendar.setOptions({
                focusOnNav: false,
                change: options.change,
                culture: options.culture,
                dates: options.dates,
                depth: options.depth,
                footer: options.footer,
                format: options.format,
                selectable: options.selectable,
                max: options.max,
                min: options.min,
                month: options.month,
                weekNumber: options.weekNumber,
                start: options.start,
                disableDates: options.disableDates,
                range: options.range
            });
        };
        DateRangeView.prototype.range = function (range) {
            this._range = range;
            if (this.calendar) {
                if (!range.start && !range.end) {
                    this.calendar.rangeSelectable.clear();
                } else {
                    this.calendar.selectRange(range);
                }
            }
        };
        DateRangeView.prototype.move = function (e) {
            var that = this;
            var key = e.keyCode;
            var calendar = that.calendar;
            var selectIsClicked = e.ctrlKey && key == keys.DOWN || key == keys.ENTER;
            var handled = false;
            if (e.altKey) {
                if (key == keys.DOWN) {
                    that.open();
                    e.preventDefault();
                    handled = true;
                } else if (key == keys.UP) {
                    that.close();
                    e.preventDefault();
                    handled = true;
                }
            } else if (that.popup.visible()) {
                if (key == keys.ESC || selectIsClicked && calendar._cell.hasClass(SELECTED)) {
                    that.close();
                    e.preventDefault();
                    return true;
                }
                that._current = calendar._move(e, true);
                handled = true;
            }
            return handled;
        };
        DateRangeView.prototype._click = function (e) {
            if (mobileOS.ios || mobileOS.android && mobileOS.browser == 'firefox') {
                if (this._range && this._range.end) {
                    this.close();
                }
            } else if (this._range && this._range.end === null && e.currentTarget.className.indexOf('k-state-selected') !== -1) {
                this.close();
            }
        };
        kendo.DateRangeView = DateRangeView;
        var DateRangePicker = Widget.extend({
            init: function (element, options) {
                var that = this;
                var div;
                var disabled;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.disableDates = kendo.calendar.disabled(options.disableDates);
                options.min = parse(element.attr('min')) || parse(options.min);
                options.max = parse(element.attr('max')) || parse(options.max);
                that._initialOptions = extend({}, options);
                that._buildHTML();
                that._range = that.options.range;
                that.dateView = new DateRangeView(extend({}, options, {
                    id: element.attr(ID),
                    anchor: that.wrapper,
                    views: 2,
                    selectable: 'range',
                    range: that._range,
                    change: function () {
                        var range = this.selectRange();
                        that.range(range);
                        that.trigger(CHANGE);
                        that._startDateInput.trigger(CHANGE);
                        that._endDateInput.trigger(CHANGE);
                    },
                    close: function (e) {
                        if (that.trigger(CLOSE)) {
                            e.preventDefault();
                        } else {
                            that.wrapper.attr(ARIA_EXPANDED, false);
                            div.attr(ARIA_HIDDEN, true);
                        }
                    },
                    open: function (e) {
                        if (that.trigger(OPEN)) {
                            e.preventDefault();
                        } else {
                            that.wrapper.attr(ARIA_EXPANDED, true);
                            div.attr(ARIA_HIDDEN, false);
                            that._updateARIA();
                        }
                    }
                }));
                div = that.dateView.div;
                that._ariaTemplate = template(this.options.ARIATemplate);
                that._reset();
                that.wrapper.attr({
                    role: 'combobox',
                    'aria-expanded': false,
                    'aria-owns': that.dateView._dateViewID,
                    'autocomplete': 'off'
                });
                that._inputs.on(UP + ns, proxy(that._click, that)).on('keydown' + ns, proxy(that._keydown, that));
                that._initializeDateInputs();
                disabled = element.is('[disabled]');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
            },
            options: {
                name: 'DateRangePicker',
                labels: true,
                footer: '',
                format: '',
                culture: '',
                min: new Date(1900, 0, 1),
                max: new Date(2099, 11, 31),
                start: MONTH,
                depth: MONTH,
                animation: {},
                month: {},
                startField: '',
                endField: '',
                dates: [],
                disableDates: null,
                range: null,
                ARIATemplate: 'Current focused date is #=kendo.toString(data.current, "D")#',
                weekNumber: false,
                messages: {
                    startLabel: 'Start',
                    endLabel: 'End'
                }
            },
            events: [
                OPEN,
                CLOSE,
                CHANGE
            ],
            setOptions: function (options) {
                var that = this;
                Widget.fn.setOptions.call(that, options);
                options = that.options;
                options.min = parse(options.min);
                options.max = parse(options.max);
                that._inputs.off(ns);
                this._initializeDateInputs();
                that.dateView.setOptions(options);
                that._range = options.range;
            },
            _click: function () {
                var that = this;
                if (!that._preventInputAction && !that.dateView.popup.visible()) {
                    that.dateView.open();
                }
            },
            _keydown: function (e) {
                var that = this, dateView = that.dateView, handled = false;
                if (that._preventInputAction) {
                    e.stopImmediatePropagation();
                    return;
                }
                handled = dateView.move(e);
                that._updateARIA(dateView._current);
                if (handled && e.stopImmediatePropagation) {
                    e.stopImmediatePropagation();
                }
            },
            _updateARIA: function (date) {
                var cell;
                var that = this;
                var calendar = that.dateView.calendar;
                if (that.element && that.element.length) {
                    that.element[0].removeAttribute('aria-activedescendant');
                }
                if (calendar) {
                    if (date && !calendar._dateInViews(date)) {
                        calendar.navigate(date);
                    }
                    cell = calendar._cellByDate(date || calendar.current());
                    calendar._focusCell(cell);
                    cell.attr('aria-label', that._ariaTemplate({ current: date || calendar.current() }));
                    that.element.attr('aria-activedescendant', cell.attr('id'));
                }
            },
            _startChange: function (e) {
                var that = this;
                var input = e.sender;
                var startValue = input.value();
                var endValue = that._endDateInput.value();
                if (that.options.disableDates(startValue)) {
                    e.sender.value(null);
                    startValue = null;
                }
                that.range({
                    start: startValue,
                    end: endValue
                });
                that.trigger(CHANGE);
            },
            _endChange: function (e) {
                var that = this;
                var input = e.sender;
                var endValue = input.value();
                var startValue = that._startDateInput.value();
                if (that.options.disableDates(endValue)) {
                    e.sender.value(null);
                    endValue = null;
                }
                that.range({
                    start: startValue,
                    end: endValue
                });
                that.trigger(CHANGE);
            },
            _initializeDateInputs: function () {
                var that = this;
                var options = that.options;
                var range = options.range || {};
                var inputOptions = {
                    footer: options.footer,
                    format: options.format,
                    culture: options.culture,
                    min: options.min,
                    max: options.max,
                    start: options.start,
                    startField: options.startField,
                    endField: options.endField,
                    depth: options.depth,
                    animation: options.animation,
                    month: options.month,
                    dates: options.dates,
                    disableDates: options.disableDates,
                    ARIATemplate: options.ARIATemplate,
                    weekNumber: options.weekNumber
                };
                if (that._startDateInput) {
                    that._startDateInput.destroy();
                    that._endDateInput.destroy();
                    that.wrapper.empty();
                    that._buildHTML();
                    that._inputs.on(UP + ns, proxy(that._click, that)).on('keydown' + ns, proxy(that._keydown, that));
                }
                that._startDateInput = that._startInput.kendoDateInput(extend(true, inputOptions, { value: range.start })).getKendoDateInput();
                that._endDateInput = that._endInput.kendoDateInput(extend(true, inputOptions, { value: range.end })).getKendoDateInput();
                that._startChangeHandler = proxy(that._startChange, that);
                that._startDateInput.bind(CHANGE, that._startChangeHandler);
                that._endChangeHandler = proxy(that._endChange, that);
                that._endDateInput.bind(CHANGE, that._endChangeHandler);
            },
            _buildHTML: function () {
                var that = this;
                var element = that.element;
                if (!that.wrapper) {
                    that.wrapper = element.addClass('k-widget k-daterangepicker');
                }
                if (that.options.labels) {
                    $('<span class="k-textbox-container"><input/><label class="k-label">' + that.options.messages.startLabel + '</label></span>').appendTo(that.wrapper);
                    $('<span>&nbsp;</span><span class="k-textbox-container"><input/><label class="k-label">' + that.options.messages.endLabel + '</label></span>').appendTo(that.wrapper);
                } else {
                    $('<input/><span>&nbsp;</span><input/>').appendTo(that.wrapper);
                }
                that._startInput = that.wrapper.find('input').eq(0);
                that._endInput = that.wrapper.find('input').eq(1);
                if (that.options.startField !== '') {
                    that._startInput.attr(kendo.attr('bind'), 'value: ' + that.options.startField);
                    that._startInput.attr('name', that.options.startField);
                }
                if (that.options.endField !== '') {
                    that._endInput.attr(kendo.attr('bind'), 'value: ' + that.options.endField);
                    that._endInput.attr('name', that.options.endField);
                }
                that._inputs = that._startInput.add(that._endInput);
            },
            _option: function (option, value) {
                var that = this, options = that.options;
                if (value === undefined) {
                    return options[option];
                }
                value = parse(value, options.parseFormats, options.culture);
                if (!value) {
                    return;
                }
                options[option] = new Date(+value);
                that.dateView[option](value);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        that.max(that._initialOptions.max);
                        that.min(that._initialOptions.min);
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            },
            _editable: function (options) {
                var that = this, inputs = that._inputs, readonly = options.readonly, disable = options.disable;
                if (!readonly && !disable) {
                    that.wrapper.addClass(DEFAULT).removeClass(STATEDISABLED);
                    $.each(inputs, function (key, item) {
                        item.removeAttribute(DISABLED);
                        item.removeAttribute(READONLY);
                    });
                    inputs.attr(ARIA_DISABLED, false);
                    that._preventInputAction = false;
                } else {
                    that.wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    inputs.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                    that._preventInputAction = true;
                }
            },
            destroy: function () {
                var that = this;
                if (that._startDateInput) {
                    that._startDateInput.unbind(CHANGE, that._startChangeHandler);
                    that._startDateInput.destroy();
                    that._startChangeHandler = null;
                }
                if (that._endDateInput) {
                    that._endDateInput.unbind(CHANGE, that._endChangeHandler);
                    that._endDateInput.destroy();
                    that._endChangeHandler = null;
                }
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
                that._inputs.off(ns);
                that._inputs = null;
                that.dateView.destroy();
                that.element.off(ns);
                Widget.fn.destroy.call(that);
            },
            range: function (range) {
                var that = this;
                if (range === undefined) {
                    return that._range;
                }
                that._range = range;
                that.dateView.range({
                    start: null,
                    end: null
                });
                if (!range) {
                    that._startDateInput.value(null);
                    that._endDateInput.value(null);
                }
                that._startDateInput.value(range.start ? range.start : null);
                that._endDateInput.value(range.end ? range.end : null);
                if (range.start && !range.end) {
                    that.dateView.range({
                        start: range.start,
                        end: null
                    });
                } else if (range.start && range.start && +range.start <= +range.end) {
                    that.dateView.range({
                        start: range.start,
                        end: range.end
                    });
                }
            },
            open: function () {
                this.dateView.open();
            },
            close: function () {
                this.dateView.close();
            },
            min: function (value) {
                return this._option(MIN, value);
            },
            max: function (value) {
                return this._option(MAX, value);
            },
            readonly: function (readonly) {
                this._startDateInput.readonly(readonly);
                this._endDateInput.readonly(readonly);
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._startDateInput.enable(enable);
                this._endDateInput.enable(enable);
                if (!enable) {
                    this.close();
                }
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            }
        });
        kendo.ui.plugin(DateRangePicker);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scrollview', [
        'kendo.fx',
        'kendo.data',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'scrollview',
        name: 'ScrollView',
        category: 'web',
        description: 'The Kendo ScrollView widget is used to scroll content wider than the device screen.',
        depends: [
            'fx',
            'data',
            'draganddrop'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, proxy = $.proxy, Transition = kendo.effects.Transition, Pane = kendo.ui.Pane, PaneDimensions = kendo.ui.PaneDimensions, Widget = ui.DataBoundWidget, DataSource = kendo.data.DataSource, math = Math, abs = math.abs, ceil = math.ceil, round = math.round, max = math.max, min = math.min, floor = math.floor, CHANGE = 'change', CLICK = 'click', CHANGING = 'changing', REFRESH = 'refresh', CURRENT_PAGE_CLASS = 'primary', VIRTUAL_PAGE_CLASS = 'scrollview-page', FUNCTION = 'function', ITEM_CHANGE = 'itemChange', CLEANUP = 'cleanup', VIRTUAL_PAGE_COUNT = 3, LEFT_PAGE = -1, CETER_PAGE = 0, RIGHT_PAGE = 1, LEFT_SWIPE = -1, NUDGE = 0, RIGHT_SWIPE = 1;
        function className(name) {
            return 'k-' + name;
        }
        var ScrollViewDataReader = kendo.Observable.extend({
            init: function (dataSource) {
                var that = this;
                this.dataSource = dataSource;
                this.pendingRequestArray = [];
                this.initialFetch = false;
                this.useRanges = dataSource.options.serverPaging;
                kendo.Observable.fn.init.call(this);
                dataSource.bind('change', function () {
                    that._change();
                });
            },
            _change: function () {
                this.trigger('reset', { offset: this.offset });
            },
            page: function (page, callback) {
                var that = this;
                if (!this.useRanges) {
                    this.dataSource.page(page + 1);
                    if (callback) {
                        callback(that.dataSource.view());
                    } else {
                        that.trigger('page', { page: page });
                    }
                }
                if (this.useRanges) {
                    this.dataSource.range(page * this.dataSource.pageSize(), this.dataSource.pageSize(), function () {
                        if (callback) {
                            callback(that.dataSource.view());
                        } else {
                            that.trigger('page', { page: page });
                        }
                    });
                }
            },
            scrollTo: function (page) {
                var pageCount = Math.ceil(this.dataSource.total() / this.dataSource.pageSize() || 1);
                var prevPage = page - 1;
                var prevPrefetch = prevPage - 1;
                var currentPage = page;
                var nextPage = pageCount > 0 && page + 1 >= pageCount ? -1 : page + 1;
                var nextPrefetch = pageCount > 0 && nextPage + 1 >= pageCount ? -1 : nextPage + 1;
                if (nextPage >= 0) {
                    this.pendingRequestArray.push(nextPage);
                }
                if (prevPage >= 0) {
                    this.pendingRequestArray.push(prevPage);
                }
                if (prevPrefetch >= 0) {
                    this.pendingRequestArray.push(prevPrefetch);
                }
                if (nextPrefetch >= 0) {
                    this.pendingRequestArray.push(nextPrefetch);
                }
                this.page(currentPage);
            },
            getViewData: function () {
                var view = this.dataSource.view();
                var data;
                if (this.dataSource.options.pageSize > 1) {
                    data = [];
                    for (var index = 0; index < view.length; index++) {
                        data.push(view[index]);
                    }
                } else {
                    data = view[0];
                }
                return data;
            },
            destroy: function () {
                var that = this;
                that.dataSource.unbind();
                that.dataSource = null;
            }
        });
        kendo.ui.ScrollViewDataReader = ScrollViewDataReader;
        var Pager = kendo.Class.extend({
            init: function (scrollView) {
                var that = this, element = $('<ul class=\'' + className('scrollview-nav') + '\'/>'), navigationWrapElement = $('<div class=\'' + className('scrollview-nav-wrap') + '\'></div>');
                navigationWrapElement.append(element);
                scrollView._navigationContainer.append(navigationWrapElement);
                this._changeProxy = proxy(that, '_change');
                this._refreshProxy = proxy(that, '_refresh');
                scrollView.bind(CHANGE, this._changeProxy);
                scrollView.bind(REFRESH, this._refreshProxy);
                element.on(CLICK, 'li.k-link', proxy(this._click, scrollView));
                $.extend(that, {
                    element: element,
                    scrollView: scrollView
                });
            },
            items: function () {
                return this.element.children();
            },
            _refresh: function (e) {
                var pageHTML = '';
                for (var idx = 0; idx < e.pageCount; idx++) {
                    pageHTML += '<li class="k-link"></li>';
                }
                this.element.html(pageHTML);
                this.items().eq(e.page).addClass(className(CURRENT_PAGE_CLASS));
                this.scrollView._toggleNavigation({ currentPage: e.page });
            },
            _change: function (e) {
                if (e.isDefaultPrevented()) {
                    return;
                }
                var innerNavigationContainer = this.scrollView._navigationContainer.find('.k-scrollview-nav');
                var scrollViewWidth = this.scrollView.element.width();
                var containerOffset = (scrollViewWidth - innerNavigationContainer.width()) / 2;
                var pageWidth = innerNavigationContainer.find('li.k-link:eq(0)').outerWidth(true) / 2;
                this.items().removeClass(className(CURRENT_PAGE_CLASS)).eq(e.nextPage).addClass(className(CURRENT_PAGE_CLASS));
                var itemOffset = this.items().eq(e.nextPage).length > 0 ? this.items().eq(e.nextPage).position().left : 0;
                if (itemOffset > scrollViewWidth / 2 || itemOffset < innerNavigationContainer.scrollLeft() + scrollViewWidth / 2) {
                    var translate = 0;
                    if (itemOffset > scrollViewWidth / 2) {
                        translate = innerNavigationContainer.scrollLeft() + itemOffset - scrollViewWidth / 2;
                    } else {
                        translate = innerNavigationContainer.scrollLeft() - (scrollViewWidth / 2 - itemOffset);
                    }
                    translate += containerOffset + pageWidth;
                    innerNavigationContainer.animate({ 'scrollLeft': translate }, 300);
                }
                this.scrollView._toggleNavigation({
                    currentPage: e.currentPage,
                    nextPage: e.nextPage
                });
            },
            _click: function (e) {
                var newPage = $(e.currentTarget).index();
                this.scrollTo(newPage);
            },
            destroy: function () {
                this.scrollView.unbind(CHANGE, this._changeProxy);
                this.scrollView.unbind(REFRESH, this._refreshProxy);
                this.element.off(CLICK);
                this.element.remove();
            }
        });
        kendo.ui.ScrollViewPager = Pager;
        var TRANSITION_END = 'transitionEnd', DRAG_START = 'dragStart', DRAG_END = 'dragEnd';
        var ElasticPane = kendo.Observable.extend({
            init: function (element, options) {
                var that = this;
                kendo.Observable.fn.init.call(this);
                this.element = element;
                this.container = element.parent();
                var movable, transition, userEvents, dimensions, dimension, pane;
                movable = new kendo.ui.Movable(that.element);
                transition = new Transition({
                    axis: 'x',
                    movable: movable,
                    onEnd: function () {
                        that.trigger(TRANSITION_END);
                    }
                });
                userEvents = new kendo.UserEvents(element, {
                    fastTap: true,
                    start: function (e) {
                        if (abs(e.x.velocity) * 2 >= abs(e.y.velocity)) {
                            userEvents.capture();
                        } else {
                            userEvents.cancel();
                        }
                        that.trigger(DRAG_START, e);
                        transition.cancel();
                    },
                    allowSelection: true,
                    end: function (e) {
                        that.trigger(DRAG_END, e);
                    }
                });
                dimensions = new PaneDimensions({
                    element: that.element,
                    container: that.container
                });
                dimension = dimensions.x;
                dimension.bind(CHANGE, function () {
                    that.trigger(CHANGE);
                });
                pane = new Pane({
                    dimensions: dimensions,
                    userEvents: userEvents,
                    movable: movable,
                    elastic: true
                });
                $.extend(that, {
                    duration: options && options.duration || 1,
                    movable: movable,
                    transition: transition,
                    userEvents: userEvents,
                    dimensions: dimensions,
                    dimension: dimension,
                    pane: pane
                });
                this.bind([
                    TRANSITION_END,
                    DRAG_START,
                    DRAG_END,
                    CHANGE
                ], options);
            },
            size: function () {
                return {
                    width: this.dimensions.x.getSize(),
                    height: this.dimensions.y.getSize()
                };
            },
            total: function () {
                return this.dimension.getTotal();
            },
            offset: function () {
                return -this.movable.x;
            },
            updateDimension: function () {
                this.dimension.update(true);
            },
            refresh: function () {
                this.dimensions.refresh();
                this.dimensions.y.enabled = false;
            },
            moveTo: function (offset) {
                this.movable.moveAxis('x', -offset);
            },
            transitionTo: function (offset, ease, instant) {
                if (instant) {
                    this.moveTo(-offset);
                } else {
                    this.transition.moveTo({
                        location: offset,
                        duration: this.duration,
                        ease: ease
                    });
                }
            },
            destroy: function () {
                var that = this;
                that.userEvents.destroy();
                that.unbind();
                that.movable = that.tansition = that.dimensions = that.dimension = that.pane = null;
                that.element.remove();
            }
        });
        kendo.ui.ScrollViewElasticPane = ElasticPane;
        var ScrollViewContent = kendo.Observable.extend({
            init: function (element, pane, options) {
                var that = this;
                kendo.Observable.fn.init.call(this);
                that.element = element;
                that.pane = pane;
                that._getPages();
                this.page = 0;
                this.pageSize = options.pageSize || 1;
                this.contentHeight = options.contentHeight;
                this.enablePager = options.enablePager;
                this.pagerOverlay = options.pagerOverlay;
            },
            scrollTo: function (page, instant) {
                var that = this;
                if (page == that.page && !instant) {
                    return;
                }
                if (!that.trigger('resize', {
                        currentPage: this.page,
                        nextPage: page,
                        data: undefined
                    })) {
                    that.page = page;
                    that.pane.transitionTo(-page * that.pane.size().width, Transition.easeOutExpo, instant);
                }
            },
            paneMoved: function (swipeType, bounce, callback, instant) {
                var that = this, pane = that.pane, width = pane.size().width * that.pageSize, approx = round, ease = bounce ? Transition.easeOutBack : Transition.easeOutExpo, snap, nextPage;
                if (swipeType === LEFT_SWIPE) {
                    approx = ceil;
                } else if (swipeType === RIGHT_SWIPE) {
                    approx = floor;
                }
                nextPage = approx(pane.offset() / width);
                if (nextPage < 0 || nextPage >= that.pageCount) {
                    var tansition = nextPage < 0 ? 0 : -this.page * this.pane.size().width;
                    return this.pane.transitionTo(tansition, ease, instant);
                }
                snap = max(that.minSnap, min(-nextPage * width, that.maxSnap));
                if (nextPage != that.page) {
                    if (callback && callback({
                            currentPage: that.page,
                            nextPage: nextPage
                        })) {
                        snap = -that.page * pane.size().width;
                    }
                }
                pane.transitionTo(snap, ease, instant);
            },
            updatePage: function () {
                var pane = this.pane, page = round(pane.offset() / pane.size().width);
                if (page != this.page) {
                    this.page = page;
                    return true;
                }
                return false;
            },
            forcePageUpdate: function () {
                return this.updatePage();
            },
            resizeTo: function (size) {
                var pane = this.pane, width = size.width;
                this.pageElements.width(width);
                if (this.contentHeight === '100%') {
                    var containerHeight = this.element.parent().height();
                    if (this.enablePager === true) {
                        var pager = this.element.parent().find('ul.k-scrollview-nav');
                        if (!this.pagerOverlay && pager.length) {
                            containerHeight -= kendo._outerHeight(pager, true);
                        }
                    }
                    this.element.css('height', containerHeight);
                    this.pageElements.css('height', containerHeight);
                }
                pane.updateDimension();
                if (!this._paged) {
                    this.page = floor(pane.offset() / width);
                }
                this.scrollTo(this.page, true, true);
                this.pageCount = floor(pane.total() / width);
                this.minSnap = -(this.pageCount - 1) * width;
                this.maxSnap = 0;
            },
            _getPages: function () {
                this.pageElements = this.element.find(kendo.roleSelector('page'));
                this._paged = this.pageElements.length > 0;
            },
            destroy: function () {
                var that = this;
                that.pane = null;
                that.element.remove();
            }
        });
        kendo.ui.ScrollViewContent = ScrollViewContent;
        var VirtualScrollViewContent = kendo.Observable.extend({
            init: function (element, pane, options) {
                var that = this;
                kendo.Observable.fn.init.call(this);
                that.element = element;
                that.pane = pane;
                that.options = options;
                that._templates();
                that.page = options.page || 0;
                that.pages = [];
                that._initPages();
                that.resizeTo(that.pane.size());
                that.pane.dimension.forceEnabled();
            },
            setDataSource: function (dataSource) {
                this.dataSource = DataSource.create(dataSource);
                this._dataReader();
                this._pendingPageRefresh = false;
                this._pendingWidgetRefresh = false;
            },
            _viewShow: function () {
                var that = this;
                if (that._pendingWidgetRefresh) {
                    setTimeout(function () {
                        that._resetPages();
                    }, 0);
                    that._pendingWidgetRefresh = false;
                }
            },
            _dataReader: function () {
                this.dataReader = new ScrollViewDataReader(this.dataSource);
                this._pageProxy = proxy(this, '_onPage');
                this._resetProxy = proxy(this, '_onReset');
                this.dataReader.bind({
                    'page': this._pageProxy,
                    'reset': this._resetProxy
                });
            },
            _templates: function () {
                var template = this.options.template, emptyTemplate = this.options.emptyTemplate, templateProxy = {}, emptyTemplateProxy = {};
                if (typeof template === FUNCTION) {
                    templateProxy.template = template;
                    template = '#=this.template(data)#';
                }
                this.template = proxy(kendo.template(template), templateProxy);
                if (typeof emptyTemplate === FUNCTION) {
                    emptyTemplateProxy.emptyTemplate = emptyTemplate;
                    emptyTemplate = '#=this.emptyTemplate(data)#';
                }
                this.emptyTemplate = proxy(kendo.template(emptyTemplate), emptyTemplateProxy);
            },
            _initPages: function () {
                var pages = this.pages, element = this.element, page;
                for (var i = 0; i < VIRTUAL_PAGE_COUNT; i++) {
                    page = new Page(element);
                    pages.push(page);
                }
                this.pane.updateDimension();
            },
            resizeTo: function (size) {
                var pages = this.pages, pane = this.pane;
                for (var i = 0; i < pages.length; i++) {
                    pages[i].setWidth(size.width);
                }
                if (this.options.contentHeight === 'auto') {
                    this.element.css('height', this.pages[1].element.height());
                } else if (this.options.contentHeight === '100%') {
                    var containerHeight = this.element.parent().height();
                    if (this.options.enablePager === true) {
                        var pager = this.element.parent().find('ul.k-scrollview-nav');
                        if (!this.options.pagerOverlay && pager.length) {
                            containerHeight -= kendo._outerHeight(pager, true);
                        }
                    }
                    this.element.css('height', containerHeight);
                    pages[0].element.css('height', containerHeight);
                    pages[1].element.css('height', containerHeight);
                    pages[2].element.css('height', containerHeight);
                } else if (this.options.contentHeight) {
                    pages[0].element.css('height', this.options.contentHeight);
                    pages[1].element.css('height', this.options.contentHeight);
                    pages[2].element.css('height', this.options.contentHeight);
                }
                pane.updateDimension();
                this._repositionPages();
                this.width = size.width;
            },
            scrollTo: function (page, instant, silent) {
                var that = this;
                var dataReader = that.dataReader;
                if (page == that.page && !instant) {
                    return;
                }
                dataReader.page(page, function (data) {
                    if (silent) {
                        dataReader.scrollTo(page);
                        return;
                    }
                    if (!that.trigger('resize', {
                            currentPage: that.page,
                            nextPage: page,
                            data: data
                        })) {
                        if (!instant) {
                            dataReader.pagerScroll = page > that.page ? -1 : 1;
                            that.page = page + dataReader.pagerScroll;
                        } else {
                            that.page = page;
                        }
                        dataReader.scrollTo(page);
                    }
                });
            },
            paneMoved: function (swipeType, bounce, callback, instant) {
                var that = this, pane = that.pane, width = pane.size().width, offset = pane.offset(), thresholdPassed = Math.abs(offset) >= width / 3, ease = bounce ? kendo.effects.Transition.easeOutBack : kendo.effects.Transition.easeOutExpo, isEndReached = that.dataSource.options.serverPaging ? that.page + 2 > that.pageCount : false, nextPage, delta = 0, data, element;
                if (swipeType === RIGHT_SWIPE) {
                    if (that.page !== 0) {
                        delta = -1;
                    }
                } else if (swipeType === LEFT_SWIPE && !isEndReached) {
                    delta = 1;
                } else if (offset > 0 && (thresholdPassed && !isEndReached)) {
                    delta = 1;
                } else if (offset < 0 && thresholdPassed) {
                    if (that.page !== 0) {
                        delta = -1;
                    }
                }
                nextPage = that.page;
                if (delta) {
                    nextPage = delta > 0 ? nextPage + 1 : nextPage - 1;
                    if (that instanceof kendo.ui.VirtualScrollViewContent) {
                        that.dataReader.page(nextPage);
                        data = that.dataReader.getViewData();
                    } else {
                        data = undefined;
                    }
                    if (!(data instanceof Array)) {
                        data = [data];
                    }
                    element = that.pages ? that.pages[1].element : undefined;
                }
                if (callback && that.page != nextPage && callback({
                        currentPage: that.page,
                        nextPage: nextPage,
                        element: element,
                        data: data
                    })) {
                    delta = 0;
                }
                if (delta === 0) {
                    that._cancelMove(ease, instant);
                } else if (delta === -1) {
                    that._moveBackward(instant);
                } else if (delta === 1) {
                    that._moveForward(instant);
                }
            },
            updatePage: function () {
                var pages = this.pages;
                if (this.pane.offset() === 0) {
                    return false;
                }
                if (this.pane.offset() > 0) {
                    pages.push(this.pages.shift());
                    this.page++;
                    if (this.page + 2 < this.pageCount) {
                        this.dataReader.pendingRequestArray.push(this.page + 2);
                    }
                    if (this.page + 1 < this.pageCount) {
                        this.dataReader.page(this.page + 1);
                    }
                    if (this.page + 1 == this.pageCount) {
                        this.setPageContent(this.pages[2], null);
                    }
                } else {
                    pages.unshift(this.pages.pop());
                    this.page--;
                    if (this.page - 2 >= 0) {
                        this.dataReader.pendingRequestArray.push(this.page - 2);
                    }
                    if (this.page - 1 >= 0) {
                        this.dataReader.page(this.page - 1);
                    }
                }
                this._repositionPages();
                this._resetMovable();
                return true;
            },
            forcePageUpdate: function () {
                var offset = this.pane.offset(), threshold = this.pane.size().width * 3 / 4;
                if (abs(offset) > threshold) {
                    return this.updatePage();
                }
                return false;
            },
            _resetMovable: function () {
                this.pane.moveTo(0);
            },
            _moveForward: function (instant) {
                this.pane.transitionTo(-this.width, kendo.effects.Transition.easeOutExpo, instant);
            },
            _moveBackward: function (instant) {
                this.pane.transitionTo(this.width, kendo.effects.Transition.easeOutExpo, instant);
            },
            _cancelMove: function (ease, instant) {
                this.pane.transitionTo(0, ease, instant);
            },
            _resetPages: function () {
                this.page = this.options.page || 0;
                this._repositionPages();
                this.trigger('reset');
            },
            _onPage: function (e) {
                if (e.page >= this.pageCount) {
                    this.setPageContent(this.pages[2], null);
                }
                if (this.page == e.page) {
                    if (!this.dataReader.pagerScroll || this.dataReader.pagerScroll === 0 && this.dataReader.initialFetch) {
                        this.setPageContent(this.pages[1], this.dataReader.getViewData());
                    } else {
                        if (this.dataReader.pagerScroll < 0) {
                            this._moveForward();
                        } else {
                            this._moveBackward();
                        }
                        this.dataReader.pagerScroll = 0;
                        this.setPageContent(this.pages[1], this.dataReader.getViewData());
                    }
                } else if (this.page + 1 == e.page) {
                    this.setPageContent(this.pages[2], this.dataReader.getViewData());
                } else if (this.page - 1 == e.page) {
                    this.setPageContent(this.pages[0], this.dataReader.getViewData());
                }
                if (this.dataReader.pendingRequestArray.length > 0 && this.dataReader.initialFetch) {
                    var item = this.dataReader.pendingRequestArray.shift();
                    this.dataReader.page(item);
                }
            },
            _onReset: function () {
                this.pageCount = ceil(this.dataSource.total() / this.dataSource.pageSize());
            },
            _repositionPages: function () {
                var pages = this.pages;
                pages[0].position(LEFT_PAGE);
                pages[1].position(CETER_PAGE);
                pages[2].position(RIGHT_PAGE);
            },
            setPageContent: function (page, data) {
                var template = this.template, emptyTemplate = this.emptyTemplate;
                if (data !== null && data !== undefined) {
                    page.content(template(data));
                } else {
                    page.content(emptyTemplate({}));
                }
            },
            destroy: function () {
                var that = this;
                var pages = that.pages;
                that.dataReader.unbind();
                that.dataSource.unbind();
                that.dataReader = that.dataSource = that.pane = null;
                for (var index = 0; index < pages.length; index++) {
                    pages[index].destroy();
                }
                that.element.remove();
            }
        });
        kendo.ui.VirtualScrollViewContent = VirtualScrollViewContent;
        var Page = kendo.Class.extend({
            init: function (container) {
                this.element = $('<li class=\'' + className(VIRTUAL_PAGE_CLASS) + '\'></li>');
                this.width = container.width();
                this.element.width(this.width);
                container.append(this.element);
            },
            content: function (theContent) {
                this.element.html(theContent);
            },
            position: function (position) {
                this.element.css('transform', 'translate3d(' + this.width * position + 'px, 0, 0)');
            },
            setWidth: function (width) {
                this.width = width;
                this.element.width(width);
            },
            destroy: function () {
                var that = this;
                that.element.remove();
                that.element = null;
            }
        });
        kendo.ui.VirtualPage = Page;
        var ScrollView = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element;
                kendo.stripWhitespace(element[0]);
                if (element.children().length === 0) {
                    element.wrapInner('<ul class=\'k-scrollview-wrap\'/>');
                } else {
                    element.wrapInner('<div class=\'k-scrollview-wrap\'/>');
                }
                element.addClass('k-widget ' + className('scrollview'));
                that._initNavigation();
                if (this.options.enablePager) {
                    this.pager = new Pager(this);
                    if (this.options.pagerOverlay) {
                        element.addClass(className('scrollview-overlay'));
                    }
                } else {
                    this._changeProxy = proxy(that, '_toggleNavigation');
                    this.bind(CHANGE, this._changeProxy);
                }
                that.inner = element.children().first();
                that.page = 0;
                that.inner.css('height', options.contentHeight);
                that.pane = new ElasticPane(that.inner, {
                    duration: this.options.duration,
                    transitionEnd: proxy(this, '_transitionEnd'),
                    dragStart: proxy(this, '_dragStart'),
                    dragEnd: proxy(this, '_dragEnd'),
                    change: proxy(this, REFRESH)
                });
                that.bind('resize', function () {
                    that.pane.refresh();
                });
                that.page = options.page;
                var empty = this.inner.children().length === 0;
                var content = empty ? new VirtualScrollViewContent(that.inner, that.pane, options) : new ScrollViewContent(that.inner, that.pane, options);
                content.page = that.page;
                content.bind('reset', function () {
                    this._pendingPageRefresh = false;
                    that.trigger(REFRESH, {
                        pageCount: content.pageCount,
                        page: content.page
                    });
                    that._toggleNavigation({
                        currentPage: content.page,
                        nextPage: content.page
                    });
                });
                content.bind('resize', function (e) {
                    var currentPage = content.page;
                    var nextPage = e.nextPage;
                    if (currentPage != nextPage) {
                        e._defaultPrevented = that.trigger(CHANGE, {
                            currentPage: content.page,
                            nextPage: e.nextPage,
                            data: e.data
                        });
                    }
                    that._toggleNavigation({
                        currentPage: content.page,
                        nextPage: e.nextPage
                    });
                });
                content.bind(ITEM_CHANGE, function (e) {
                    that.trigger(ITEM_CHANGE, e);
                    that.angular('compile', function () {
                        return {
                            elements: e.item,
                            data: [{ dataItem: e.data }]
                        };
                    });
                });
                content.bind(CLEANUP, function (e) {
                    that.angular('cleanup', function () {
                        return { elements: e.item };
                    });
                });
                that._content = content;
                that.setDataSource(options.dataSource);
                this.viewInit();
                this.viewShow();
            },
            options: {
                name: 'ScrollView',
                page: 0,
                duration: 400,
                velocityThreshold: 0.8,
                contentHeight: 'auto',
                pageSize: 1,
                bounceVelocityThreshold: 1.6,
                enablePager: true,
                enableNavigationButtons: true,
                pagerOverlay: true,
                autoBind: true,
                template: '',
                emptyTemplate: ''
            },
            events: [
                CHANGING,
                CHANGE,
                REFRESH
            ],
            destroy: function () {
                Widget.fn.destroy.call(this);
                this._content.destroy();
                this.pane.destroy();
                if (this.pager) {
                    this.pager.destroy();
                }
                this.inner = null;
                kendo.destroy(this.element);
            },
            viewInit: function () {
                if (this.options.autoBind) {
                    this._content.scrollTo(this._content.page, true, true);
                }
            },
            viewShow: function () {
                this.pane.refresh();
            },
            refresh: function () {
                var content = this._content;
                var options = this.options;
                content.resizeTo(this.pane.size());
                this.page = content.page;
                if (content instanceof ScrollViewContent || content.dataReader.initialFetch) {
                    if (options.enablePager) {
                        this.trigger(REFRESH, {
                            pageCount: content.pageCount,
                            page: content.page
                        });
                    } else {
                        this.trigger(CHANGE, {
                            pageCount: content.pageCount,
                            currentPage: content.page
                        });
                    }
                }
            },
            content: function (html) {
                this.element.children().first().html(html);
                this._content._getPages();
                this.pane.refresh();
            },
            scrollTo: function (page, instant, silent) {
                this._content.scrollTo(page, instant, silent);
            },
            prev: function () {
                var that = this, prevPage = that._content.page - 1;
                if (that._content instanceof VirtualScrollViewContent) {
                    that._content.paneMoved(RIGHT_SWIPE, undefined, function (eventData) {
                        return that.trigger(CHANGE, eventData);
                    });
                } else if (prevPage > -1) {
                    that.scrollTo(prevPage);
                }
            },
            next: function () {
                var that = this, nextPage = that._content.page + 1;
                if (that._content instanceof VirtualScrollViewContent) {
                    that._content.paneMoved(LEFT_SWIPE, undefined, function (eventData) {
                        return that.trigger(CHANGE, eventData);
                    });
                } else if (nextPage < that._content.pageCount) {
                    that.scrollTo(nextPage);
                }
            },
            setDataSource: function (dataSource) {
                var that = this;
                if (!(this._content instanceof VirtualScrollViewContent)) {
                    return;
                }
                var emptyDataSource = !dataSource;
                if (dataSource instanceof DataSource) {
                    dataSource.options.pageSize = dataSource.options.pageSize || 1;
                    this.dataSource = dataSource = new DataSource(dataSource.options);
                } else {
                    this.dataSource = DataSource.create(dataSource);
                }
                this._content.setDataSource(this.dataSource);
                if (this.options.autoBind && !emptyDataSource) {
                    this.dataSource.fetch(function () {
                        that._content.dataReader.initialFetch = true;
                        that.scrollTo(that._content.page, true, true);
                        that._content.trigger('reset');
                    });
                }
            },
            items: function () {
                return this.element.find('.k-' + VIRTUAL_PAGE_CLASS);
            },
            _dragStart: function () {
                this._content.forcePageUpdate();
            },
            _dragEnd: function (e) {
                var that = this, velocity = e.x.velocity, velocityThreshold = this.options.velocityThreshold, swipeType = NUDGE, bounce = abs(velocity) > this.options.bounceVelocityThreshold;
                if (velocity > velocityThreshold) {
                    swipeType = RIGHT_SWIPE;
                } else if (velocity < -velocityThreshold) {
                    swipeType = LEFT_SWIPE;
                }
                this._content.paneMoved(swipeType, bounce, function (eventData) {
                    return that.trigger(CHANGE, eventData);
                });
            },
            _transitionEnd: function () {
                this._content.updatePage();
            },
            _initNavigation: function () {
                var that = this;
                var navigationContainer = that._navigationContainer = $('<div class=\'k-scrollview-elements\'></div>');
                var prevArrow = $('<a class="k-scrollview-prev"><span class="k-icon k-i-arrowhead-w"></span></a>').hide();
                var nextArrow = $('<a class="k-scrollview-next"><span class="k-icon k-i-arrowhead-e"></span></a>').hide();
                navigationContainer.append(prevArrow);
                navigationContainer.append(nextArrow);
                that.element.append(navigationContainer);
                navigationContainer.on(CLICK, 'a.k-scrollview-prev', proxy(that.prev, that));
                navigationContainer.on(CLICK, 'a.k-scrollview-next', proxy(that.next, that));
            },
            _toggleNavigation: function (e) {
                var page = e.nextPage || e.nextPage === 0 ? e.nextPage : e.currentPage;
                var navigationContainer = this._navigationContainer;
                var prevArrow = navigationContainer.find('>a.k-scrollview-prev');
                var nextArrow = navigationContainer.find('>a.k-scrollview-next');
                prevArrow.hide();
                nextArrow.hide();
                if (page || page === 0) {
                    if (page !== 0) {
                        prevArrow.show();
                    }
                    if (page != this._content.pageCount - 1) {
                        nextArrow.show();
                    }
                }
            }
        });
        ui.plugin(ScrollView);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.splitter', ['kendo.resizable'], f);
}(function () {
    var __meta__ = {
        id: 'splitter',
        name: 'Splitter',
        category: 'web',
        description: 'The Splitter widget provides an easy way to create a dynamic layout of resizable and collapsible panes.',
        depends: ['resizable']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, keys = kendo.keys, extend = $.extend, proxy = $.proxy, Widget = ui.Widget, pxUnitsRegex = /^\d+(\.\d+)?px$/i, percentageUnitsRegex = /^\d+(\.\d+)?%$/i, NS = '.kendoSplitter', EXPAND = 'expand', COLLAPSE = 'collapse', CONTENTLOAD = 'contentLoad', ERROR = 'error', RESIZE = 'resize', LAYOUTCHANGE = 'layoutChange', HORIZONTAL = 'horizontal', VERTICAL = 'vertical', MOUSEENTER = 'mouseenter', CLICK = 'click', PANE = 'pane', MOUSELEAVE = 'mouseleave', FOCUSED = 'k-state-focused', KPANE = 'k-' + PANE, PANECLASS = '.' + KPANE;
        function isPercentageSize(size) {
            return percentageUnitsRegex.test(size);
        }
        function isPixelSize(size) {
            return pxUnitsRegex.test(size) || /^\d+$/.test(size);
        }
        function isFluid(size) {
            return !isPercentageSize(size) && !isPixelSize(size);
        }
        function calculateSize(size, total) {
            var output = parseInt(size, 10);
            if (isPercentageSize(size)) {
                output = Math.floor(output * total / 100);
            }
            return output;
        }
        function panePropertyAccessor(propertyName, triggersResize) {
            return function (pane, value) {
                var paneConfig = this.element.find(pane).data(PANE);
                if (arguments.length == 1) {
                    return paneConfig[propertyName];
                }
                paneConfig[propertyName] = value;
                if (triggersResize) {
                    var splitter = this.element.data('kendo' + this.options.name);
                    splitter.resize(true);
                }
            };
        }
        var Splitter = Widget.extend({
            init: function (element, options) {
                var that = this, isHorizontal;
                Widget.fn.init.call(that, element, options);
                that.wrapper = that.element;
                if (that.options.orientation) {
                    isHorizontal = that.options.orientation.toLowerCase() != VERTICAL;
                }
                that.orientation = isHorizontal ? HORIZONTAL : VERTICAL;
                that._dimension = isHorizontal ? 'width' : 'height';
                that._keys = {
                    decrease: isHorizontal ? keys.LEFT : keys.UP,
                    increase: isHorizontal ? keys.RIGHT : keys.DOWN
                };
                that._resizeStep = 10;
                that._marker = kendo.guid().substring(0, 8);
                that._initPanes();
                that.resizing = new PaneResizing(that);
                that.element.triggerHandler('init' + NS);
            },
            events: [
                EXPAND,
                COLLAPSE,
                CONTENTLOAD,
                ERROR,
                RESIZE,
                LAYOUTCHANGE
            ],
            _addOverlays: function () {
                this._panes().append('<div class=\'k-splitter-overlay k-overlay\' />');
            },
            _removeOverlays: function () {
                this._panes().children('.k-splitter-overlay').remove();
            },
            _attachEvents: function () {
                var that = this, orientation = that.options.orientation;
                that.element.children('.k-splitbar-draggable-' + orientation).on('keydown' + NS, proxy(that._keydown, that)).on('mousedown' + NS, function (e) {
                    e.currentTarget.focus();
                }).on('focus' + NS, function (e) {
                    $(e.currentTarget).addClass(FOCUSED);
                }).on('blur' + NS, function (e) {
                    $(e.currentTarget).removeClass(FOCUSED);
                    if (that.resizing) {
                        that.resizing.end();
                    }
                }).on(MOUSEENTER + NS, function () {
                    $(this).addClass('k-splitbar-' + that.orientation + '-hover');
                }).on(MOUSELEAVE + NS, function () {
                    $(this).removeClass('k-splitbar-' + that.orientation + '-hover');
                }).on('mousedown' + NS, proxy(that._addOverlays, that)).end().children('.k-splitbar').on('dblclick' + NS, proxy(that._togglePane, that)).children('.k-collapse-next, .k-collapse-prev').on(CLICK + NS, that._arrowClick(COLLAPSE)).end().children('.k-expand-next, .k-expand-prev').on(CLICK + NS, that._arrowClick(EXPAND)).end().end();
                $(window).on('resize' + NS + that._marker, proxy(that.resize, that, false));
                $(document).on('mouseup' + NS + that._marker, proxy(that._removeOverlays, that));
            },
            _detachEvents: function () {
                var that = this;
                that.element.children('.k-splitbar-draggable-' + that.orientation).off(NS).end().children('.k-splitbar').off('dblclick' + NS).children('.k-collapse-next, .k-collapse-prev, .k-expand-next, .k-expand-prev').off(NS);
                $(window).off(NS + that._marker);
                $(document).off(NS + that._marker);
            },
            options: {
                name: 'Splitter',
                orientation: HORIZONTAL,
                panes: []
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this._detachEvents();
                if (this.resizing) {
                    this.resizing.destroy();
                }
                kendo.destroy(this.element);
                this.wrapper = this.element = null;
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, resizing = that.resizing, target = $(e.currentTarget), navigationKeys = that._keys, increase = key === navigationKeys.increase, decrease = key === navigationKeys.decrease, pane;
                if (increase || decrease) {
                    if (e.ctrlKey) {
                        pane = target[decrease ? 'next' : 'prev']();
                        if (resizing && resizing.isResizing()) {
                            resizing.end();
                        }
                        if (!pane[that._dimension]()) {
                            that._triggerAction(EXPAND, pane);
                        } else {
                            that._triggerAction(COLLAPSE, target[decrease ? 'prev' : 'next']());
                        }
                    } else if (resizing) {
                        resizing.move((decrease ? -1 : 1) * that._resizeStep, target);
                    }
                    e.preventDefault();
                } else if (key === keys.HOME) {
                    resizing.move(-resizing._maxPosition, target);
                    e.preventDefault();
                } else if (key === keys.END) {
                    resizing.move(resizing._maxPosition, target);
                    e.preventDefault();
                } else if (key === keys.ENTER && resizing) {
                    resizing.end();
                    e.preventDefault();
                }
            },
            _initPanes: function () {
                var panesConfig = this.options.panes || [];
                var that = this;
                this.element.addClass('k-widget').addClass('k-splitter').children().each(function (i, pane) {
                    if (pane.nodeName.toLowerCase() != 'script') {
                        that._initPane(pane, panesConfig[i]);
                    }
                });
                this.resize();
            },
            _initPane: function (pane, config) {
                pane = $(pane).attr('role', 'group').addClass(KPANE);
                pane.data(PANE, config ? config : {}).toggleClass('k-scrollable', config ? config.scrollable !== false : true);
                this.ajaxRequest(pane);
            },
            ajaxRequest: function (pane, url, data) {
                var that = this, paneConfig;
                pane = that.element.find(pane);
                paneConfig = pane.data(PANE);
                url = url || paneConfig.contentUrl;
                if (url) {
                    pane.append('<span class=\'k-icon k-i-loading k-pane-loading\' />');
                    if (kendo.isLocalUrl(url)) {
                        jQuery.ajax({
                            url: url,
                            data: data || {},
                            type: 'GET',
                            dataType: 'html',
                            success: function (data) {
                                that.angular('cleanup', function () {
                                    return { elements: pane.get() };
                                });
                                pane.html(data);
                                that.angular('compile', function () {
                                    return { elements: pane.get() };
                                });
                                that.trigger(CONTENTLOAD, { pane: pane[0] });
                            },
                            error: function (xhr, status) {
                                that.trigger(ERROR, {
                                    pane: pane[0],
                                    status: status,
                                    xhr: xhr
                                });
                            }
                        });
                    } else {
                        pane.removeClass('k-scrollable').html('<iframe src=\'' + url + '\' frameborder=\'0\' class=\'k-content-frame\'>' + 'This page requires frames in order to show content' + '</iframe>');
                    }
                }
            },
            _triggerAction: function (type, pane) {
                if (!this.trigger(type, { pane: pane[0] })) {
                    this[type](pane[0]);
                }
            },
            _togglePane: function (e) {
                var that = this, target = $(e.target), arrow;
                if (target.closest('.k-splitter')[0] != that.element[0]) {
                    return;
                }
                arrow = target.children('.k-icon:not(.k-resize-handle)');
                if (arrow.length !== 1) {
                    return;
                }
                if (arrow.is('.k-collapse-prev')) {
                    that._triggerAction(COLLAPSE, target.prev());
                } else if (arrow.is('.k-collapse-next')) {
                    that._triggerAction(COLLAPSE, target.next());
                } else if (arrow.is('.k-expand-prev')) {
                    that._triggerAction(EXPAND, target.prev());
                } else if (arrow.is('.k-expand-next')) {
                    that._triggerAction(EXPAND, target.next());
                }
            },
            _arrowClick: function (arrowType) {
                var that = this;
                return function (e) {
                    var target = $(e.target), pane;
                    if (target.closest('.k-splitter')[0] != that.element[0]) {
                        return;
                    }
                    if (target.is('.k-' + arrowType + '-prev')) {
                        pane = target.parent().prev();
                    } else {
                        pane = target.parent().next();
                    }
                    that._triggerAction(arrowType, pane);
                };
            },
            _updateSplitBar: function (splitbar, previousPane, nextPane) {
                var catIconIf = function (iconType, condition) {
                        return condition ? '<div class=\'k-icon ' + iconType + '\' />' : '';
                    }, orientation = this.orientation, draggable = previousPane.resizable !== false && nextPane.resizable !== false, prevCollapsible = previousPane.collapsible, prevCollapsed = previousPane.collapsed, nextCollapsible = nextPane.collapsible, nextCollapsed = nextPane.collapsed;
                splitbar.addClass('k-splitbar k-state-default k-splitbar-' + orientation).attr('role', 'separator').attr('aria-expanded', !(prevCollapsed || nextCollapsed)).removeClass('k-splitbar-' + orientation + '-hover').toggleClass('k-splitbar-draggable-' + orientation, draggable && !prevCollapsed && !nextCollapsed).toggleClass('k-splitbar-static-' + orientation, !draggable && !prevCollapsible && !nextCollapsible).html(catIconIf('k-collapse-prev k-i-arrow-60-up', prevCollapsible && !prevCollapsed && !nextCollapsed && orientation == VERTICAL) + catIconIf('k-collapse-prev k-i-arrow-60-left', prevCollapsible && !prevCollapsed && !nextCollapsed && orientation == HORIZONTAL) + catIconIf('k-expand-prev k-i-arrow-60-down', prevCollapsible && prevCollapsed && !nextCollapsed && orientation == VERTICAL) + catIconIf('k-expand-prev k-i-arrow-60-right', prevCollapsible && prevCollapsed && !nextCollapsed && orientation == HORIZONTAL) + catIconIf('k-resize-handle k-i-hbar', draggable && orientation == VERTICAL) + catIconIf('k-resize-handle k-i-vbar', draggable && orientation == HORIZONTAL) + catIconIf('k-collapse-next k-i-arrow-60-down', nextCollapsible && !nextCollapsed && !prevCollapsed && orientation == VERTICAL) + catIconIf('k-collapse-next k-i-arrow-60-right', nextCollapsible && !nextCollapsed && !prevCollapsed && orientation == HORIZONTAL) + catIconIf('k-expand-next k-i-arrow-60-up', nextCollapsible && nextCollapsed && !prevCollapsed && orientation == VERTICAL) + catIconIf('k-expand-next k-i-arrow-60-left', nextCollapsible && nextCollapsed && !prevCollapsed && orientation == HORIZONTAL));
                if (!draggable && !prevCollapsible && !nextCollapsible) {
                    splitbar.removeAttr('tabindex');
                }
            },
            _updateSplitBars: function () {
                var that = this;
                this.element.children('.k-splitbar').each(function () {
                    var splitbar = $(this), previousPane = splitbar.prevAll(PANECLASS).first().data(PANE), nextPane = splitbar.nextAll(PANECLASS).first().data(PANE);
                    if (!nextPane) {
                        return;
                    }
                    that._updateSplitBar(splitbar, previousPane, nextPane);
                });
            },
            _removeSplitBars: function () {
                this.element.children('.k-splitbar').remove();
            },
            _panes: function () {
                if (!this.element) {
                    return $();
                }
                return this.element.children(PANECLASS);
            },
            _resize: function () {
                var that = this, element = that.element, panes = element.children(PANECLASS), isHorizontal = that.orientation == HORIZONTAL, splitBars = element.children('.k-splitbar'), splitBarsCount = splitBars.length, sizingProperty = isHorizontal ? 'width' : 'height', totalSize = element[sizingProperty]();
                that.wrapper.addClass('k-splitter-resizing');
                if (splitBarsCount === 0) {
                    splitBarsCount = panes.length - 1;
                    panes.slice(0, splitBarsCount).after('<div tabindex=\'0\' class=\'k-splitbar\' data-marker=\'' + that._marker + '\' />');
                    that._updateSplitBars();
                    splitBars = element.children('.k-splitbar');
                } else {
                    that._updateSplitBars();
                }
                splitBars.each(function () {
                    totalSize -= this[isHorizontal ? 'offsetWidth' : 'offsetHeight'];
                });
                var sizedPanesWidth = 0, sizedPanesCount = 0, freeSizedPanes = $();
                panes.css({
                    position: 'absolute',
                    top: 0
                })[sizingProperty](function () {
                    var element = $(this), config = element.data(PANE) || {}, size;
                    element.removeClass('k-state-collapsed');
                    if (config.collapsed) {
                        size = config.collapsedSize ? calculateSize(config.collapsedSize, totalSize) : 0;
                        element.css('overflow', 'hidden').addClass('k-state-collapsed');
                    } else if (isFluid(config.size)) {
                        freeSizedPanes = freeSizedPanes.add(this);
                        return;
                    } else {
                        size = calculateSize(config.size, totalSize);
                    }
                    sizedPanesCount++;
                    sizedPanesWidth += size;
                    return size;
                });
                totalSize -= sizedPanesWidth;
                var freeSizePanesCount = freeSizedPanes.length, freeSizePaneWidth = Math.floor(totalSize / freeSizePanesCount);
                freeSizedPanes.slice(0, freeSizePanesCount - 1).css(sizingProperty, freeSizePaneWidth).end().eq(freeSizePanesCount - 1).css(sizingProperty, totalSize - (freeSizePanesCount - 1) * freeSizePaneWidth);
                var sum = 0, alternateSizingProperty = isHorizontal ? 'height' : 'width', positioningProperty = isHorizontal ? 'left' : 'top', sizingDomProperty = isHorizontal ? 'offsetWidth' : 'offsetHeight';
                if (freeSizePanesCount === 0) {
                    var lastNonCollapsedPane = panes.filter(function () {
                        return !($(this).data(PANE) || {}).collapsed;
                    }).last();
                    lastNonCollapsedPane[sizingProperty](totalSize + lastNonCollapsedPane[0][sizingDomProperty]);
                }
                element.children().css(alternateSizingProperty, element[alternateSizingProperty]()).each(function (i, child) {
                    if (child.tagName.toLowerCase() != 'script') {
                        child.style[positioningProperty] = Math.floor(sum) + 'px';
                        sum += child[sizingDomProperty];
                    }
                });
                that._detachEvents();
                that._attachEvents();
                that.wrapper.removeClass('k-splitter-resizing');
                kendo.resize(panes);
                that.trigger(LAYOUTCHANGE);
            },
            toggle: function (pane, expand) {
                var that = this, paneConfig;
                pane = that.element.find(pane);
                paneConfig = pane.data(PANE);
                if (!expand && !paneConfig.collapsible) {
                    return;
                }
                if (arguments.length == 1) {
                    expand = paneConfig.collapsed === undefined ? false : paneConfig.collapsed;
                }
                paneConfig.collapsed = !expand;
                if (paneConfig.collapsed) {
                    pane.css('overflow', 'hidden');
                } else {
                    pane.css('overflow', '');
                }
                that.resize(true);
            },
            collapse: function (pane) {
                this.toggle(pane, false);
            },
            expand: function (pane) {
                this.toggle(pane, true);
            },
            _addPane: function (config, idx, paneElement) {
                var that = this;
                if (paneElement.length) {
                    that.options.panes.splice(idx, 0, config);
                    that._initPane(paneElement, config);
                    that._removeSplitBars();
                    that.resize(true);
                }
                return paneElement;
            },
            append: function (config) {
                config = config || {};
                var that = this, paneElement = $('<div />').appendTo(that.element);
                return that._addPane(config, that.options.panes.length, paneElement);
            },
            insertBefore: function (config, referencePane) {
                referencePane = $(referencePane);
                config = config || {};
                var that = this, idx = that.wrapper.children('.k-pane').index(referencePane), paneElement = $('<div />').insertBefore($(referencePane));
                return that._addPane(config, idx, paneElement);
            },
            insertAfter: function (config, referencePane) {
                referencePane = $(referencePane);
                config = config || {};
                var that = this, idx = that.wrapper.children('.k-pane').index(referencePane), paneElement = $('<div />').insertAfter($(referencePane));
                return that._addPane(config, idx + 1, paneElement);
            },
            remove: function (pane) {
                var that = this;
                pane = that.wrapper.find(pane);
                if (pane.length) {
                    kendo.destroy(pane);
                    pane.each(function (idx, element) {
                        that.options.panes.splice(that.wrapper.children('.k-pane').index(element), 1);
                        $(element).remove();
                    });
                    that._removeSplitBars();
                    if (that.options.panes.length) {
                        that.resize(true);
                    }
                }
                return that;
            },
            size: panePropertyAccessor('size', true),
            min: panePropertyAccessor('min'),
            max: panePropertyAccessor('max')
        });
        ui.plugin(Splitter);
        var verticalDefaults = {
            sizingProperty: 'height',
            sizingDomProperty: 'offsetHeight',
            alternateSizingProperty: 'width',
            positioningProperty: 'top',
            mousePositioningProperty: 'pageY'
        };
        var horizontalDefaults = {
            sizingProperty: 'width',
            sizingDomProperty: 'offsetWidth',
            alternateSizingProperty: 'height',
            positioningProperty: 'left',
            mousePositioningProperty: 'pageX'
        };
        function PaneResizing(splitter) {
            var that = this, orientation = splitter.orientation;
            that.owner = splitter;
            that._element = splitter.element;
            that.orientation = orientation;
            extend(that, orientation === HORIZONTAL ? horizontalDefaults : verticalDefaults);
            that._resizable = new kendo.ui.Resizable(splitter.element, {
                orientation: orientation,
                handle: '.k-splitbar-draggable-' + orientation + '[data-marker=' + splitter._marker + ']',
                hint: proxy(that._createHint, that),
                start: proxy(that._start, that),
                max: proxy(that._max, that),
                min: proxy(that._min, that),
                invalidClass: 'k-restricted-size-' + orientation,
                resizeend: proxy(that._stop, that)
            });
        }
        PaneResizing.prototype = {
            press: function (target) {
                this._resizable.press(target);
            },
            move: function (delta, target) {
                if (!this.pressed) {
                    this.press(target);
                    this.pressed = true;
                }
                if (!this._resizable.target) {
                    this._resizable.press(target);
                }
                this._resizable.move(delta);
            },
            end: function () {
                this._resizable.end();
                this.pressed = false;
            },
            destroy: function () {
                this._resizable.destroy();
                this._resizable = this._element = this.owner = null;
            },
            isResizing: function () {
                return this._resizable.resizing;
            },
            _createHint: function (handle) {
                var that = this;
                return $('<div class=\'k-ghost-splitbar k-ghost-splitbar-' + that.orientation + ' k-state-default\' />').css(that.alternateSizingProperty, handle[that.alternateSizingProperty]());
            },
            _start: function (e) {
                var that = this, splitbar = $(e.currentTarget), previousPane = splitbar.prev(), nextPane = splitbar.next(), previousPaneConfig = previousPane.data(PANE), nextPaneConfig = nextPane.data(PANE), prevBoundary = parseInt(previousPane[0].style[that.positioningProperty], 10), nextBoundary = parseInt(nextPane[0].style[that.positioningProperty], 10) + nextPane[0][that.sizingDomProperty] - splitbar[0][that.sizingDomProperty], totalSize = parseInt(that._element.css(that.sizingProperty), 10), toPx = function (value) {
                        var val = parseInt(value, 10);
                        return (isPixelSize(value) ? val : totalSize * val / 100) || 0;
                    }, prevMinSize = toPx(previousPaneConfig.min), prevMaxSize = toPx(previousPaneConfig.max) || nextBoundary - prevBoundary, nextMinSize = toPx(nextPaneConfig.min), nextMaxSize = toPx(nextPaneConfig.max) || nextBoundary - prevBoundary;
                that.previousPane = previousPane;
                that.nextPane = nextPane;
                that._maxPosition = Math.min(nextBoundary - nextMinSize, prevBoundary + prevMaxSize);
                that._minPosition = Math.max(prevBoundary + prevMinSize, nextBoundary - nextMaxSize);
            },
            _max: function () {
                return this._maxPosition;
            },
            _min: function () {
                return this._minPosition;
            },
            _stop: function (e) {
                var that = this, splitbar = $(e.currentTarget), owner = that.owner;
                owner._panes().children('.k-splitter-overlay').remove();
                if (e.keyCode !== kendo.keys.ESC) {
                    var ghostPosition = e.position, previousPane = splitbar.prev(), nextPane = splitbar.next(), previousPaneConfig = previousPane.data(PANE), nextPaneConfig = nextPane.data(PANE), previousPaneNewSize = ghostPosition - parseInt(previousPane[0].style[that.positioningProperty], 10), nextPaneNewSize = parseInt(nextPane[0].style[that.positioningProperty], 10) + nextPane[0][that.sizingDomProperty] - ghostPosition - splitbar[0][that.sizingDomProperty], fluidPanesCount = that._element.children(PANECLASS).filter(function () {
                            return isFluid($(this).data(PANE).size);
                        }).length;
                    if (!isFluid(previousPaneConfig.size) || fluidPanesCount > 1) {
                        if (isFluid(previousPaneConfig.size)) {
                            fluidPanesCount--;
                        }
                        previousPaneConfig.size = previousPaneNewSize + 'px';
                    }
                    if (!isFluid(nextPaneConfig.size) || fluidPanesCount > 1) {
                        nextPaneConfig.size = nextPaneNewSize + 'px';
                    }
                    owner.resize(true);
                }
                return false;
            }
        };
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dialog', [
        'kendo.core',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dialog',
        name: 'Dialog',
        category: 'web',
        description: 'The dialog widget is a modal popup that brings information to the user.',
        depends: [
            'core',
            'popup'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, TabKeyTrap = kendo.ui.Popup.TabKeyTrap, proxy = $.proxy, template = kendo.template, keys = kendo.keys, isFunction = $.isFunction, NS = 'kendoWindow', KDIALOG = '.k-dialog', KWINDOW = '.k-window', KICONCLOSE = '.k-dialog-close', KCONTENTCLASS = 'k-content k-window-content k-dialog-content', KCONTENTSELECTOR = '.k-window-content', KCONTENT = '.k-content', KSCROLL = 'k-scroll', KTITLELESS = 'k-dialog-titleless', KDIALOGTITLE = '.k-dialog-title', KDIALOGTITLEBAR = KDIALOGTITLE + 'bar', KBUTTONGROUP = '.k-dialog-buttongroup', KBUTTON = '.k-button', KALERT = 'k-alert', KCONFIRM = 'k-confirm', KPROMPT = 'k-prompt', KTEXTBOX = '.k-textbox', KOVERLAY = '.k-overlay', VISIBLE = ':visible', ZINDEX = 'zIndex', BODY = 'body', INITOPEN = 'initOpen', TOUCHSTART = 'touchstart', TOUCHMOVE = 'touchmove', OPEN = 'open', CLOSE = 'close', SHOW = 'show', HIDE = 'hide', WIDTH = 'width', SIZE = {
                small: 'k-window-sm',
                medium: 'k-window-md',
                large: 'k-window-lg'
            }, HIDDEN = 'hidden', OVERFLOW = 'overflow', DATADOCOVERFLOWRULE = 'original-overflow-rule', DATAHTMLTAPYRULE = 'tap-y', HUNDREDPERCENT = 100, CSSFLEXBOX = kendo.support.cssFlexbox, messages = {
                okText: 'OK',
                cancel: 'Cancel',
                promptInput: 'Input'
            }, ceil = Math.ceil, templates, overlaySelector = ':not(link,meta,script,style)';
        function defined(x) {
            return typeof x != 'undefined';
        }
        function constrain(value, low, high) {
            return Math.max(Math.min(parseInt(value, 10), high === Infinity ? high : parseInt(high, 10)), parseInt(low, 10));
        }
        function buttonKeyTrigger(e) {
            return e.keyCode == keys.ENTER || e.keyCode == keys.SPACEBAR;
        }
        var DialogBase = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that._init(that.element, that.options);
                kendo.notify(that);
            },
            _init: function (element, options) {
                var that = this, wrapper;
                that._centerCallback = proxy(that._center, that);
                that.appendTo = $(BODY);
                if (!defined(options.visible) || options.visible === null) {
                    options.visible = element.is(VISIBLE);
                }
                if (that.wrapperTemplate === undefined) {
                    that.wrapperTemplate = templates.wrapper;
                }
                that._createDialog();
                wrapper = that.wrapper = element.closest(KDIALOG);
                if (options._defaultFocus === undefined) {
                    that._defaultFocus = element[0];
                }
                that._tabindex(element);
                that._dimensions();
                this._tabKeyTrap = new TabKeyTrap(wrapper);
                if (!that.options.visible) {
                    that.wrapper.hide();
                } else {
                    that._triggerOpen();
                }
            },
            setOptions: function (options) {
                var that = this;
                var sizeClass = that.options.size;
                options = $.extend(that.options, options);
                Widget.fn.setOptions.call(that, options);
                if (options.title !== undefined) {
                    that.title(options.title);
                }
                if (options.content) {
                    kendo.destroy(that.element.children());
                    that.element.html(options.content);
                }
                if (options.actions) {
                    that.wrapper.children(KBUTTONGROUP).remove();
                    that._createActionbar(that.wrapper);
                }
                that.wrapper.show();
                that._closable(that.wrapper);
                that.wrapper.removeClass(SIZE[sizeClass]);
                that._dimensions();
                if (!options.visible) {
                    that.wrapper.hide();
                } else {
                    that._triggerOpen();
                }
                if (typeof options.modal !== 'undefined') {
                    var visible = that.options.visible !== false;
                    that._enableDocumentScrolling();
                    that._overlay(options.modal && visible);
                }
            },
            _dimensions: function () {
                var that = this, wrapper = that.wrapper, options = that.options, width = options.width, height = options.height, sizeClass = options.size, dimensions = [
                        'minWidth',
                        'minHeight',
                        'maxWidth',
                        'maxHeight'
                    ];
                for (var i = 0; i < dimensions.length; i++) {
                    var value = options[dimensions[i]];
                    if (value && value != Infinity) {
                        wrapper.css(dimensions[i], value);
                    }
                }
                this._setElementMaxHeight();
                if (width) {
                    if (width.toString().indexOf('%') > 0) {
                        wrapper.width(width);
                    } else {
                        wrapper.outerWidth(constrain(width, options.minWidth, options.maxWidth));
                    }
                }
                if (height) {
                    if (height.toString().indexOf('%') > 0) {
                        wrapper.height(height);
                    } else {
                        wrapper.outerHeight(constrain(height, options.minHeight, options.maxHeight));
                    }
                    this._setElementHeight();
                }
                if (sizeClass && SIZE[sizeClass]) {
                    wrapper.addClass(SIZE[sizeClass]);
                }
            },
            _setElementMaxHeight: function () {
                var that = this, element = that.element, maxHeight = that.options.maxHeight, paddingBox, elementMaxHeight;
                if (maxHeight != Infinity) {
                    paddingBox = that._paddingBox(element);
                    elementMaxHeight = parseFloat(maxHeight, 10) - that._uiHeight() - paddingBox.vertical;
                    if (elementMaxHeight > 0) {
                        element.css({ maxHeight: ceil(elementMaxHeight) + 'px' });
                    }
                }
            },
            _paddingBox: function (element) {
                var paddingTop = parseFloat(element.css('padding-top'), 10), paddingLeft = parseFloat(element.css('padding-left'), 10), paddingBottom = parseFloat(element.css('padding-bottom'), 10), paddingRight = parseFloat(element.css('padding-right'), 10);
                return {
                    vertical: paddingTop + paddingBottom,
                    horizontal: paddingLeft + paddingRight
                };
            },
            _setElementHeight: function () {
                var that = this, element = that.element, height = that.options.height, paddingBox = that._paddingBox(element), elementHeight = parseFloat(height, 10) - that._uiHeight() - paddingBox.vertical;
                if (elementHeight < 0) {
                    elementHeight = 0;
                }
                element.css({ height: ceil(elementHeight) + 'px' });
                this._applyScrollClassName(element);
            },
            _applyScrollClassName: function (element) {
                var hasScroll = element.get(0).scrollHeight > element.outerHeight();
                if (hasScroll) {
                    element.addClass(KSCROLL);
                } else {
                    element.removeClass(KSCROLL);
                }
            },
            _uiHeight: function () {
                var that = this, wrapper = that.wrapper, actionbar = wrapper.children(KBUTTONGROUP), actionbarHeight = actionbar[0] && actionbar[0].offsetHeight || 0, titlebar = wrapper.children(KDIALOGTITLEBAR), titlebarHeight = titlebar[0] && titlebar[0].offsetHeight || 0;
                return actionbarHeight + titlebarHeight;
            },
            _overlay: function (visible) {
                var overlay = this.appendTo.children(KOVERLAY), wrapper = this.wrapper;
                if (!overlay.length) {
                    overlay = $(templates.overlay);
                }
                overlay.insertBefore(wrapper[0]).toggle(visible).css(ZINDEX, parseInt(wrapper.css(ZINDEX), 10) - 1);
                if (visible) {
                    this._waiAriaOverlay();
                } else {
                    this._removeWaiAriaOverlay();
                }
                if (this.options.modal.preventScroll) {
                    this._stopDocumentScrolling();
                }
                return overlay;
            },
            _waiAriaOverlay: function () {
                var node = this.wrapper;
                this._overlayedNodes = node.prevAll(overlaySelector).add(node.nextAll(overlaySelector)).each(function () {
                    var jthis = $(this);
                    jthis.data('ariaHidden', jthis.attr('aria-hidden'));
                    jthis.attr('aria-hidden', 'true');
                });
            },
            _removeWaiAriaOverlay: function () {
                return this._overlayedNodes && this._overlayedNodes.each(function () {
                    var node = $(this);
                    var hiddenValue = node.data('ariaHidden');
                    if (hiddenValue) {
                        node.attr('aria-hidden', hiddenValue);
                    } else {
                        node.removeAttr('aria-hidden');
                    }
                });
            },
            _closeClick: function (e) {
                e.preventDefault();
                this.close(false);
            },
            _closeKeyHandler: function (e) {
                if (buttonKeyTrigger(e) || e.keyCode == keys.ESC) {
                    this.close(false);
                }
            },
            _keydown: function (e) {
                var that = this, options = that.options, keyCode = e.keyCode;
                if (keyCode == keys.ESC && !that._closing && options.closable) {
                    that.close(false);
                }
            },
            _createDialog: function () {
                var that = this, content = that.element, options = that.options, isRtl = kendo.support.isRtl(content), titlebar = $(templates.titlebar(options)), titleId = (content.id || kendo.guid()) + '_title', wrapper = $(that.wrapperTemplate(options));
                wrapper.toggleClass('k-rtl', isRtl);
                content.addClass(KCONTENTCLASS);
                that.appendTo.append(wrapper);
                if (options.title !== false) {
                    wrapper.append(titlebar);
                    titlebar.attr('id', titleId);
                    wrapper.attr('aria-labelledby', titleId);
                } else {
                    wrapper.addClass(KTITLELESS);
                }
                that._closable(wrapper);
                wrapper.append(content);
                if (options.content) {
                    kendo.destroy(content.children());
                    content.html(options.content);
                }
                if (options.actions.length) {
                    that._createActionbar(wrapper);
                }
            },
            _closable: function (wrapper) {
                var that = this;
                var options = that.options;
                var titlebar = wrapper.children(KDIALOGTITLEBAR);
                var titlebarActions = titlebar.find('.k-window-actions');
                var closeAction = titlebarActions.length ? titlebarActions.find('.k-dialog-close') : wrapper.find('.k-dialog-close');
                closeAction.remove();
                if (options.closable !== false) {
                    if (options.title !== false && titlebarActions.length) {
                        titlebarActions.append(templates.close(options));
                    } else {
                        wrapper.prepend(templates.close(options));
                    }
                    wrapper.autoApplyNS(NS);
                    that.element.autoApplyNS(NS);
                    wrapper.find(KICONCLOSE).on('click', proxy(that._closeClick, that)).on('keydown', proxy(that._closeKeyHandler, that));
                    that.element.on('keydown', proxy(that._keydown, that));
                }
            },
            _createActionbar: function (wrapper) {
                var isStretchedLayout = this.options.buttonLayout === 'stretched';
                var buttonLayout = isStretchedLayout ? 'stretched' : 'normal';
                var actionbar = $(templates.actionbar({ buttonLayout: buttonLayout }));
                this._addButtons(actionbar);
                if (isStretchedLayout && !CSSFLEXBOX) {
                    this._normalizeButtonSize(actionbar);
                }
                wrapper.append(actionbar);
            },
            _addButtons: function (actionbar) {
                var that = this, o = that.options, actionClick = proxy(that._actionClick, that), actionKeyHandler = proxy(that._actionKeyHandler, that), actions = that.options.actions, length = actions.length, buttonSize = Math.round(HUNDREDPERCENT / length), action, text;
                for (var i = 0; i < length; i++) {
                    action = actions[i];
                    text = that._mergeTextWithOptions(action);
                    var btn = $(templates.action(action)).autoApplyNS(NS).html(text).appendTo(actionbar).data('action', action.action).on('click', actionClick).on('keydown', actionKeyHandler);
                    if (o.buttonLayout === 'stretched' && !CSSFLEXBOX) {
                        if (i == length - 1) {
                            buttonSize = HUNDREDPERCENT - i * buttonSize;
                        }
                        btn.css(WIDTH, buttonSize + '%');
                    }
                }
            },
            _mergeTextWithOptions: function (action) {
                var text = action.text;
                return text ? template(text)(this.options) : '';
            },
            _normalizeButtonSize: function (actionbar) {
                var that = this, options = that.options, lastButton = actionbar.children(KBUTTON + ':last'), currentSize = parseFloat(lastButton[0] ? lastButton[0].style[WIDTH] : 0), difference = HUNDREDPERCENT - options.actions.length * currentSize;
                if (difference > 0) {
                    lastButton.css(WIDTH, currentSize + difference + '%');
                }
            },
            _tabindex: function (target) {
                var that = this;
                var wrapper = that.wrapper;
                var closeBtn = wrapper.find(KICONCLOSE);
                var actionButtons = wrapper.find(KBUTTONGROUP + ' ' + KBUTTON);
                Widget.fn._tabindex.call(this, target);
                var tabIndex = target.attr('tabindex');
                closeBtn.attr('tabIndex', tabIndex);
                actionButtons.attr('tabIndex', tabIndex);
            },
            _actionClick: function (e) {
                if (this.wrapper.is(VISIBLE)) {
                    this._runActionBtn(e.currentTarget);
                }
            },
            _actionKeyHandler: function (e) {
                if (buttonKeyTrigger(e)) {
                    this._runActionBtn(e.currentTarget);
                } else if (e.keyCode == keys.ESC) {
                    this.close(false);
                }
            },
            _runActionBtn: function (target) {
                var that = this;
                if (that._closing) {
                    return;
                }
                var action = $(target).data('action'), preventClose = isFunction(action) && action({ sender: that }) === false;
                if (!preventClose) {
                    that.close(false);
                }
            },
            _triggerOpen: function () {
                var that = this;
                var options = that.options;
                var wrapper = that.wrapper;
                that.toFront();
                that._triggerInitOpen();
                that.trigger(OPEN);
                if (options.modal) {
                    that._overlay(wrapper.is(VISIBLE)).css({ opacity: 0.5 });
                    that._focusDialog();
                }
            },
            open: function () {
                var that = this, wrapper = that.wrapper, showOptions = this._animationOptions(OPEN), options = that.options, overlay, otherModalsVisible;
                this._triggerInitOpen();
                if (!that.trigger(OPEN)) {
                    if (that._closing) {
                        wrapper.kendoStop(true, true);
                    }
                    that._closing = false;
                    that.toFront();
                    options.visible = true;
                    if (options.modal) {
                        otherModalsVisible = !!that._modals().length;
                        overlay = that._overlay(otherModalsVisible);
                        overlay.kendoStop(true, true);
                        if (showOptions.duration && kendo.effects.Fade && !otherModalsVisible) {
                            var overlayFx = kendo.fx(overlay).fadeIn();
                            overlayFx.duration(showOptions.duration || 0);
                            overlayFx.endValue(0.5);
                            overlayFx.play();
                        } else {
                            overlay.css('opacity', 0.5);
                        }
                        overlay.show();
                    }
                    wrapper.show().kendoStop().kendoAnimate({
                        effects: showOptions.effects,
                        duration: showOptions.duration,
                        complete: proxy(that._openAnimationEnd, that)
                    });
                    wrapper.show();
                }
                return that;
            },
            _animationOptions: function (id) {
                var animation = this.options.animation;
                var basicAnimation = {
                    open: { effects: {} },
                    close: {
                        hide: true,
                        effects: {}
                    }
                };
                return animation && animation[id] || basicAnimation[id];
            },
            _openAnimationEnd: function () {
                if (this.options.modal) {
                    this._focusDialog();
                }
                this.trigger(SHOW);
            },
            _triggerInitOpen: function () {
                if (!defined(this._initOpenTriggered)) {
                    this._initOpenTriggered = true;
                    this.trigger(INITOPEN);
                }
            },
            toFront: function () {
                var that = this, wrapper = that.wrapper, zIndex = +wrapper.css(ZINDEX), originalZIndex = zIndex;
                that.center();
                $(KWINDOW).each(function (i, element) {
                    var windowObject = $(element), zIndexNew = windowObject.css(ZINDEX);
                    if (!isNaN(zIndexNew)) {
                        zIndex = Math.max(+zIndexNew, zIndex);
                    }
                });
                if (!wrapper[0].style.zIndex || originalZIndex < zIndex) {
                    wrapper.css(ZINDEX, zIndex + 2);
                }
                that.element.find('> .k-overlay').remove();
                wrapper = null;
                return that;
            },
            close: function (systemTriggered) {
                if (!arguments.length) {
                    systemTriggered = true;
                }
                this._close(systemTriggered);
                this._stopCenterOnResize();
                return this;
            },
            _close: function (systemTriggered) {
                var that = this, wrapper = that.wrapper, options = that.options, showOptions = this._animationOptions('open'), hideOptions = this._animationOptions('close');
                if (wrapper.is(VISIBLE) && !that.trigger(CLOSE, { userTriggered: !systemTriggered })) {
                    if (that._closing) {
                        return;
                    }
                    that._closing = true;
                    options.visible = false;
                    this._removeOverlay();
                    wrapper.kendoStop().kendoAnimate({
                        effects: hideOptions.effects || showOptions.effects,
                        reverse: hideOptions.reverse === true,
                        duration: hideOptions.duration,
                        complete: proxy(this._closeAnimationEnd, this)
                    });
                }
                return that;
            },
            center: function () {
                this._center();
                this._centerOnResize();
            },
            _center: function () {
                var that = this, wrapper = that.wrapper, documentWindow = $(window), scrollTop = 0, scrollLeft = 0, newLeft = scrollLeft + Math.max(0, (documentWindow.width() - wrapper.width()) / 2), newTop = scrollTop + Math.max(0, (documentWindow.height() - wrapper.height() - parseInt(wrapper.css('paddingTop'), 10)) / 2);
                wrapper.css({
                    left: newLeft,
                    top: newTop
                });
                return that;
            },
            _centerOnResize: function () {
                if (this._trackResize) {
                    return;
                }
                kendo.onResize(this._centerCallback);
                this._trackResize = true;
            },
            _stopCenterOnResize: function () {
                kendo.unbindResize(this._centerCallback);
                this._trackResize = false;
            },
            _removeOverlay: function () {
                var modals = this._modals();
                var options = this.options;
                var hideOverlay = options.modal && !modals.length;
                if (hideOverlay) {
                    this._overlay(false).remove();
                    if (options.modal.preventScroll) {
                        this._enableDocumentScrolling();
                    }
                } else if (modals.length) {
                    this._object(modals.last())._overlay(true);
                    if (options.modal.preventScroll) {
                        this._stopDocumentScrolling();
                    }
                }
            },
            _stopDocumentScrolling: function () {
                var that = this;
                var $body = $('body');
                that._storeOverflowRule($body);
                $body.css(OVERFLOW, HIDDEN);
                var $html = $('html');
                var html = $html[0];
                that._storeOverflowRule($html);
                $html.css(OVERFLOW, HIDDEN);
                if (kendo.support.mobileOS.ios) {
                    html.addEventListener(TOUCHSTART, that._touchStart, { passive: false });
                    html.addEventListener(TOUCHMOVE, that._touchMove, { passive: false });
                }
            },
            _touchStart: function (e) {
                $(this).data(DATAHTMLTAPYRULE, e.changedTouches[0].pageY);
            },
            _touchMove: function (e) {
                var target = e.target;
                var $target = $(e.target);
                var upScroll = e.changedTouches[0].pageY - $(this).data(DATAHTMLTAPYRULE) > 0;
                var preventYScroll = $target.is(KCONTENTSELECTOR) && (upScroll && $target.scrollTop() === 0) || !upScroll && $target.scrollTop() === target.scrollHeight - target.clientHeight;
                if (!$target.is(KCONTENTSELECTOR) || preventYScroll) {
                    e.preventDefault();
                }
            },
            _enableDocumentScrolling: function () {
                var that = this;
                var $body = $(document.body);
                var $html = $('html');
                var html = $html[0];
                that._restoreOverflowRule($body);
                that._restoreOverflowRule($html);
                if (kendo.support.mobileOS.ios) {
                    $html.removeData(DATAHTMLTAPYRULE);
                    html.removeEventListener(TOUCHSTART, that._touchStart, { passive: false });
                    html.removeEventListener(TOUCHMOVE, that._touchMove, { passive: false });
                }
            },
            _storeOverflowRule: function ($element) {
                if (this._isOverflowStored($element)) {
                    return;
                }
                var overflowRule = $element.get(0).style.overflow;
                if (typeof overflowRule === 'string') {
                    $element.data(DATADOCOVERFLOWRULE, overflowRule);
                }
            },
            _isOverflowStored: function ($element) {
                return typeof $element.data(DATADOCOVERFLOWRULE) === 'string';
            },
            _restoreOverflowRule: function ($element) {
                var overflowRule = $element.data(DATADOCOVERFLOWRULE);
                if (overflowRule !== null && overflowRule !== undefined) {
                    $element.css(OVERFLOW, overflowRule);
                    $element.removeData(DATADOCOVERFLOWRULE);
                } else {
                    $element.css(OVERFLOW, '');
                }
            },
            _closeAnimationEnd: function () {
                var that = this;
                that._closing = false;
                that.wrapper.hide().css('opacity', '');
                that.trigger(HIDE);
                if (that.options.modal) {
                    var lastModal = that._object(that._modals().last());
                    if (lastModal) {
                        lastModal.toFront();
                    }
                }
            },
            _modals: function () {
                var that = this;
                var zStack = $(KWINDOW).filter(function () {
                    var dom = $(this);
                    var object = that._object(dom);
                    var options = object && object.options;
                    return options && options.modal && that.options.appendTo == options.appendTo && options.visible && dom.is(VISIBLE);
                }).sort(function (a, b) {
                    return +$(a).css('zIndex') - +$(b).css('zIndex');
                });
                that = null;
                return zStack;
            },
            _object: function (element) {
                var content = element.children(KCONTENT);
                var widget = kendo.widgetInstance(content);
                if (widget) {
                    return widget;
                }
                return undefined;
            },
            destroy: function () {
                var that = this;
                that._destroy();
                Widget.fn.destroy.call(that);
                that.wrapper.remove();
                that.wrapper = that.element = $();
            },
            _destroy: function () {
                var that = this;
                var ns = '.' + NS;
                that.wrapper.off(ns);
                that.element.off(ns);
                that.wrapper.find(KICONCLOSE + ',' + KBUTTONGROUP + ' > ' + KBUTTON).off(ns);
                that._stopCenterOnResize();
            },
            title: function (html) {
                var that = this, wrapper = that.wrapper, options = that.options, titlebar = wrapper.children(KDIALOGTITLEBAR), title = titlebar.children(KDIALOGTITLE), encodedHtml = kendo.htmlEncode(html);
                if (!arguments.length) {
                    return title.html();
                }
                if (html === false) {
                    titlebar.remove();
                    wrapper.addClass(KTITLELESS);
                } else {
                    if (!titlebar.length) {
                        titlebar = $(templates.titlebar(options)).prependTo(wrapper);
                        title = titlebar.children(KDIALOGTITLE);
                        wrapper.removeClass(KTITLELESS);
                    }
                    title.html(encodedHtml);
                }
                that.options.title = encodedHtml;
                return that;
            },
            content: function (html, data) {
                var that = this, content = that.wrapper.children(KCONTENT);
                if (!defined(html)) {
                    return content.html();
                }
                this.angular('cleanup', function () {
                    return { elements: content.children() };
                });
                kendo.destroy(content.children());
                content.html(html);
                this.angular('compile', function () {
                    var a = [];
                    for (var i = content.length; --i >= 0;) {
                        a.push({ dataItem: data });
                    }
                    return {
                        elements: content.children(),
                        data: a
                    };
                });
                that.options.content = html;
                return that;
            },
            _focusDialog: function () {
                if (this._defaultFocus) {
                    this._focus(this._defaultFocus);
                }
                this._tabKeyTrap.trap();
            },
            _focus: function (node) {
                if (node) {
                    node.focus();
                }
            },
            events: [
                INITOPEN,
                OPEN,
                CLOSE,
                SHOW,
                HIDE
            ],
            options: {
                title: '',
                buttonLayout: 'stretched',
                actions: [],
                modal: true,
                size: 'auto',
                width: null,
                height: null,
                minWidth: 0,
                minHeight: 0,
                maxWidth: Infinity,
                maxHeight: Infinity,
                content: null,
                visible: null,
                appendTo: BODY,
                closable: true
            }
        });
        var Dialog = DialogBase.extend({
            options: {
                name: 'Dialog',
                messages: { close: 'Close' }
            }
        });
        kendo.ui.plugin(Dialog);
        var PopupBox = DialogBase.extend({
            _init: function (element, options) {
                var that = this;
                that.wrapperTemplate = templates.alertWrapper;
                options._defaultFocus = null;
                that._ensureContentId(element);
                DialogBase.fn._init.call(that, element, options);
                that.bind(HIDE, proxy(that.destroy, that));
                that._ariaDescribedBy();
                that._initFocus();
            },
            _ensureContentId: function (element) {
                var node = $(element);
                if (!node.attr('id')) {
                    node.attr('id', kendo.guid() + '_k-popup');
                }
            },
            _ariaDescribedBy: function () {
                this.wrapper.attr('aria-describedby', this.element.attr('id'));
            },
            _initFocus: function () {
                var o = this.options;
                this._defaultFocus = this._chooseEntryFocus();
                if (this._defaultFocus && o.visible && o.modal) {
                    this._focusDialog();
                }
            },
            _chooseEntryFocus: function () {
                return this.wrapper.find(KBUTTONGROUP + ' > ' + KBUTTON)[0];
            },
            options: {
                title: window.location.host,
                closable: false,
                messages: messages
            }
        });
        var Alert = PopupBox.extend({
            _init: function (element, options) {
                var that = this;
                PopupBox.fn._init.call(that, element, options);
                that.wrapper.addClass(KALERT);
            },
            options: {
                name: 'Alert',
                modal: true,
                actions: [{ text: '#: messages.okText #' }]
            }
        });
        kendo.ui.plugin(Alert);
        var kendoAlert = function (text) {
            return $(templates.alert).kendoAlert({ content: text }).data('kendoAlert').open();
        };
        var Confirm = PopupBox.extend({
            _init: function (element, options) {
                var that = this;
                PopupBox.fn._init.call(that, element, options);
                that.wrapper.addClass(KCONFIRM);
                that.result = $.Deferred();
            },
            options: {
                name: 'Confirm',
                modal: true,
                actions: [
                    {
                        text: '#: messages.okText #',
                        primary: true,
                        action: function (e) {
                            e.sender.result.resolve();
                        }
                    },
                    {
                        text: '#: messages.cancel #',
                        action: function (e) {
                            e.sender.result.reject();
                        }
                    }
                ]
            }
        });
        kendo.ui.plugin(Confirm);
        var kendoConfirm = function (text) {
            var confirmDialog = $(templates.confirm).kendoConfirm({ content: text }).data('kendoConfirm').open();
            return confirmDialog.result;
        };
        var Prompt = PopupBox.extend({
            _init: function (element, options) {
                var that = this;
                PopupBox.fn._init.call(that, element, options);
                that.wrapper.addClass(KPROMPT);
                that._createPrompt();
                that.result = $.Deferred();
            },
            _createPrompt: function () {
                var value = this.options.value, promptContainer = $(templates.promptInputContainer(this.options)).insertAfter(this.element);
                if (value) {
                    promptContainer.children(KTEXTBOX).val(value);
                }
                this._defaultFocus = this._chooseEntryFocus();
                this._focusDialog();
            },
            _chooseEntryFocus: function () {
                return this.wrapper.find(KTEXTBOX)[0];
            },
            options: {
                name: 'Prompt',
                modal: true,
                value: '',
                actions: [
                    {
                        text: '#: messages.okText #',
                        primary: true,
                        action: function (e) {
                            var sender = e.sender, value = sender.wrapper.find(KTEXTBOX).val();
                            sender.result.resolve(value);
                        }
                    },
                    {
                        text: '#: messages.cancel #',
                        action: function (e) {
                            var sender = e.sender, value = sender.wrapper.find(KTEXTBOX).val();
                            e.sender.result.reject(value);
                        }
                    }
                ]
            }
        });
        kendo.ui.plugin(Prompt);
        var kendoPrompt = function (text, value) {
            var promptDialog = $(templates.prompt).kendoPrompt({
                content: text,
                value: value
            }).data('kendoPrompt').open();
            return promptDialog.result;
        };
        templates = {
            wrapper: template('<div class=\'k-widget k-window k-dialog\' role=\'dialog\' />'),
            action: template('<button type=\'button\' class=\'k-button# if (data.primary) { # k-primary# } role=\'button\' #\'></button>'),
            titlebar: template('<div class=\'k-window-titlebar k-dialog-titlebar k-header\'>' + '<span class=\'k-window-title k-dialog-title\'>#: title #</span>' + '<div class=\'k-window-actions k-dialog-actions\' />' + '</div>'),
            close: template('<a role=\'button\' href=\'\\#\' class=\'k-button k-bare k-button-icon k-window-action k-dialog-action k-dialog-close\' title=\'#: messages.close #\' aria-label=\'#: messages.close #\' tabindex=\'-1\'><span class=\'k-icon k-i-close\'></span></a>'),
            actionbar: template('<div class=\'k-dialog-buttongroup k-dialog-button-layout-#: buttonLayout #\' role=\'toolbar\' />'),
            overlay: '<div class=\'k-overlay\' />',
            alertWrapper: template('<div class=\'k-widget k-window k-dialog\' role=\'alertdialog\' />'),
            alert: '<div />',
            confirm: '<div />',
            prompt: '<div />',
            promptInputContainer: template('<div class=\'k-prompt-container\'><input type=\'text\' class=\'k-textbox\' title=\'#: messages.promptInput #\' aria-label=\'#: messages.promptInput #\' /></div>')
        };
        kendo.alert = kendoAlert;
        kendo.confirm = kendoConfirm;
        kendo.prompt = kendoPrompt;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.view', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.view',
        name: 'Scheduler View',
        category: 'web',
        description: 'The Scheduler Common View',
        depends: ['core'],
        hidden: true
    };
    kendo.ui.scheduler = {};
    (function ($) {
        var kendo = window.kendo, ui = kendo.ui, getDate = kendo.date.getDate, Widget = ui.Widget, outerHeight = kendo._outerHeight, keys = kendo.keys, NS = '.kendoSchedulerView', INVERSE_COLOR_CLASS = 'k-event-inverse', MIN_HORIZONTAL_SCROLL_SIZE = 1024, math = Math;
        function levels(values, key) {
            var result = [];
            function collect(depth, values) {
                values = values[key];
                if (values) {
                    var level = result[depth] = result[depth] || [];
                    for (var idx = 0; idx < values.length; idx++) {
                        level.push(values[idx]);
                        collect(depth + 1, values[idx]);
                    }
                }
            }
            collect(0, values);
            return result;
        }
        function cellspacing() {
            if (kendo.support.cssBorderSpacing) {
                return '';
            }
            return 'cellspacing="0"';
        }
        function table(tableRows, className) {
            if (!tableRows.length) {
                return '';
            }
            return '<table ' + cellspacing() + ' class="' + $.trim('k-scheduler-table ' + (className || '')) + '">' + '<tr>' + tableRows.join('</tr><tr>') + '</tr>' + '</table>';
        }
        function allDayTable(tableRows, className) {
            if (!tableRows.length) {
                return '';
            }
            return '<div style=\'position:relative\'>' + table(tableRows, className) + '</div>';
        }
        function timesHeader(columnLevelCount, allDaySlot, rowCount) {
            var tableRows = [];
            if (rowCount > 0) {
                for (var idx = 0; idx < columnLevelCount; idx++) {
                    tableRows.push('<th>&#8203;</th>');
                }
            }
            if (allDaySlot) {
                tableRows.push('<th class="k-scheduler-times-all-day">' + allDaySlot.text + '</th>');
            }
            if (rowCount < 1) {
                return $();
            }
            return $('<div class="k-scheduler-times">' + table(tableRows) + '</div>');
        }
        function datesHeader(columnLevels, columnCount, allDaySlot) {
            var dateTableRows = [];
            var columnIndex;
            for (var columnLevelIndex = 0; columnLevelIndex < columnLevels.length; columnLevelIndex++) {
                var level = columnLevels[columnLevelIndex];
                var th = [];
                var colspan = columnCount / level.length;
                for (columnIndex = 0; columnIndex < level.length; columnIndex++) {
                    var column = level[columnIndex];
                    th.push('<th colspan="' + (column.colspan || colspan) + '" class="' + (column.className || '') + '">' + column.text + '</th>');
                }
                dateTableRows.push(th.join(''));
            }
            var allDayTableRows = [];
            if (allDaySlot) {
                var lastLevel = columnLevels[columnLevels.length - 1];
                var td = [];
                var cellContent = allDaySlot.cellContent;
                for (columnIndex = 0; columnIndex < lastLevel.length; columnIndex++) {
                    td.push('<td class="' + (lastLevel[columnIndex].className || '') + '">' + (cellContent ? cellContent(columnIndex) : '&nbsp;') + '</td>');
                }
                allDayTableRows.push(td.join(''));
            }
            return $('<div class="k-scheduler-header k-state-default">' + '<div class="k-scheduler-header-wrap">' + table(dateTableRows) + allDayTable(allDayTableRows, 'k-scheduler-header-all-day') + '</div>' + '</div>');
        }
        function times(rowLevels, rowCount, isMobile) {
            var rows = new Array(rowCount).join().split(',');
            var rowHeaderRows = [];
            var rowIndex;
            for (var rowLevelIndex = 0; rowLevelIndex < rowLevels.length; rowLevelIndex++) {
                var level = rowLevels[rowLevelIndex];
                var rowspan = rowCount / level.length;
                var className;
                var text;
                for (rowIndex = 0; rowIndex < level.length; rowIndex++) {
                    className = level[rowIndex].className || '';
                    text = level[rowIndex].text;
                    if (level[rowIndex].allDay) {
                        className = 'k-scheduler-times-all-day';
                    }
                    if (isMobile && className.indexOf('k-scheduler-group-cell') !== -1) {
                        text = '<span class="k-scheduler-group-text">' + text + '</span>';
                    }
                    rows[rowspan * rowIndex] += '<th class="' + className + '" rowspan="' + rowspan + '">' + text + '</th>';
                }
            }
            for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
                rowHeaderRows.push(rows[rowIndex]);
            }
            if (rowCount < 1) {
                return $();
            }
            return $('<div class="k-scheduler-times">' + table(rowHeaderRows) + '</div>');
        }
        function content() {
            return $('<div class="k-scheduler-content">' + '<table ' + cellspacing() + ' class="k-scheduler-table"/>' + '</div>');
        }
        var HINT = '<div class="k-marquee k-scheduler-marquee">' + '<div class="k-marquee-color"></div>' + '<div class="k-marquee-text">' + '<div class="k-label-top"></div>' + '<div class="k-label-bottom"></div>' + '</div>' + '</div>';
        var ResourceView = kendo.Class.extend({
            init: function (index, isRtl) {
                this._index = index;
                this._timeSlotCollections = [];
                this._daySlotCollections = [];
                this._isRtl = isRtl;
            },
            addTimeSlotCollection: function (startDate, endDate) {
                return this._addCollection(startDate, endDate, this._timeSlotCollections);
            },
            addDaySlotCollection: function (startDate, endDate) {
                return this._addCollection(startDate, endDate, this._daySlotCollections);
            },
            _addCollection: function (startDate, endDate, collections) {
                var collection = new SlotCollection(startDate, endDate, this._index, collections.length);
                collections.push(collection);
                return collection;
            },
            timeSlotCollectionCount: function () {
                return this._timeSlotCollections.length;
            },
            daySlotCollectionCount: function () {
                return this._daySlotCollections.length;
            },
            daySlotByPosition: function (x, y, byDate) {
                return this._slotByPosition(x, y, this._daySlotCollections, byDate);
            },
            timeSlotByPosition: function (x, y, byDate) {
                return this._slotByPosition(x, y, this._timeSlotCollections, byDate);
            },
            _slotByPosition: function (x, y, collections, byDate) {
                for (var collectionIndex = 0; collectionIndex < collections.length; collectionIndex++) {
                    var collection = collections[collectionIndex];
                    for (var slotIndex = 0; slotIndex < collection.count(); slotIndex++) {
                        var slot = collection.at(slotIndex);
                        var width = slot.offsetWidth;
                        var height = slot.offsetHeight;
                        var nextSlot;
                        var horizontalEnd = slot.offsetLeft + width;
                        var verticalEnd = slot.offsetTop + height;
                        if (!byDate) {
                            nextSlot = collection.at(slotIndex + 1);
                        }
                        if (nextSlot) {
                            if (nextSlot.offsetLeft != slot.offsetLeft) {
                                if (this._isRtl) {
                                    horizontalEnd = slot.offsetLeft + (slot.offsetLeft - nextSlot.offsetLeft);
                                } else {
                                    horizontalEnd = nextSlot.offsetLeft;
                                }
                            } else {
                                verticalEnd = nextSlot.offsetTop;
                            }
                        }
                        if (x >= slot.offsetLeft && x < horizontalEnd && y >= slot.offsetTop && y < verticalEnd) {
                            return slot;
                        }
                    }
                }
            },
            refresh: function () {
                var collectionIndex;
                for (collectionIndex = 0; collectionIndex < this._daySlotCollections.length; collectionIndex++) {
                    this._daySlotCollections[collectionIndex].refresh();
                }
                for (collectionIndex = 0; collectionIndex < this._timeSlotCollections.length; collectionIndex++) {
                    this._timeSlotCollections[collectionIndex].refresh();
                }
            },
            timeSlotRanges: function (startTime, endTime) {
                var collections = this._timeSlotCollections;
                var start = this._startSlot(startTime, collections);
                if (!start.inRange && startTime >= start.slot.end) {
                    start = null;
                }
                var end = start;
                if (startTime < endTime) {
                    end = this._endSlot(endTime, collections);
                }
                if (end && !end.inRange && endTime <= end.slot.start) {
                    end = null;
                }
                if (start === null && end === null) {
                    return [];
                }
                if (start === null) {
                    if (end.slot.end <= startTime) {
                        return [];
                    }
                    start = {
                        inRange: true,
                        slot: collections[end.slot.collectionIndex].first()
                    };
                }
                if (end === null) {
                    if (start.slot.start >= endTime) {
                        return [];
                    }
                    end = {
                        inRange: true,
                        slot: collections[start.slot.collectionIndex].last()
                    };
                }
                return this._continuousRange(TimeSlotRange, collections, start, end);
            },
            daySlotRanges: function (startTime, endTime, isAllDay) {
                var collections = this._daySlotCollections;
                var start = this._startSlot(startTime, collections, isAllDay);
                if (!start.inRange && startTime >= start.slot.end) {
                    start = null;
                }
                var end = start;
                if (startTime < endTime) {
                    end = this._endSlot(endTime, collections, isAllDay);
                }
                if (end && !end.inRange && endTime <= end.slot.start) {
                    end = null;
                }
                if (start === null && end === null) {
                    return [];
                }
                if (start === null) {
                    if (end.slot.end <= startTime) {
                        return [];
                    }
                    do {
                        startTime += kendo.date.MS_PER_DAY;
                        start = this._startSlot(startTime, collections, isAllDay);
                    } while (!start.inRange && startTime >= start.slot.end);
                }
                if (end === null) {
                    if (start.slot.start >= endTime) {
                        return [];
                    }
                    do {
                        endTime -= kendo.date.MS_PER_DAY;
                        end = this._endSlot(endTime, collections, isAllDay);
                    } while (!end.inRange && endTime <= end.slot.start);
                }
                return this._continuousRange(DaySlotRange, collections, start, end);
            },
            _continuousRange: function (range, collections, start, end) {
                var startSlot = start.slot;
                var endSlot = end.slot;
                var startIndex = startSlot.collectionIndex;
                var endIndex = endSlot.collectionIndex;
                var ranges = [];
                for (var collectionIndex = startIndex; collectionIndex <= endIndex; collectionIndex++) {
                    var collection = collections[collectionIndex];
                    var first = collection.first();
                    var last = collection.last();
                    var head = false;
                    var tail = false;
                    if (collectionIndex == startIndex) {
                        tail = !start.inRange;
                    }
                    if (collectionIndex == endIndex) {
                        head = !end.inRange;
                    }
                    if (first.start < startSlot.start) {
                        first = startSlot;
                    }
                    if (last.start > endSlot.start) {
                        last = endSlot;
                    }
                    if (startIndex < endIndex) {
                        if (collectionIndex == startIndex) {
                            head = true;
                        } else if (collectionIndex == endIndex) {
                            tail = true;
                        } else {
                            head = tail = true;
                        }
                    }
                    ranges.push(new range({
                        start: first,
                        end: last,
                        collection: collection,
                        head: head,
                        tail: tail
                    }));
                }
                return ranges;
            },
            slotRanges: function (event, isDay) {
                var startTime = event._startTime || kendo.date.toUtcTime(event.start);
                var endTime = event._endTime || kendo.date.toUtcTime(event.end);
                if (isDay === undefined) {
                    isDay = event.isMultiDay();
                }
                if (isDay) {
                    return this.daySlotRanges(startTime, endTime, event.isAllDay);
                }
                return this.timeSlotRanges(startTime, endTime);
            },
            ranges: function (startTime, endTime, isDay, isAllDay) {
                if (typeof startTime != 'number') {
                    startTime = kendo.date.toUtcTime(startTime);
                }
                if (typeof endTime != 'number') {
                    endTime = kendo.date.toUtcTime(endTime);
                }
                if (isDay) {
                    return this.daySlotRanges(startTime, endTime, isAllDay);
                }
                return this.timeSlotRanges(startTime, endTime);
            },
            _startCollection: function (date, collections) {
                for (var collectionIndex = 0; collectionIndex < collections.length; collectionIndex++) {
                    var collection = collections[collectionIndex];
                    if (collection.startInRange(date)) {
                        return collection;
                    }
                }
                return null;
            },
            _endCollection: function (date, collections, isAllDay) {
                for (var collectionIndex = 0; collectionIndex < collections.length; collectionIndex++) {
                    var collection = collections[collectionIndex];
                    if (collection.endInRange(date, isAllDay)) {
                        return collection;
                    }
                }
                return null;
            },
            _getCollections: function (isDay) {
                return isDay ? this._daySlotCollections : this._timeSlotCollections;
            },
            continuousSlot: function (slot, reverse) {
                var pad = reverse ? -1 : 1;
                var collections = this._getCollections(slot.isDaySlot);
                var collection = collections[slot.collectionIndex + pad];
                return collection ? collection[reverse ? 'last' : 'first']() : undefined;
            },
            firstSlot: function () {
                var collections = this._getCollections(this.daySlotCollectionCount());
                return collections[0].first();
            },
            lastSlot: function () {
                var collections = this._getCollections(this.daySlotCollectionCount());
                return collections[collections.length - 1].last();
            },
            upSlot: function (slot, keepCollection, groupByDateVertically) {
                var that = this;
                var moveToDaySlot = function (isDaySlot, collectionIndex, index) {
                    var isFirstCell = index === 0;
                    if (!keepCollection && !isDaySlot && isFirstCell && that.daySlotCollectionCount()) {
                        return that._daySlotCollections[0].at(collectionIndex);
                    }
                };
                if (!this.timeSlotCollectionCount()) {
                    keepCollection = true;
                }
                return this._verticalSlot(slot, -1, moveToDaySlot, groupByDateVertically);
            },
            downSlot: function (slot, keepCollection, groupByDateVertically) {
                var that = this;
                var moveToTimeSlot = function (isDaySlot, collectionIndex, index) {
                    if (!keepCollection && isDaySlot && that.timeSlotCollectionCount()) {
                        return that._timeSlotCollections[index].at(0);
                    }
                };
                if (!this.timeSlotCollectionCount()) {
                    keepCollection = true;
                }
                return this._verticalSlot(slot, 1, moveToTimeSlot, groupByDateVertically);
            },
            leftSlot: function (slot, groupByDateVertically) {
                return this._horizontalSlot(slot, -1, groupByDateVertically);
            },
            rightSlot: function (slot, groupByDateVertically) {
                return this._horizontalSlot(slot, 1, groupByDateVertically);
            },
            _horizontalSlot: function (slot, step, groupByDateVertically) {
                var index = slot.index;
                var isDaySlot = slot.isDaySlot;
                var collectionIndex = slot.collectionIndex;
                var collections = this._getCollections(isDaySlot);
                isDaySlot = groupByDateVertically ? false : isDaySlot;
                if (isDaySlot) {
                    index += step;
                } else {
                    collectionIndex += step;
                }
                var collection = collections[collectionIndex];
                return collection ? collection.at(index) : undefined;
            },
            _verticalSlot: function (slot, step, swapCollection, groupByDateVertically) {
                var index = slot.index;
                var isDaySlot = slot.isDaySlot;
                var collectionIndex = slot.collectionIndex;
                var collections = this._getCollections(isDaySlot);
                slot = swapCollection(isDaySlot, collectionIndex, index);
                if (slot) {
                    return slot;
                }
                isDaySlot = groupByDateVertically ? false : isDaySlot;
                if (isDaySlot) {
                    collectionIndex += step;
                } else {
                    index += step;
                }
                var collection = collections[collectionIndex];
                return collection ? collection.at(index) : undefined;
            },
            _collection: function (index, multiday) {
                var collections = multiday ? this._daySlotCollections : this._timeSlotCollections;
                return collections[index];
            },
            _startSlot: function (time, collections, isAllDay) {
                var collection = this._startCollection(time, collections);
                var inRange = true;
                if (!collection) {
                    collection = collections[0];
                    inRange = false;
                }
                var slot = collection.slotByStartDate(time, isAllDay);
                if (!slot) {
                    slot = collection.first();
                    inRange = false;
                }
                return {
                    slot: slot,
                    inRange: inRange
                };
            },
            _endSlot: function (time, collections, isAllDay) {
                var collection = this._endCollection(time, collections, isAllDay);
                var inRange = true;
                if (!collection) {
                    collection = collections[collections.length - 1];
                    inRange = false;
                }
                var slot = collection.slotByEndDate(time, isAllDay);
                if (!slot) {
                    slot = collection.last();
                    inRange = false;
                }
                return {
                    slot: slot,
                    inRange: inRange
                };
            },
            getSlotCollection: function (index, isDay) {
                return this[isDay ? 'getDaySlotCollection' : 'getTimeSlotCollection'](index);
            },
            getTimeSlotCollection: function (index) {
                return this._timeSlotCollections[index];
            },
            getDaySlotCollection: function (index) {
                return this._daySlotCollections[index];
            }
        });
        var SlotRange = kendo.Class.extend({
            init: function (options) {
                $.extend(this, options);
            },
            innerHeight: function () {
                var collection = this.collection;
                var startIndex = this.start.index;
                var endIndex = this.end.index;
                var result = 0;
                for (var slotIndex = startIndex; slotIndex <= endIndex; slotIndex++) {
                    result += collection.at(slotIndex).offsetHeight;
                }
                return result;
            },
            events: function () {
                return this.collection.events();
            },
            addEvent: function (event) {
                this.events().push(event);
            },
            startSlot: function () {
                if (this.start.offsetLeft > this.end.offsetLeft) {
                    return this.end;
                }
                return this.start;
            },
            endSlot: function () {
                if (this.start.offsetLeft > this.end.offsetLeft) {
                    return this.start;
                }
                return this.end;
            }
        });
        var TimeSlotRange = SlotRange.extend({
            innerHeight: function () {
                var collection = this.collection;
                var startIndex = this.start.index;
                var endIndex = this.end.index;
                var result = 0;
                for (var slotIndex = startIndex; slotIndex <= endIndex; slotIndex++) {
                    result += collection.at(slotIndex).offsetHeight;
                }
                return result;
            },
            outerRect: function (start, end, snap) {
                return this._rect('offset', start, end, snap);
            },
            _rect: function (property, start, end, snap) {
                var top;
                var bottom;
                var left;
                var right;
                var startSlot = this.start;
                var endSlot = this.end;
                var isRtl = kendo.support.isRtl(startSlot.element);
                if (typeof start != 'number') {
                    start = kendo.date.toUtcTime(start);
                }
                if (typeof end != 'number') {
                    end = kendo.date.toUtcTime(end);
                }
                if (snap) {
                    top = startSlot.offsetTop;
                    bottom = endSlot.offsetTop + endSlot[property + 'Height'];
                    if (isRtl) {
                        left = endSlot.offsetLeft;
                        right = startSlot.offsetLeft + startSlot[property + 'Width'];
                    } else {
                        left = startSlot.offsetLeft;
                        right = endSlot.offsetLeft + endSlot[property + 'Width'];
                    }
                } else {
                    var startOffset = start - startSlot.start;
                    if (startOffset < 0) {
                        startOffset = 0;
                    }
                    var startSlotDuration = startSlot.end - startSlot.start;
                    top = startSlot.offsetTop + startSlot[property + 'Height'] * startOffset / startSlotDuration;
                    var endOffset = endSlot.end - end;
                    if (endOffset < 0) {
                        endOffset = 0;
                    }
                    var endSlotDuration = endSlot.end - endSlot.start;
                    bottom = endSlot.offsetTop + endSlot[property + 'Height'] - endSlot[property + 'Height'] * endOffset / endSlotDuration;
                    if (isRtl) {
                        left = Math.round(endSlot.offsetLeft + endSlot[property + 'Width'] * endOffset / endSlotDuration);
                        right = Math.round(startSlot.offsetLeft + startSlot[property + 'Width'] - startSlot[property + 'Width'] * startOffset / startSlotDuration);
                    } else {
                        left = Math.round(startSlot.offsetLeft + startSlot[property + 'Width'] * startOffset / startSlotDuration);
                        right = Math.round(endSlot.offsetLeft + endSlot[property + 'Width'] - endSlot[property + 'Width'] * endOffset / endSlotDuration);
                    }
                }
                return {
                    top: top,
                    bottom: bottom,
                    left: left === 0 ? left : left + 1,
                    right: right
                };
            },
            innerRect: function (start, end, snap) {
                return this._rect('client', start, end, snap);
            }
        });
        var DaySlotRange = SlotRange.extend({
            innerWidth: function () {
                var collection = this.collection;
                var startIndex = this.start.index;
                var endIndex = this.end.index;
                var result = 0;
                var width = startIndex !== endIndex ? 'offsetWidth' : 'clientWidth';
                for (var slotIndex = startIndex; slotIndex <= endIndex; slotIndex++) {
                    result += collection.at(slotIndex)[width];
                }
                return result;
            }
        });
        var SlotCollection = kendo.Class.extend({
            init: function (startDate, endDate, groupIndex, collectionIndex) {
                this._slots = [];
                this._events = [];
                this._start = kendo.date.toUtcTime(startDate);
                this._end = kendo.date.toUtcTime(endDate);
                this._groupIndex = groupIndex;
                this._collectionIndex = collectionIndex;
            },
            refresh: function () {
                for (var slotIndex = 0; slotIndex < this._slots.length; slotIndex++) {
                    this._slots[slotIndex].refresh();
                }
            },
            startInRange: function (date) {
                return this._start <= date && date < this._end;
            },
            endInRange: function (date, isAllDay) {
                var end = isAllDay ? date < this._end : date <= this._end;
                return this._start <= date && end;
            },
            slotByStartDate: function (date) {
                var time = date;
                if (typeof time != 'number') {
                    time = kendo.date.toUtcTime(date);
                }
                for (var slotIndex = 0; slotIndex < this._slots.length; slotIndex++) {
                    var slot = this._slots[slotIndex];
                    if (slot.startInRange(time)) {
                        return slot;
                    }
                }
                return null;
            },
            slotByEndDate: function (date, allday) {
                var time = date;
                if (typeof time != 'number') {
                    time = kendo.date.toUtcTime(date);
                }
                if (allday) {
                    return this.slotByStartDate(date, false);
                }
                for (var slotIndex = 0; slotIndex < this._slots.length; slotIndex++) {
                    var slot = this._slots[slotIndex];
                    if (slot.endInRange(time)) {
                        return slot;
                    }
                }
                return null;
            },
            count: function () {
                return this._slots.length;
            },
            events: function () {
                return this._events;
            },
            addTimeSlot: function (element, start, end, isHorizontal) {
                var slot = new TimeSlot(element, start, end, this._groupIndex, this._collectionIndex, this._slots.length, isHorizontal);
                this._slots.push(slot);
            },
            addDaySlot: function (element, start, end, eventCount) {
                var slot = new DaySlot(element, start, end, this._groupIndex, this._collectionIndex, this._slots.length, eventCount);
                this._slots.push(slot);
            },
            first: function () {
                return this._slots[0];
            },
            last: function () {
                return this._slots[this._slots.length - 1];
            },
            at: function (index) {
                return this._slots[index];
            }
        });
        var Slot = kendo.Class.extend({
            init: function (element, start, end, groupIndex, collectionIndex, index) {
                this.element = element;
                this.clientWidth = element.clientWidth;
                this.clientHeight = element.clientHeight;
                this.offsetWidth = element.offsetWidth;
                this.offsetHeight = element.offsetHeight;
                this.offsetTop = element.offsetTop;
                this.offsetLeft = element.offsetLeft;
                this.start = start;
                this.end = end;
                this.element = element;
                this.groupIndex = groupIndex;
                this.collectionIndex = collectionIndex;
                this.index = index;
                this.isDaySlot = false;
            },
            refresh: function () {
                var element = this.element;
                this.clientWidth = element.clientWidth;
                this.clientHeight = element.clientHeight;
                this.offsetWidth = element.offsetWidth;
                this.offsetHeight = element.offsetHeight;
                this.offsetTop = element.offsetTop;
                this.offsetLeft = element.offsetLeft;
            },
            startDate: function () {
                return kendo.timezone.toLocalDate(this.start);
            },
            endDate: function () {
                return kendo.timezone.toLocalDate(this.end);
            },
            startInRange: function (date) {
                return this.start <= date && date < this.end;
            },
            endInRange: function (date) {
                return this.start < date && date <= this.end;
            },
            startOffset: function () {
                return this.start;
            },
            endOffset: function () {
                return this.end;
            }
        });
        var TimeSlot = Slot.extend({
            init: function (element, start, end, groupIndex, collectionIndex, index, isHorizontal) {
                Slot.fn.init.apply(this, arguments);
                this.isHorizontal = isHorizontal ? true : false;
            },
            offsetX: function (rtl, offset) {
                if (rtl) {
                    return this.offsetLeft + offset;
                } else {
                    return this.offsetLeft + offset;
                }
            },
            startInRange: function (date) {
                return this.start <= date && date < this.end;
            },
            endInRange: function (date) {
                return this.start < date && date <= this.end;
            },
            startOffset: function (x, y, snap) {
                if (snap) {
                    return this.start;
                }
                var offset = $(this.element).offset();
                var duration = this.end - this.start;
                var difference;
                var time;
                if (this.isHorizontal) {
                    var isRtl = kendo.support.isRtl(this.element);
                    difference = x - offset.left;
                    time = Math.floor(duration * (difference / this.offsetWidth));
                    if (isRtl) {
                        return this.start + duration - time;
                    }
                } else {
                    difference = y - offset.top;
                    time = Math.floor(duration * (difference / this.offsetHeight));
                }
                return this.start + time;
            },
            endOffset: function (x, y, snap) {
                if (snap) {
                    return this.end;
                }
                var offset = $(this.element).offset();
                var duration = this.end - this.start;
                var difference;
                var time;
                if (this.isHorizontal) {
                    var isRtl = kendo.support.isRtl(this.element);
                    difference = x - offset.left;
                    time = Math.floor(duration * (difference / this.offsetWidth));
                    if (isRtl) {
                        return this.start + duration - time;
                    }
                } else {
                    difference = y - offset.top;
                    time = Math.floor(duration * (difference / this.offsetHeight));
                }
                return this.start + time;
            }
        });
        var DaySlot = Slot.extend({
            init: function (element, start, end, groupIndex, collectionIndex, index, eventCount) {
                Slot.fn.init.apply(this, arguments);
                this.eventCount = eventCount;
                this.isDaySlot = true;
                if (this.element.children.length) {
                    var firstChild = this.element.children[0];
                    this.firstChildHeight = firstChild.offsetHeight;
                    this.firstChildTop = firstChild.offsetTop;
                } else {
                    this.firstChildHeight = 3;
                    this.firstChildTop = 0;
                }
            },
            startDate: function () {
                var date = new Date(this.start);
                return kendo.timezone.apply(date, 'Etc/UTC');
            },
            endDate: function () {
                var date = new Date(this.end);
                return kendo.timezone.apply(date, 'Etc/UTC');
            },
            startInRange: function (date) {
                return this.start <= date && date < this.end;
            },
            endInRange: function (date) {
                return this.start < date && date <= this.end;
            }
        });
        var scrollbarWidth;
        function scrollbar() {
            scrollbarWidth = scrollbarWidth ? scrollbarWidth : kendo.support.scrollbar();
            return scrollbarWidth;
        }
        kendo.ui.SchedulerView = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this._normalizeOptions();
                this._scrollbar = scrollbar();
                this._isRtl = kendo.support.isRtl(element);
                this._resizeHint = $();
                this._moveHint = $();
                this._cellId = kendo.guid();
                this._resourcesForGroups();
                this._selectedSlots = [];
            },
            visibleEndDate: function () {
                return this.endDate();
            },
            _normalizeOptions: function () {
                var options = this.options;
                if (options.startTime) {
                    options.startTime.setMilliseconds(0);
                }
                if (options.endTime) {
                    options.endTime.setMilliseconds(0);
                }
                if (options.workDayStart) {
                    options.workDayStart.setMilliseconds(0);
                }
                if (options.workDayEnd) {
                    options.workDayEnd.setMilliseconds(0);
                }
            },
            _isMobile: function () {
                var options = this.options;
                return options.mobile === true && kendo.support.mobileOS || options.mobile === 'phone' || options.mobile === 'tablet';
            },
            _addResourceView: function () {
                var resourceView = new ResourceView(this.groups.length, this._isRtl);
                this.groups.push(resourceView);
                return resourceView;
            },
            dateForTitle: function () {
                return kendo.format(this.options.selectedDateFormat, this.startDate(), this.endDate());
            },
            shortDateForTitle: function () {
                return kendo.format(this.options.selectedShortDateFormat, this.startDate(), this.endDate());
            },
            mobileDateForTitle: function () {
                return kendo.format(this.options.selectedMobileDateFormat || this.options.selectedShortDateFormat, this.startDate(), this.endDate());
            },
            _changeGroup: function (selection, previous) {
                var method = previous ? 'prevGroupSlot' : 'nextGroupSlot';
                var slot = this[method](selection.start, selection.groupIndex, selection.isAllDay);
                if (slot) {
                    selection.groupIndex += previous ? -1 : 1;
                }
                if (this._isGroupedByDate() && !slot) {
                    selection.groupIndex = previous ? this.groups.length - 1 : 0;
                }
                return slot;
            },
            _changeDate: function (selection, slot, previous) {
                var group = this.groups[selection.groupIndex];
                var collections, index;
                if (previous) {
                    collections = group._getCollections(false);
                    index = group.daySlotCollectionCount() ? slot.index - 1 : slot.collectionIndex - 1;
                    if (index >= 0) {
                        return collections[index]._slots[collections[index]._slots.length - 1];
                    }
                } else {
                    collections = group._getCollections(group.daySlotCollectionCount());
                    index = group.daySlotCollectionCount() ? 0 : slot.collectionIndex + 1;
                    var slotIndex = group.daySlotCollectionCount() ? slot.collectionIndex + 1 : 0;
                    if (collections[index] && collections[index]._slots[slotIndex]) {
                        return collections[index]._slots[slotIndex];
                    }
                }
            },
            _changeGroupContinuously: function () {
                return null;
            },
            _changeViewPeriod: function () {
                return false;
            },
            _isInRange: function (newStart, newEnd) {
                if (!newStart || !newEnd || !this.options.min || !this.options.max) {
                    return false;
                }
                return getDate(newStart) <= getDate(this.options.min) || getDate(newEnd) >= getDate(this.options.max);
            },
            _horizontalSlots: function (selection, ranges, multiple, reverse) {
                var method = reverse ? 'leftSlot' : 'rightSlot';
                var horizontalRange = {
                    startSlot: ranges[0].start,
                    endSlot: ranges[ranges.length - 1].end
                };
                var group = this.groups[selection.groupIndex];
                var isVertical = this._isVerticallyGrouped();
                if (!multiple) {
                    var slot = this._normalizeHorizontalSelection(selection, ranges, reverse);
                    if (slot) {
                        horizontalRange.startSlot = horizontalRange.endSlot = slot;
                    }
                }
                if (this._isGroupedByDate() && !multiple) {
                    var tempSlot = this._changeGroup(selection, reverse);
                    if (!tempSlot) {
                        horizontalRange = this._getNextHorizontalRange(group, method, horizontalRange);
                    } else {
                        horizontalRange.startSlot = horizontalRange.endSlot = tempSlot;
                    }
                } else {
                    horizontalRange.startSlot = group[method](horizontalRange.startSlot);
                    horizontalRange.endSlot = group[method](horizontalRange.endSlot);
                    if (!multiple && !isVertical && (!horizontalRange.startSlot || !horizontalRange.endSlot)) {
                        horizontalRange.startSlot = horizontalRange.endSlot = this._changeGroup(selection, reverse);
                    }
                }
                var continuousSlot;
                if ((!horizontalRange.startSlot || !horizontalRange.endSlot) && !this._isGroupedByDate()) {
                    continuousSlot = this._continuousSlot(selection, ranges, reverse);
                    continuousSlot = this._changeGroupContinuously(selection, continuousSlot, multiple, reverse);
                    if (continuousSlot) {
                        horizontalRange.startSlot = horizontalRange.endSlot = continuousSlot;
                    }
                }
                return horizontalRange;
            },
            _getNextHorizontalRange: function (group, method, horizontalRange) {
                if (!this._isVerticallyGrouped()) {
                    horizontalRange.startSlot = group[method](horizontalRange.startSlot);
                    horizontalRange.endSlot = group[method](horizontalRange.endSlot);
                }
                return horizontalRange;
            },
            _verticalSlots: function (selection, ranges, multiple, reverse) {
                var group = this.groups[selection.groupIndex];
                var slot;
                var verticalRange = {
                    startSlot: ranges[0].start,
                    endSlot: ranges[ranges.length - 1].end
                };
                if (!multiple) {
                    slot = this._normalizeVerticalSelection(selection, ranges, reverse);
                    if (slot) {
                        verticalRange.startSlot = verticalRange.endSlot = slot;
                    }
                }
                var method = reverse ? 'upSlot' : 'downSlot';
                verticalRange = this._getNextVerticalRange(group, method, verticalRange, multiple);
                if (!multiple && this._isVerticallyGrouped() && (!verticalRange.startSlot || !verticalRange.endSlot)) {
                    if (this._isGroupedByDate()) {
                        verticalRange.startSlot = verticalRange.endSlot = this._changeDate(selection, slot, reverse);
                    } else {
                        verticalRange.startSlot = verticalRange.endSlot = this._changeGroup(selection, reverse);
                    }
                }
                return verticalRange;
            },
            _getNextVerticalRange: function (group, method, verticalRange, multiple) {
                verticalRange.startSlot = group[method](verticalRange.startSlot, multiple);
                verticalRange.endSlot = group[method](verticalRange.endSlot, multiple);
                return verticalRange;
            },
            _normalizeHorizontalSelection: function () {
                return null;
            },
            _normalizeVerticalSelection: function (selection, ranges, reverse) {
                var slot;
                if (reverse) {
                    slot = ranges[0].start;
                } else {
                    slot = ranges[ranges.length - 1].end;
                }
                return slot;
            },
            _continuousSlot: function () {
                return null;
            },
            _footer: function () {
                var that = this;
                var options = that.options;
                if (that._isMobile()) {
                    var html = '<div class="k-header k-scheduler-footer">';
                    html += '<span class="k-state-default k-scheduler-today"><a href="#" class="k-link">';
                    html += options.messages.today + '</a></span>';
                    html += '</div>';
                    that.footer = $(html).appendTo(that.element);
                }
                if (that.footer) {
                    that.footer.on('click' + NS, '.k-scheduler-today', function (e) {
                        e.preventDefault();
                        var timezone = that.options.timezone;
                        var action = 'today';
                        var currentDate = new Date();
                        var date;
                        if (timezone) {
                            var timezoneOffset = kendo.timezone.offset(currentDate, timezone);
                            date = kendo.timezone.convert(currentDate, currentDate.getTimezoneOffset(), timezoneOffset);
                        } else {
                            date = currentDate;
                        }
                        that.trigger('navigate', {
                            view: that.name || options.name,
                            action: action,
                            date: date
                        });
                    });
                }
            },
            constrainSelection: function (selection) {
                var group = this.groups[0];
                var slot;
                if (!this.inRange(selection)) {
                    slot = group.firstSlot();
                    selection.isAllDay = slot.isDaySlot;
                    selection.start = slot.startDate();
                    selection.end = slot.endDate();
                } else {
                    if (!group.daySlotCollectionCount()) {
                        selection.isAllDay = false;
                    } else if (!group.timeSlotCollectionCount()) {
                        selection.isAllDay = true;
                    }
                }
                if (!this.groups[selection.groupIndex]) {
                    selection.groupIndex = 0;
                }
            },
            move: function (selection, key, shift) {
                var handled = false;
                var group = this.groups[selection.groupIndex];
                var verticalByDate = this._isGroupedByDate() && this._isVerticallyGrouped();
                if (!group.timeSlotCollectionCount()) {
                    selection.isAllDay = true;
                }
                var ranges = group.ranges(selection.start, selection.end, selection.isAllDay, false);
                var startSlot, endSlot, reverse, slots;
                if (key === keys.DOWN || key === keys.UP) {
                    handled = true;
                    reverse = key === keys.UP;
                    this._updateDirection(selection, ranges, shift, reverse, true);
                    slots = this._verticalSlots(selection, ranges, shift, reverse);
                    if (!slots.startSlot && !shift && this._changeViewPeriod(selection, reverse, !verticalByDate)) {
                        return handled;
                    }
                } else if (key === keys.LEFT || key === keys.RIGHT) {
                    handled = true;
                    reverse = key === keys.LEFT;
                    this._updateDirection(selection, ranges, shift, reverse, false);
                    slots = this._horizontalSlots(selection, ranges, shift, reverse);
                    if (!slots.startSlot && !shift && this._changeViewPeriod(selection, reverse, verticalByDate)) {
                        return handled;
                    }
                }
                if (handled) {
                    startSlot = slots.startSlot;
                    endSlot = slots.endSlot;
                    if (shift) {
                        var backward = selection.backward;
                        if (backward && startSlot) {
                            selection.start = startSlot.startDate();
                        } else if (!backward && endSlot) {
                            selection.end = endSlot.endDate();
                        }
                    } else if (startSlot && endSlot) {
                        selection.isAllDay = startSlot.isDaySlot;
                        selection.start = startSlot.startDate();
                        selection.end = endSlot.endDate();
                    }
                    selection.events = [];
                }
                return handled;
            },
            moveToEventInGroup: function (group, slot, selectedEvents, prev) {
                var events = group._continuousEvents || [];
                var found, event;
                var pad = prev ? -1 : 1;
                var length = events.length;
                var idx = prev ? length - 1 : 0;
                if (selectedEvents.length) {
                    var lastSelected = selectedEvents[selectedEvents.length - 1];
                    for (var i = 0; i < events.length; i++) {
                        if (events[i].uid === lastSelected) {
                            idx = i + pad;
                        }
                    }
                }
                while (idx < length && idx > -1) {
                    event = events[idx];
                    if (!prev && event.start.startDate() >= slot.startDate() || prev && event.start.startDate() <= slot.startDate()) {
                        if (event && $.inArray(event.uid, selectedEvents) === -1) {
                            found = !!event;
                            break;
                        }
                    }
                    idx += pad;
                }
                return event;
            },
            moveToEvent: function (selection, prev) {
                var groupIndex = selection.groupIndex;
                var group = this.groups[groupIndex];
                var slot = group.ranges(selection.start, selection.end, selection.isAllDay, false)[0].start;
                var length = this.groups.length;
                var pad = prev ? -1 : 1;
                var events = selection.events;
                var event;
                if (this._isGroupedByDate()) {
                    var allEvents = this._getAllEvents();
                    var uniqueAllEvents = this._getUniqueEvents(allEvents);
                    var sortedEvents = this._getSortedEvents(uniqueAllEvents);
                    if (events.length === 0) {
                        var eventIndex = this._getNextEventIndexBySlot(slot, sortedEvents, groupIndex);
                        if (prev) {
                            eventIndex--;
                        }
                        event = sortedEvents[eventIndex];
                    } else {
                        var idx = this._getStartIdx(events, sortedEvents);
                        while (idx < sortedEvents.length && idx > -1) {
                            if (events.length > 0) {
                                slot = this._getSelectedSlot(slot, sortedEvents, event, idx, pad, prev);
                            }
                            if (!slot) {
                                break;
                            }
                            if (!prev && sortedEvents[idx].start.startDate() >= slot.startDate() || prev && sortedEvents[idx].start.startDate() <= slot.startDate()) {
                                if (events[0] != sortedEvents[idx].uid) {
                                    event = sortedEvents[idx];
                                    break;
                                }
                            }
                            idx += pad;
                        }
                    }
                } else {
                    while (groupIndex < length && groupIndex > -1) {
                        event = this.moveToEventInGroup(group, slot, events, prev);
                        groupIndex += pad;
                        group = this.groups[groupIndex];
                        if (!group || event) {
                            break;
                        }
                        events = [];
                        if (prev) {
                            slot = group.lastSlot();
                        } else {
                            slot = group.firstSlot(true);
                        }
                    }
                }
                if (event) {
                    selection.events = [event.uid];
                    selection.start = event.start.startDate();
                    selection.end = event.end.endDate();
                    selection.isAllDay = event.start.isDaySlot;
                    selection.groupIndex = event.start.groupIndex;
                }
                return !!event;
            },
            current: function (candidate) {
                if (candidate !== undefined) {
                    this._current = candidate;
                    if (this.content.has(candidate)) {
                        this._scrollTo(candidate, this.content[0]);
                    }
                } else {
                    return this._current;
                }
            },
            select: function (selection) {
                this.clearSelection();
                if (!this._selectEvents(selection)) {
                    this._selectSlots(selection);
                }
            },
            _getNextEventIndexBySlot: function (slot, sortedEvents, groupIndex) {
                var tempIndex = 0;
                var slotStartDate = kendo.date.getDate(slot.startDate());
                for (var i = 0; i < sortedEvents.length; i++) {
                    var eventStartDate = kendo.date.getDate(sortedEvents[i].start.startDate());
                    if (slotStartDate > eventStartDate) {
                        tempIndex++;
                        continue;
                    }
                    if (slotStartDate.getTime() === eventStartDate.getTime() && groupIndex > sortedEvents[i].start.groupIndex) {
                        tempIndex++;
                        continue;
                    }
                    if (slotStartDate.getTime() === eventStartDate.getTime() && groupIndex >= sortedEvents[i].start.groupIndex && slot.startDate() > sortedEvents[i].start.startDate()) {
                        tempIndex++;
                        continue;
                    }
                    break;
                }
                return tempIndex;
            },
            _getSelectedSlot: function (slot, sortedEvents, event, idx, pad, prev) {
                if (sortedEvents[idx + pad] && sortedEvents[idx].start.groupIndex !== sortedEvents[idx + pad].start.groupIndex) {
                    var groupIndex = sortedEvents[idx + pad].start.groupIndex;
                    var group = this.groups[groupIndex];
                    if (!group || event) {
                        slot = null;
                    }
                    if (prev) {
                        slot = group.lastSlot();
                    } else {
                        slot = group.firstSlot(true);
                    }
                }
                return slot;
            },
            _getStartIdx: function (events, sortedEvents) {
                var selectedEventIndex = 0;
                $.each(sortedEvents, function () {
                    if (this.uid === events[0]) {
                        return false;
                    }
                    selectedEventIndex++;
                });
                return selectedEventIndex;
            },
            _getAllEvents: function () {
                var allEvents = [];
                var groups = this.groups;
                for (var idx = 0; idx < groups.length; idx++) {
                    if (groups[idx]._continuousEvents) {
                        allEvents = allEvents.concat(groups[idx]._continuousEvents);
                    }
                }
                return allEvents;
            },
            _getUniqueEvents: function (allEvents) {
                var uniqueAllEvents = [];
                for (var i = 0; i < allEvents.length; i++) {
                    var exists = false;
                    for (var j = 0; j < uniqueAllEvents.length; j++) {
                        if (allEvents[i].uid === uniqueAllEvents[j].uid) {
                            exists = true;
                            break;
                        }
                    }
                    if (!exists) {
                        uniqueAllEvents.push(allEvents[i]);
                    }
                }
                return uniqueAllEvents;
            },
            _getSortedEvents: function (uniqueAllEvents) {
                return uniqueAllEvents.sort(function (first, second) {
                    var firstStartDate = first.start.startDate();
                    var secondStartDate = second.start.startDate();
                    var result = kendo.date.getDate(firstStartDate) - kendo.date.getDate(secondStartDate);
                    if (result === 0) {
                        result = first.start.groupIndex - second.start.groupIndex;
                    }
                    if (result === 0) {
                        result = firstStartDate.getTime() - secondStartDate.getTime();
                    }
                    if (result === 0) {
                        if (first.start.isDaySlot && !second.start.isDaySlot) {
                            result = -1;
                        }
                        if (!first.start.isDaySlot && second.start.isDaySlot) {
                            result = 1;
                        }
                    }
                    if (result === 0) {
                        result = $(first.element).index() - $(second.element).index();
                    }
                    return result;
                });
            },
            _selectSlots: function (selection) {
                var isAllDay = selection.isAllDay;
                var group = this.groups[selection.groupIndex];
                if (!group.timeSlotCollectionCount()) {
                    isAllDay = true;
                }
                this._selectedSlots = [];
                var ranges = group.ranges(selection.start, selection.end, isAllDay, false);
                var element;
                var slot;
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    var range = ranges[rangeIndex];
                    var collection = range.collection;
                    for (var slotIndex = range.start.index; slotIndex <= range.end.index; slotIndex++) {
                        slot = collection.at(slotIndex);
                        element = slot.element;
                        element.setAttribute('aria-selected', true);
                        addSelectedState(element);
                        this._selectedSlots.push({
                            start: slot.startDate(),
                            end: slot.endDate(),
                            element: element
                        });
                    }
                }
                if (selection.backward) {
                    element = ranges[0].start.element;
                }
                this.current(element);
            },
            _selectEvents: function (selection) {
                var found = false;
                var events = selection.events;
                var groupEvents = this._getAllEvents();
                var idx, groupEvent, length = groupEvents.length;
                if (!events[0] || !groupEvents[0]) {
                    return found;
                }
                var result = $();
                selection.events = [];
                for (idx = 0; idx < length; idx++) {
                    if ($.inArray(groupEvents[idx].uid, events) > -1) {
                        groupEvent = groupEvents[idx];
                        result = result.add(groupEvent.element);
                        if (selection.events.indexOf(groupEvent.uid) === -1) {
                            selection.events.push(groupEvent.uid);
                        }
                    }
                }
                if (result[0]) {
                    result.addClass('k-state-selected').attr('aria-selected', true);
                    this.current(result.last()[0]);
                    this._selectedSlots = [];
                    found = true;
                }
                return found;
            },
            inRange: function (options) {
                var startDate = this.startDate();
                var endDate = kendo.date.addDays(this.endDate(), 1);
                var start = options.start;
                var end = options.end;
                return startDate <= start && start < endDate && startDate < end && end <= endDate;
            },
            _resourceValue: function (resource, item) {
                if (resource.valuePrimitive) {
                    item = kendo.getter(resource.dataValueField)(item);
                }
                return item;
            },
            _resourceBySlot: function (slot) {
                var resources = this.groupedResources;
                var result = {};
                if (resources.length) {
                    var resourceIndex = slot.groupIndex;
                    for (var idx = resources.length - 1; idx >= 0; idx--) {
                        var resource = resources[idx];
                        var value = this._resourceValue(resource, resource.dataSource.view()[resourceIndex % resource.dataSource.total()]);
                        if (resource.multiple) {
                            value = [value];
                        }
                        var setter = kendo.setter(resource.field);
                        setter(result, value);
                        resourceIndex = Math.floor(resourceIndex / resource.dataSource.total());
                    }
                }
                return result;
            },
            _createResizeHint: function (left, top, width, height) {
                return $(HINT).css({
                    left: left,
                    top: top,
                    width: width,
                    height: height
                });
            },
            _removeResizeHint: function () {
                this._resizeHint.remove();
                this._resizeHint = $();
            },
            _removeMoveHint: function (uid) {
                if (uid) {
                    this._moveHint.filter('[data-uid=\'' + uid + '\']').remove();
                    this._moveHint = this._moveHint.filter('[data-uid!=\'' + uid + '\']');
                } else {
                    this._moveHint.remove();
                    this._moveHint = $();
                }
            },
            _scrollTo: function (element, container) {
                var elementOffset = element.offsetTop, elementOffsetDir = element.offsetHeight, containerScroll = container.scrollTop, containerOffsetDir = container.clientHeight, bottomDistance = elementOffset + elementOffsetDir, result = 0;
                if (containerScroll > elementOffset) {
                    result = elementOffset;
                } else if (bottomDistance > containerScroll + containerOffsetDir) {
                    if (elementOffsetDir <= containerOffsetDir) {
                        result = bottomDistance - containerOffsetDir;
                    } else {
                        result = elementOffset;
                    }
                } else {
                    result = containerScroll;
                }
                container.scrollTop = result;
            },
            _inverseEventColor: function (element) {
                var eventColor = element.css('color');
                var eventColorIsDark = new Color(eventColor).isDark();
                var eventBackground = element.css('background-color');
                var eventBackgroundIsDark = new Color(eventBackground).isDark();
                if (eventColorIsDark == eventBackgroundIsDark) {
                    element.addClass(INVERSE_COLOR_CLASS);
                }
            },
            _eventTmpl: function (template, wrapper) {
                var options = this.options, settings = $.extend({}, kendo.Template, options.templateSettings), paramName = settings.paramName, html = '', type = typeof template, state = {
                        storage: {},
                        count: 0
                    };
                if (type === 'function') {
                    state.storage['tmpl' + state.count] = template;
                    html += '#=this.tmpl' + state.count + '(' + paramName + ')#';
                    state.count++;
                } else if (type === 'string') {
                    html += template;
                }
                var tmpl = kendo.template(kendo.format(wrapper, html), settings);
                if (state.count > 0) {
                    tmpl = $.proxy(tmpl, state.storage);
                }
                return tmpl;
            },
            eventResources: function (event) {
                var resources = [], options = this.options;
                if (!options.resources) {
                    return resources;
                }
                for (var idx = 0; idx < options.resources.length; idx++) {
                    var resource = options.resources[idx];
                    var field = resource.field;
                    var eventResources = kendo.getter(field)(event);
                    if (eventResources == null) {
                        continue;
                    }
                    if (!resource.multiple) {
                        eventResources = [eventResources];
                    }
                    var data = resource.dataSource.view();
                    for (var resourceIndex = 0; resourceIndex < eventResources.length; resourceIndex++) {
                        var eventResource = null;
                        var value = eventResources[resourceIndex];
                        if (!resource.valuePrimitive) {
                            value = kendo.getter(resource.dataValueField)(value);
                        }
                        for (var dataIndex = 0; dataIndex < data.length; dataIndex++) {
                            if (data[dataIndex].get(resource.dataValueField) == value) {
                                eventResource = data[dataIndex];
                                break;
                            }
                        }
                        if (eventResource !== null) {
                            var resourceColor = kendo.getter(resource.dataColorField)(eventResource);
                            resources.push({
                                field: resource.field,
                                title: resource.title,
                                name: resource.name,
                                text: kendo.getter(resource.dataTextField)(eventResource),
                                value: value,
                                color: resourceColor
                            });
                        }
                    }
                }
                return resources;
            },
            createLayout: function (layout) {
                var allDayIndex = -1;
                if (!layout.rows) {
                    layout.rows = [];
                }
                for (var idx = 0; idx < layout.rows.length; idx++) {
                    if (layout.rows[idx].allDay) {
                        allDayIndex = idx;
                        break;
                    }
                }
                var allDaySlot = layout.rows[allDayIndex];
                if (allDayIndex >= 0) {
                    layout.rows.splice(allDayIndex, 1);
                }
                var columnLevels = this.columnLevels = levels(layout, 'columns');
                var rowLevels = this.rowLevels = levels(layout, 'rows');
                this.table = $('<table ' + cellspacing() + ' class="k-scheduler-layout k-scheduler-' + this.name + 'view"><tbody></tbody></table>');
                var rowCount = rowLevels[rowLevels.length - 1].length;
                this.table.find('tbody:first').append(this._topSection(columnLevels, allDaySlot, rowCount));
                this.table.find('tbody:first').append(this._bottomSection(columnLevels, rowLevels, rowCount));
                this.element.append(this.table);
                if (this._isMobile() && columnLevels.length > 1 && this._groupOrientation() === 'horizontal' && kendo._outerWidth($(window)) < MIN_HORIZONTAL_SCROLL_SIZE) {
                    this.table.find('.k-scheduler-content .k-scheduler-table').width(columnLevels[columnLevels.length - 2].length * 100 + '%');
                    this.table.find('.k-scheduler-header .k-scheduler-table').width(columnLevels[columnLevels.length - 2].length * 100 + '%');
                }
                this._scroller();
            },
            refreshLayout: function () {
                var that = this, toolbar = that.element.find('>.k-scheduler-toolbar'), height = that.element.innerHeight(), scrollbar = this._scrollbar, headerHeight = 0, paddingDirection = this._isRtl ? 'left' : 'right';
                for (var idx = 0; idx < toolbar.length; idx++) {
                    height -= outerHeight(toolbar.eq(idx));
                }
                if (that.datesHeader) {
                    headerHeight = outerHeight(that.datesHeader);
                }
                if (that.timesHeader && outerHeight(that.timesHeader) > headerHeight) {
                    headerHeight = outerHeight(that.timesHeader);
                }
                if (that.datesHeader && that.timesHeader) {
                    var datesHeaderRows = that.datesHeader.find('table:first tr');
                    that.timesHeader.find('tr').height(function (index) {
                        $(this).height(datesHeaderRows.eq(index).height());
                    });
                }
                if (headerHeight) {
                    height -= headerHeight;
                }
                if (that.footer) {
                    height -= outerHeight(that.footer);
                }
                var isSchedulerHeightSet = function (el) {
                    var initialHeight, newHeight;
                    if (el[0].style.height) {
                        return true;
                    } else {
                        initialHeight = el.height();
                    }
                    el.height('auto');
                    newHeight = el.height();
                    if (initialHeight != newHeight) {
                        el.height('');
                        return true;
                    }
                    el.height('');
                    return false;
                };
                var contentDiv = that.content[0], scrollbarWidth = !kendo.support.kineticScrollNeeded ? scrollbar : 0;
                if (isSchedulerHeightSet(that.element)) {
                    if (height > scrollbar * 2) {
                        that.content.height(height);
                    } else {
                        that.content.height(scrollbar * 2 + 1);
                    }
                    that.times.height(contentDiv.clientHeight);
                    var timesTable = that.times.find('table');
                    if (timesTable.length) {
                        timesTable.height(that.content.find('table')[0].clientHeight);
                    }
                }
                if (contentDiv.offsetWidth - contentDiv.clientWidth > 0) {
                    that.table.addClass('k-scrollbar-v');
                    that.datesHeader.css('padding-' + paddingDirection, scrollbarWidth - parseInt(that.datesHeader.children().css('border-' + paddingDirection + '-width'), 10));
                } else {
                    that.datesHeader.css('padding-' + paddingDirection, '');
                }
                if (contentDiv.offsetHeight - contentDiv.clientHeight > 0 || contentDiv.clientHeight > that.content.children('.k-scheduler-table').height()) {
                    that.table.addClass('k-scrollbar-h');
                } else {
                    that.table.removeClass('k-scrollbar-h');
                }
            },
            _topSection: function (columnLevels, allDaySlot, rowCount) {
                var columnCount = columnLevels[columnLevels.length - 1].length;
                this.timesHeader = timesHeader(columnLevels.length, allDaySlot, rowCount);
                this.datesHeader = datesHeader(columnLevels, columnCount, allDaySlot);
                var thElm = '<tr ' + (this._isMobile() ? 'class=\'k-mobile-header\'' : '') + '>';
                return $(thElm).append(this.timesHeader.add(this.datesHeader).wrap('<td>').parent());
            },
            _bottomSection: function (columnLevels, rowLevels, rowCount) {
                this.times = times(rowLevels, rowCount, this._isMobile());
                this.content = content(columnLevels[columnLevels.length - 1], rowLevels[rowLevels.length - 1]);
                return $('<tr>').append(this.times.add(this.content).wrap('<td>').parent());
            },
            _scroller: function () {
                var that = this;
                this.content.bind('scroll' + NS, function () {
                    that.datesHeader.find('>.k-scheduler-header-wrap').scrollLeft(this.scrollLeft);
                    that.times.scrollTop(this.scrollTop);
                });
                var touchScroller = kendo.touchScroller(this.content, {
                    avoidScrolling: function (e) {
                        return $(e.event.target).closest('.k-event.k-event-active').length > 0;
                    }
                });
                if (touchScroller && touchScroller.movable) {
                    this._touchScroller = touchScroller;
                    this.content = touchScroller.scrollElement;
                    touchScroller.movable.bind('change', function (e) {
                        that.datesHeader.find('>.k-scheduler-header-wrap').scrollLeft(-e.sender.x);
                        that.times.scrollTop(-e.sender.y);
                    });
                }
            },
            _resourcesForGroups: function () {
                var result = [];
                var groups = this.options.group;
                var resources = this.options.resources;
                groups = groups && groups.resources ? groups.resources : [];
                if (resources && groups.length) {
                    for (var idx = 0, length = resources.length; idx < length; idx++) {
                        for (var groupIdx = 0, groupLength = groups.length; groupIdx < groupLength; groupIdx++) {
                            if (resources[idx].name === groups[groupIdx]) {
                                result.push(resources[idx]);
                            }
                        }
                    }
                }
                this.groupedResources = result;
            },
            _createDateLayout: function (dates, inner, times) {
                return createDateLayoutConfiguration('rows', dates, inner, times);
            },
            _createColumnsLayout: function (resources, inner, template, dates, times) {
                return createLayoutConfiguration('columns', resources, inner, template, dates, times);
            },
            _groupOrientation: function () {
                var groups = this.options.group;
                return groups && groups.resources ? groups.orientation : 'horizontal';
            },
            _isGroupedByDate: function () {
                return this.options.group && this.options.group.date;
            },
            _isVerticallyGrouped: function () {
                return this.groupedResources.length && this._groupOrientation() === 'vertical';
            },
            _createRowsLayout: function (resources, inner, template, dates) {
                return createLayoutConfiguration('rows', resources, inner, template, dates);
            },
            selectionByElement: function () {
                return null;
            },
            clearSelection: function () {
                this.content.find('.k-state-selected').removeAttr('id').attr('aria-selected', false).removeClass('k-state-selected');
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(this);
                if (that.table) {
                    kendo.destroy(that.table);
                    that.table.remove();
                }
                if (that.footer) {
                    kendo.destroy(that.footer);
                    that.footer.remove();
                }
                that.groups = null;
                that.table = null;
                that.content = null;
                that.times = null;
                that.datesHeader = null;
                that.timesHeader = null;
                that.footer = null;
                that._resizeHint = null;
                that._moveHint = null;
            },
            calendarInfo: function () {
                return kendo.getCulture().calendars.standard;
            },
            prevGroupSlot: function (date, groupIndex, isDay) {
                var collection;
                var group = this.groups[groupIndex];
                var slot = group.ranges(date, date, isDay, false)[0].start;
                if (groupIndex <= 0) {
                    return;
                }
                if (this._isGroupedByDate()) {
                    return slot;
                }
                if (this._isVerticallyGrouped()) {
                    if (!group.timeSlotCollectionCount()) {
                        collection = group._collection(group.daySlotCollectionCount() - 1, true);
                        return collection.at(slot.index);
                    } else {
                        collection = group._collection(isDay ? slot.index : slot.collectionIndex, false);
                        return collection.last();
                    }
                } else {
                    if (!group.timeSlotCollectionCount()) {
                        collection = group._collection(slot.collectionIndex, true);
                        return collection.last();
                    } else {
                        collection = group._collection(isDay ? 0 : group.timeSlotCollectionCount() - 1, isDay);
                        return isDay ? collection.last() : collection.at(slot.index);
                    }
                }
            },
            nextGroupSlot: function (date, groupIndex, isDay) {
                var collection;
                var group = this.groups[groupIndex];
                var slot = group.ranges(date, date, isDay, false)[0].start;
                var daySlotCollectionCount;
                if (groupIndex >= this.groups.length - 1) {
                    return;
                }
                if (this._isGroupedByDate()) {
                    return slot;
                }
                if (this._isVerticallyGrouped()) {
                    if (!group.timeSlotCollectionCount()) {
                        collection = group._collection(0, true);
                        return collection.at(slot.index);
                    } else {
                        daySlotCollectionCount = group.daySlotCollectionCount();
                        collection = group._collection(daySlotCollectionCount ? 0 : slot.collectionIndex, daySlotCollectionCount);
                        return isDay ? collection.first() : collection.at(slot.collectionIndex);
                    }
                } else {
                    if (!group.timeSlotCollectionCount()) {
                        collection = group._collection(slot.collectionIndex, true);
                        return collection.first();
                    } else {
                        collection = group._collection(0, isDay);
                        return isDay ? collection.first() : collection.at(slot.index);
                    }
                }
            },
            _eventOptionsForMove: function () {
                return {};
            },
            _updateEventForResize: function () {
                return;
            },
            _updateEventForSelection: function (event) {
                return event;
            }
        });
        function collidingEvents(elements, start, end) {
            var idx, index, startIndex, overlaps, endIndex;
            for (idx = elements.length - 1; idx >= 0; idx--) {
                index = rangeIndex(elements[idx]);
                startIndex = index.start;
                endIndex = index.end;
                overlaps = startIndex <= start && endIndex >= start;
                if (overlaps || startIndex >= start && endIndex <= end || start <= startIndex && end >= startIndex) {
                    if (startIndex < start) {
                        start = startIndex;
                    }
                    if (endIndex > end) {
                        end = endIndex;
                    }
                }
            }
            return eventsForSlot(elements, start, end);
        }
        function rangeIndex(eventElement) {
            return {
                start: eventElement.start,
                end: eventElement.end
            };
        }
        function eventsForSlot(elements, slotStart, slotEnd) {
            var events = [];
            for (var idx = 0; idx < elements.length; idx++) {
                var event = rangeIndex(elements[idx]);
                if (event.start < slotStart && event.end > slotStart || event.start >= slotStart && event.end <= slotEnd) {
                    events.push(elements[idx]);
                }
            }
            return events;
        }
        function createColumns(eventElements) {
            return _createColumns(eventElements);
        }
        function createRows(eventElements) {
            return _createColumns(eventElements);
        }
        var Color = function (value) {
            var color = this, formats = Color.formats, re, processor, parts, i, channels;
            if (arguments.length === 1) {
                value = color.resolveColor(value);
                for (i = 0; i < formats.length; i++) {
                    re = formats[i].re;
                    processor = formats[i].process;
                    parts = re.exec(value);
                    if (parts) {
                        channels = processor(parts);
                        color.r = channels[0];
                        color.g = channels[1];
                        color.b = channels[2];
                    }
                }
            } else {
                color.r = arguments[0];
                color.g = arguments[1];
                color.b = arguments[2];
            }
            color.r = color.normalizeByte(color.r);
            color.g = color.normalizeByte(color.g);
            color.b = color.normalizeByte(color.b);
        };
        Color.prototype = {
            resolveColor: function (value) {
                value = value || '#000';
                if (value.charAt(0) == '#') {
                    value = value.substr(1, 6);
                }
                value = value.replace(/ /g, '');
                value = value.toLowerCase();
                value = Color.namedColors[value] || value;
                return value;
            },
            normalizeByte: function (value) {
                return value < 0 || isNaN(value) ? 0 : value > 255 ? 255 : value;
            },
            percBrightness: function () {
                var color = this;
                return math.sqrt(0.241 * color.r * color.r + 0.691 * color.g * color.g + 0.068 * color.b * color.b);
            },
            isDark: function () {
                var color = this;
                var brightnessValue = color.percBrightness();
                return brightnessValue < 180;
            }
        };
        Color.formats = [
            {
                re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
                process: function (parts) {
                    return [
                        parseInt(parts[1], 10),
                        parseInt(parts[2], 10),
                        parseInt(parts[3], 10)
                    ];
                }
            },
            {
                re: /^(\w{2})(\w{2})(\w{2})$/,
                process: function (parts) {
                    return [
                        parseInt(parts[1], 16),
                        parseInt(parts[2], 16),
                        parseInt(parts[3], 16)
                    ];
                }
            },
            {
                re: /^(\w{1})(\w{1})(\w{1})$/,
                process: function (parts) {
                    return [
                        parseInt(parts[1] + parts[1], 16),
                        parseInt(parts[2] + parts[2], 16),
                        parseInt(parts[3] + parts[3], 16)
                    ];
                }
            }
        ];
        Color.namedColors = {
            aqua: '00ffff',
            azure: 'f0ffff',
            beige: 'f5f5dc',
            black: '000000',
            blue: '0000ff',
            brown: 'a52a2a',
            coral: 'ff7f50',
            cyan: '00ffff',
            darkblue: '00008b',
            darkcyan: '008b8b',
            darkgray: 'a9a9a9',
            darkgreen: '006400',
            darkorange: 'ff8c00',
            darkred: '8b0000',
            dimgray: '696969',
            fuchsia: 'ff00ff',
            gold: 'ffd700',
            goldenrod: 'daa520',
            gray: '808080',
            green: '008000',
            greenyellow: 'adff2f',
            indigo: '4b0082',
            ivory: 'fffff0',
            khaki: 'f0e68c',
            lightblue: 'add8e6',
            lightgrey: 'd3d3d3',
            lightgreen: '90ee90',
            lightpink: 'ffb6c1',
            lightyellow: 'ffffe0',
            lime: '00ff00',
            limegreen: '32cd32',
            linen: 'faf0e6',
            magenta: 'ff00ff',
            maroon: '800000',
            mediumblue: '0000cd',
            navy: '000080',
            olive: '808000',
            orange: 'ffa500',
            orangered: 'ff4500',
            orchid: 'da70d6',
            pink: 'ffc0cb',
            plum: 'dda0dd',
            purple: '800080',
            red: 'ff0000',
            royalblue: '4169e1',
            salmon: 'fa8072',
            silver: 'c0c0c0',
            skyblue: '87ceeb',
            slateblue: '6a5acd',
            slategray: '708090',
            snow: 'fffafa',
            steelblue: '4682b4',
            tan: 'd2b48c',
            teal: '008080',
            tomato: 'ff6347',
            turquoise: '40e0d0',
            violet: 'ee82ee',
            wheat: 'f5deb3',
            white: 'ffffff',
            whitesmoke: 'f5f5f5',
            yellow: 'ffff00',
            yellowgreen: '9acd32'
        };
        function _createColumns(eventElements) {
            var columns = [];
            for (var idx = 0; idx < eventElements.length; idx++) {
                var event = eventElements[idx];
                var eventRange = rangeIndex(event);
                var column = null;
                for (var j = 0, columnLength = columns.length; j < columnLength; j++) {
                    var endOverlaps = eventRange.start > columns[j].end;
                    if (eventRange.start < columns[j].start || endOverlaps) {
                        column = columns[j];
                        if (column.end < eventRange.end) {
                            column.end = eventRange.end;
                        }
                        break;
                    }
                }
                if (!column) {
                    column = {
                        start: eventRange.start,
                        end: eventRange.end,
                        events: []
                    };
                    columns.push(column);
                }
                column.events.push(event);
            }
            return columns;
        }
        function createDateLayoutConfiguration(name, dates, inner, times) {
            var configuration = [];
            $.each(dates, function (index, item) {
                var className = item.className ? 'k-slot-cell ' + item.className : 'k-slot-cell';
                var obj = {
                    text: item.text,
                    className: className
                };
                if (times && !item.minorTicks) {
                    obj[name] = createDateLayoutConfiguration(name, item.columns, inner, times);
                } else {
                    obj[name] = inner;
                }
                configuration.push(obj);
            });
            return configuration;
        }
        function createLayoutConfiguration(name, resources, inner, template, dates, times) {
            var resource = resources[0];
            var configuration = [];
            if (resource) {
                if (dates && inner) {
                    $.each(dates, function (index, item) {
                        if (times && !item.minorTicks) {
                            item[name] = createLayoutConfiguration(name, resources, item.columns, template, item.columns, times);
                        } else {
                            item[name] = createLayoutConfiguration(name, resources, null, template);
                        }
                    });
                    configuration = dates;
                } else {
                    var data = resource.dataSource.view();
                    for (var dataIndex = 0; dataIndex < data.length; dataIndex++) {
                        var obj = {
                            text: template({
                                text: kendo.htmlEncode(kendo.getter(resource.dataTextField)(data[dataIndex])),
                                color: kendo.getter(resource.dataColorField)(data[dataIndex]),
                                field: resource.field,
                                title: resource.title,
                                name: resource.name,
                                value: kendo.getter(resource.dataValueField)(data[dataIndex])
                            }),
                            className: 'k-slot-cell k-scheduler-group-cell'
                        };
                        obj[name] = createLayoutConfiguration(name, resources.slice(1), inner, template);
                        configuration.push(obj);
                    }
                }
                return configuration;
            }
            return inner;
        }
        function groupEqFilter(value) {
            return function (item) {
                if ($.isArray(item) || item instanceof kendo.data.ObservableArray) {
                    for (var idx = 0; idx < item.length; idx++) {
                        if (item[idx] == value) {
                            return true;
                        }
                    }
                    return false;
                }
                return item == value;
            };
        }
        var selectedStateRegExp = /\s*k-state-selected/;
        function addSelectedState(cell) {
            cell.className = cell.className.replace(selectedStateRegExp, '') + ' k-state-selected';
        }
        $.extend(ui.SchedulerView, {
            createColumns: createColumns,
            createRows: createRows,
            rangeIndex: rangeIndex,
            collidingEvents: collidingEvents,
            groupEqFilter: groupEqFilter
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.dayview', ['kendo.scheduler.view'], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.dayview',
        name: 'Scheduler Day View',
        category: 'web',
        description: 'The Scheduler Day View',
        depends: ['scheduler.view'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, browser = kendo.support.browser, setTime = kendo.date.setTime, SchedulerView = ui.SchedulerView, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, extend = $.extend, proxy = $.proxy, getDate = kendo.date.getDate, MS_PER_MINUTE = kendo.date.MS_PER_MINUTE, MS_PER_DAY = kendo.date.MS_PER_DAY, CURRENT_TIME_MARKER_CLASS = 'k-current-time', CURRENT_TIME_MARKER_ARROW_CLASS = 'k-current-time-arrow', INVERSE_COLOR_CLASS = 'k-event-inverse', BORDER_SIZE_COEFF = 0.8666, getMilliseconds = kendo.date.getMilliseconds, NS = '.kendoMultiDayView';
        var DAY_VIEW_EVENT_TEMPLATE = kendo.template('<div title="(#=kendo.format("{0:t} - {1:t}", start, end)#): #=title.replace(/"/g,"&\\#34;")#">' + '<div class="k-event-template k-event-time">#:kendo.format("{0:t} - {1:t}", start, end)#</div>' + '<div class="k-event-template">${title}</div>' + '</div>'), DAY_VIEW_ALL_DAY_EVENT_TEMPLATE = kendo.template('<div title="(#=kendo.format("{0:t}", start)#): #=title.replace(/"/g,"&\\#34;")#">' + '<div class="k-event-template">${title}</div>' + '</div>'), DATA_HEADER_TEMPLATE = kendo.template('#var dateString = isMobile ? kendo.toString(date,\'ddd\')[0] : kendo.toString(date,\'ddd M/dd\'); #' + '<span class=\'k-link k-nav-day\'>#=dateString#</span>'), ALLDAY_EVENT_WRAPPER_STRING = '<div role="gridcell" aria-selected="false" ' + 'data-#=ns#uid="#=uid#"' + '#if (resources[0]) { #' + 'style="background-color:#=resources[0].color#; border-color: #=resources[0].color#"' + 'class="k-event"' + '#} else {#' + 'class="k-event"' + '#}#' + '>' + '<span class="k-event-actions">' + '# if(data.tail || data.middle) {#' + '<span class="k-icon k-i-arrow-60-left"></span>' + '#}#' + '# if(data.isException()) {#' + '<span class="k-icon k-i-non-recurrence"></span>' + '# } else if(data.isRecurring()) {#' + '<span class="k-icon k-i-reload"></span>' + '# } #' + '</span>' + '{0}' + '<span class="k-event-actions">' + '#if (showDelete) {#' + '<a href="\\#" class="k-link k-event-delete" title="${data.messages.destroy}" aria-label="${data.messages.destroy}"><span class="k-icon k-i-close"></span></a>' + '#}#' + '# if(data.head || data.middle) {#' + '<span class="k-icon k-i-arrow-60-right"></span>' + '#}#' + '</span>' + '#if(resizable && !singleDay && !data.tail && !data.middle){#' + '<span class="k-resize-handle k-resize-w"></span>' + '#}#' + '#if(resizable && !singleDay && !data.head && !data.middle){#' + '<span class="k-resize-handle k-resize-e"></span>' + '#}#' + '</div>', EVENT_WRAPPER_STRING = '<div role="gridcell" aria-selected="false" ' + 'data-#=ns#uid="#=uid#" ' + '#if (resources[0]) { #' + 'style="background-color:#=resources[0].color #; border-color: #=resources[0].color#"' + 'class="k-event"' + '#} else {#' + 'class="k-event"' + '#}#' + '>' + '<span class="k-event-actions">' + '# if(data.isException()) {#' + '<span class="k-icon k-i-non-recurrence"></span>' + '# } else if(data.isRecurring()) {#' + '<span class="k-icon k-i-reload"></span>' + '# } #' + '</span>' + '{0}' + '<span class="k-event-actions">' + '#if (showDelete) {#' + '<a href="\\#" class="k-link k-event-delete" title="${data.messages.destroy}" aria-label="${data.messages.destroy}"><span class="k-icon k-i-close"></span></a>' + '#}#' + '</span>' + '<span class="k-event-top-actions">' + '# if(data.tail || data.middle) {#' + '<span class="k-icon k-i-arrow-60-up"></span>' + '# } #' + '</span>' + '<span class="k-event-bottom-actions">' + '# if(data.head || data.middle) {#' + '<span class="k-icon k-i-arrow-60-down"></span>' + '# } #' + '</span>' + '# if(resizable && !data.tail && !data.middle) {#' + '<span class="k-resize-handle k-resize-n"></span>' + '# } #' + '# if(resizable && !data.head && !data.middle) {#' + '<span class="k-resize-handle k-resize-s"></span>' + '# } #' + '</div>';
        function toInvariantTime(date) {
            var staticDate = new Date(1980, 1, 1, 0, 0, 0);
            setTime(staticDate, getMilliseconds(date));
            return staticDate;
        }
        function isInDateRange(value, min, max) {
            return value >= min && value <= max;
        }
        function isInTimeRange(value, min, max, overlaps) {
            overlaps = overlaps ? value <= max : value < max;
            return value > min && overlaps;
        }
        function addContinuousEvent(group, range, element, isAllDay) {
            var events = group._continuousEvents;
            var lastEvent = events[events.length - 1];
            var startDate = getDate(range.start.startDate()).getTime();
            if (isAllDay && lastEvent && getDate(lastEvent.start.startDate()).getTime() == startDate) {
                var idx = events.length - 1;
                for (; idx > -1; idx--) {
                    if (events[idx].isAllDay || getDate(events[idx].start.startDate()).getTime() < startDate) {
                        break;
                    }
                }
                events.splice(idx + 1, 0, {
                    element: element,
                    isAllDay: true,
                    uid: element.attr(kendo.attr('uid')),
                    start: range.start,
                    end: range.end
                });
            } else {
                events.push({
                    element: element,
                    isAllDay: isAllDay,
                    uid: element.attr(kendo.attr('uid')),
                    start: range.start,
                    end: range.end
                });
            }
        }
        function getWorkDays(options) {
            var workDays = [];
            var dayIndex = options.workWeekStart % 7;
            var workWeekEnd = Math.abs(options.workWeekEnd % 7);
            workDays.push(dayIndex);
            while (workWeekEnd != dayIndex) {
                if (dayIndex > 6) {
                    dayIndex -= 7;
                } else {
                    dayIndex++;
                }
                workDays.push(dayIndex);
            }
            return workDays;
        }
        var MultiDayView = SchedulerView.extend({
            init: function (element, options) {
                var that = this;
                SchedulerView.fn.init.call(that, element, options);
                that.title = that.options.title || that.options.name;
                that._workDays = getWorkDays(that.options);
                that._templates();
                that._editable();
                that.calculateDateRange();
                that._groups();
                that._currentTime(true);
            },
            _currentTimeMarkerUpdater: function () {
                this._updateCurrentTimeMarker(new Date());
            },
            _updateCurrentTimeMarker: function (currentTime) {
                var options = this.options;
                if (options.currentTimeMarker.useLocalTimezone === false) {
                    var timezone = options.dataSource.options.schema.timezone;
                    if (options.dataSource && timezone) {
                        var timezoneOffset = kendo.timezone.offset(currentTime, timezone);
                        currentTime = kendo.timezone.convert(currentTime, currentTime.getTimezoneOffset(), timezoneOffset);
                    }
                }
                this.times.find('.' + CURRENT_TIME_MARKER_CLASS).remove();
                this.content.find('.' + CURRENT_TIME_MARKER_CLASS).remove();
                var groupsCount = !options.group || options.group.orientation == 'horizontal' ? 1 : this.groups.length;
                var firstTimesCell = this.times.find('tr:first th:first');
                var lastTimesCell = this.times.find('tr:first th:last');
                for (var groupIndex = 0; groupIndex < groupsCount; groupIndex++) {
                    var currentGroup = this.groups[groupIndex];
                    if (!currentGroup) {
                        return;
                    }
                    var utcCurrentTime = kendo.date.toUtcTime(currentTime);
                    var ranges = currentGroup.timeSlotRanges(utcCurrentTime, utcCurrentTime + 1);
                    if (ranges.length === 0) {
                        return;
                    }
                    var collection = ranges[0].collection;
                    var slotElement = collection.slotByStartDate(currentTime);
                    if (slotElement) {
                        var elementHtml = '<div class=\'' + CURRENT_TIME_MARKER_CLASS + '\'></div>';
                        var timesTableMarker = $(elementHtml).prependTo(this.times);
                        var markerTopPosition = Math.round(ranges[0].innerRect(currentTime, new Date(currentTime.getTime() + 1), false).top);
                        var timesTableMarkerCss = {};
                        var markerWidth = this.content[0].scrollWidth;
                        if (browser.msie || browser.edge) {
                            markerWidth -= 1;
                        }
                        if (this._isRtl) {
                            timesTableMarkerCss.right = firstTimesCell.position().left + outerHeight(firstTimesCell) - outerHeight(lastTimesCell);
                            timesTableMarker.addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-left');
                        } else {
                            timesTableMarkerCss.left = lastTimesCell.position().left;
                            timesTableMarker.addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-right');
                        }
                        timesTableMarkerCss.top = markerTopPosition - outerWidth(timesTableMarker) * BORDER_SIZE_COEFF / 2;
                        timesTableMarker.css(timesTableMarkerCss);
                        $(elementHtml).prependTo(this.content).css({
                            top: markerTopPosition,
                            height: '1px',
                            right: 0,
                            width: markerWidth,
                            left: 0
                        });
                    }
                }
            },
            _currentTime: function (setUpdateTimer) {
                var that = this;
                var markerOptions = that.options.currentTimeMarker;
                if (markerOptions !== false && markerOptions.updateInterval !== undefined) {
                    that._currentTimeMarkerUpdater();
                    if (setUpdateTimer) {
                        that._currentTimeUpdateTimer = setInterval(proxy(this._currentTimeMarkerUpdater, that), markerOptions.updateInterval);
                    }
                }
            },
            _updateResizeHint: function (event, groupIndex, startTime, endTime) {
                var multiday = event.isMultiDay();
                var group = this.groups[groupIndex];
                var ranges = group.ranges(startTime, endTime, multiday, event.isAllDay);
                var width, height, top, hint;
                this._removeResizeHint();
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    var range = ranges[rangeIndex];
                    var start = range.startSlot();
                    if (this._isGroupedByDate() && multiday) {
                        for (var slotIdx = start.index; slotIdx <= range.end.index; slotIdx++) {
                            var slot = range.collection._slots[slotIdx];
                            width = slot.offsetWidth;
                            height = slot.clientHeight;
                            top = slot.offsetTop;
                            hint = SchedulerView.fn._createResizeHint.call(this, slot.offsetLeft, top, width, height);
                            this._resizeHint = this._resizeHint.add(hint);
                        }
                    } else {
                        width = start.offsetWidth;
                        height = start.clientHeight;
                        top = start.offsetTop;
                        if (multiday) {
                            width = range.innerWidth();
                        } else {
                            var rect = range.outerRect(startTime, endTime, this.options.snap);
                            top = rect.top;
                            height = rect.bottom - rect.top;
                        }
                        hint = SchedulerView.fn._createResizeHint.call(this, start.offsetLeft, top, width, height);
                        this._resizeHint = this._resizeHint.add(hint);
                    }
                }
                var format = 't';
                var container = this.content;
                if (multiday) {
                    format = 'M/dd';
                    container = this.element.find('.k-scheduler-header-wrap:has(.k-scheduler-header-all-day) > div');
                    if (!container.length) {
                        container = this.content;
                    }
                }
                this._resizeHint.appendTo(container);
                this._resizeHint.find('.k-label-top,.k-label-bottom').text('');
                this._resizeHint.first().addClass('k-first').find('.k-label-top').text(kendo.toString(kendo.timezone.toLocalDate(startTime), format));
                this._resizeHint.last().addClass('k-last').find('.k-label-bottom').text(kendo.toString(kendo.timezone.toLocalDate(endTime), format));
            },
            _updateMoveHint: function (event, groupIndex, distance) {
                var multiday = event.isMultiDay();
                var group = this.groups[groupIndex];
                var start = kendo.date.toUtcTime(event.start) + distance;
                var end = start + event.duration();
                var ranges = group.ranges(start, end, multiday, event.isAllDay);
                start = kendo.timezone.toLocalDate(start);
                end = kendo.timezone.toLocalDate(end);
                this._removeMoveHint(event.uid);
                if (!multiday && (getMilliseconds(end) === 0 || getMilliseconds(end) < getMilliseconds(this.startTime()))) {
                    if (ranges.length > 1) {
                        ranges.pop();
                    }
                }
                var eventHint = $();
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    var range = ranges[rangeIndex];
                    var startSlot = range.start;
                    var hint;
                    var css = {
                        left: startSlot.offsetLeft + 2,
                        top: startSlot.offsetTop
                    };
                    if (this._isGroupedByDate() && multiday) {
                        for (var slotIdx = startSlot.index; slotIdx <= range.end.index; slotIdx++) {
                            var slot = range.collection._slots[slotIdx];
                            css.left = this._isRtl ? slot.clientWidth * 0.1 + slot.offsetLeft + 2 : slot.offsetLeft + 2;
                            css.height = slot.offsetHeight;
                            css.width = slot.clientWidth * 0.9 - 4;
                            hint = this._createEventElement(event.clone({
                                start: start,
                                end: end
                            }), !multiday);
                            if (event.inverseColor) {
                                hint.addClass(INVERSE_COLOR_CLASS);
                            }
                            this._appendMoveHint(hint, css);
                            eventHint = eventHint.add(hint);
                        }
                    } else {
                        if (this._isRtl) {
                            css.left = startSlot.clientWidth * 0.1 + startSlot.offsetLeft + 2;
                        }
                        if (multiday) {
                            css.width = range.innerWidth() - 4;
                        } else {
                            var rect = range.outerRect(start, end, this.options.snap);
                            css.top = rect.top;
                            css.height = rect.bottom - rect.top;
                            css.width = startSlot.clientWidth * 0.9 - 4;
                        }
                        hint = this._createEventElement(event.clone({
                            start: start,
                            end: end
                        }), !multiday);
                        if (event.inverseColor) {
                            hint.addClass(INVERSE_COLOR_CLASS);
                        }
                        this._appendMoveHint(hint, css);
                        eventHint = eventHint.add(hint);
                    }
                }
                var content = this.content;
                if (multiday) {
                    content = this.element.find('.k-scheduler-header-wrap:has(.k-scheduler-header-all-day) > div');
                    if (!content.length) {
                        content = this.content;
                    }
                }
                eventHint.appendTo(content);
            },
            _appendMoveHint: function (hint, css) {
                hint.addClass('k-event-drag-hint');
                hint.css(css);
                this._moveHint = this._moveHint.add(hint);
            },
            _slotByPosition: function (x, y) {
                var slot, offset;
                if (this._isVerticallyGrouped()) {
                    offset = this.content.offset();
                    y += this.content[0].scrollTop;
                    x += this.content[0].scrollLeft;
                } else {
                    offset = this.element.find('.k-scheduler-header-wrap:has(.k-scheduler-header-all-day)').find('>div').offset();
                }
                if (offset) {
                    x -= offset.left;
                    y -= offset.top;
                }
                x = Math.ceil(x);
                y = Math.ceil(y);
                var group;
                var groupIndex;
                for (groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                    group = this.groups[groupIndex];
                    slot = group.daySlotByPosition(x, y, this._isGroupedByDate());
                    if (slot) {
                        return slot;
                    }
                }
                if (offset) {
                    x += offset.left;
                    y += offset.top;
                }
                offset = this.content.offset();
                x -= offset.left;
                y -= offset.top;
                if (!this._isVerticallyGrouped()) {
                    y += this.content[0].scrollTop;
                    x += this.content[0].scrollLeft;
                }
                x = Math.ceil(x);
                y = Math.ceil(y);
                for (groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                    group = this.groups[groupIndex];
                    slot = group.timeSlotByPosition(x, y);
                    if (slot) {
                        return slot;
                    }
                }
                return null;
            },
            _groupCount: function () {
                var resources = this.groupedResources;
                var byDate = this._isGroupedByDate();
                if (resources.length) {
                    if (this._groupOrientation() === 'vertical') {
                        if (byDate) {
                            return this._columnCountForLevel(resources.length - 1);
                        } else {
                            return this._rowCountForLevel(resources.length - 1);
                        }
                    } else {
                        if (byDate) {
                            return this._columnCountForLevel(resources.length) / this._columnCountForLevel(0);
                        } else {
                            return this._columnCountForLevel(resources.length) / this._columnOffsetForResource(resources.length);
                        }
                    }
                }
                return 1;
            },
            _columnCountInResourceView: function () {
                var resources = this.groupedResources;
                var byDate = this._isGroupedByDate();
                if (!resources.length || this._isVerticallyGrouped()) {
                    if (byDate) {
                        return this._rowCountForLevel(0);
                    } else {
                        return this._columnCountForLevel(0);
                    }
                }
                if (byDate) {
                    return this._columnCountForLevel(0);
                } else {
                    return this._columnOffsetForResource(resources.length);
                }
            },
            _timeSlotGroups: function (groupCount, columnCount) {
                var interval = this._timeSlotInterval();
                var verticalViews = groupCount;
                var byDate = this._isGroupedByDate();
                var tableRows = this.content.find('tr:not(.k-scheduler-header-all-day)');
                var group, time, rowIndex, cellIndex;
                tableRows.attr('role', 'row');
                var rowCount = tableRows.length;
                if (this._isVerticallyGrouped()) {
                    if (byDate) {
                        verticalViews = columnCount;
                    }
                    rowCount = Math.floor(rowCount / verticalViews);
                }
                for (var groupIndex = 0; groupIndex < verticalViews; groupIndex++) {
                    var rowMultiplier = 0;
                    var cellMultiplier = 0;
                    if (this._isVerticallyGrouped()) {
                        rowMultiplier = groupIndex;
                    } else {
                        cellMultiplier = groupIndex;
                    }
                    rowIndex = rowMultiplier * rowCount;
                    while (rowIndex < (rowMultiplier + 1) * rowCount) {
                        var cells = tableRows[rowIndex].children;
                        if (rowIndex % rowCount === 0) {
                            time = getMilliseconds(new Date(+this.startTime()));
                        }
                        var timeIndex = 0;
                        if (byDate) {
                            if (this._isVerticallyGrouped()) {
                                for (cellIndex = 0; cellIndex < groupCount; cellIndex++) {
                                    group = this.groups[cellIndex];
                                    this._addTimeSlotGroup(group, cells, cellIndex, time, interval, groupIndex);
                                }
                            } else {
                                group = this.groups[groupIndex];
                                for (cellIndex = cellMultiplier; cellIndex < groupCount * columnCount; cellIndex = cellIndex + groupCount) {
                                    this._addTimeSlotGroup(group, cells, cellIndex, time, interval, timeIndex);
                                    timeIndex++;
                                }
                            }
                        } else {
                            group = this.groups[groupIndex];
                            for (cellIndex = cellMultiplier * columnCount; cellIndex < (cellMultiplier + 1) * columnCount; cellIndex++) {
                                this._addTimeSlotGroup(group, cells, cellIndex, time, interval, timeIndex);
                                timeIndex++;
                            }
                        }
                        time += interval;
                        rowIndex++;
                    }
                }
            },
            _addTimeSlotGroup: function (group, cells, cellIndex, time, interval, timeIndex) {
                var cell = cells[cellIndex];
                var collection = group.getTimeSlotCollection(timeIndex);
                var currentDate = this._dates[timeIndex];
                if (!currentDate) {
                    return;
                }
                var currentTime = Date.UTC(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate());
                var start = currentTime + time;
                var end = start + interval;
                cell.setAttribute('role', 'gridcell');
                cell.setAttribute('aria-selected', false);
                collection.addTimeSlot(cell, start, end);
            },
            _addDaySlotGroup: function (collection, cells, cellIndex, columnCount, cellCount) {
                var cell = cells[cellIndex];
                var start = this._dates[cellCount];
                if (!start) {
                    return;
                }
                var currentTime = Date.UTC(start.getFullYear(), start.getMonth(), start.getDate());
                cell.setAttribute('role', 'gridcell');
                cell.setAttribute('aria-selected', false);
                collection.addDaySlot(cell, currentTime, currentTime + kendo.date.MS_PER_DAY);
            },
            _daySlotGroups: function (groupCount, columnCount) {
                var tableRows, cellIndex;
                var verticalViews = groupCount;
                var byDate = this._isGroupedByDate();
                if (this._isVerticallyGrouped()) {
                    if (byDate) {
                        verticalViews = columnCount;
                    }
                    tableRows = this.element.find('.k-scheduler-header-all-day');
                } else {
                    tableRows = this.element.find('.k-scheduler-header-all-day tr');
                }
                tableRows.attr('role', 'row');
                for (var groupIndex = 0; groupIndex < verticalViews; groupIndex++) {
                    var rowMultiplier = 0;
                    var group, collection;
                    if (this._isVerticallyGrouped()) {
                        rowMultiplier = groupIndex;
                    }
                    var cells = tableRows[rowMultiplier].children;
                    var cellMultiplier = 0;
                    if (!this._isVerticallyGrouped()) {
                        cellMultiplier = groupIndex;
                    }
                    var cellCount = 0;
                    if (byDate) {
                        if (this._isVerticallyGrouped()) {
                            for (cellIndex = 0; cellIndex < groupCount; cellIndex++) {
                                group = this.groups[cellIndex];
                                collection = group.getDaySlotCollection(0);
                                this._addDaySlotGroup(collection, cells, cellIndex, columnCount, groupIndex);
                            }
                        } else {
                            group = this.groups[groupIndex];
                            collection = group.getDaySlotCollection(0);
                            for (cellIndex = cellMultiplier; cellIndex < groupCount * columnCount; cellIndex = cellIndex + groupCount) {
                                this._addDaySlotGroup(collection, cells, cellIndex, columnCount, cellCount);
                                cellCount++;
                            }
                        }
                    } else {
                        group = this.groups[groupIndex];
                        collection = group.getDaySlotCollection(0);
                        for (cellIndex = cellMultiplier * columnCount; cellIndex < (cellMultiplier + 1) * columnCount; cellIndex++) {
                            this._addDaySlotGroup(collection, cells, cellIndex, columnCount, cellCount);
                            cellCount++;
                        }
                    }
                }
            },
            _groups: function () {
                var groupCount = this._groupCount();
                var columnCount = this._columnCountInResourceView();
                this.groups = [];
                for (var idx = 0; idx < groupCount; idx++) {
                    var view = this._addResourceView(idx);
                    for (var columnIndex = 0; columnIndex < columnCount; columnIndex++) {
                        if (this._dates[columnIndex]) {
                            view.addTimeSlotCollection(this._dates[columnIndex], kendo.date.addDays(this._dates[columnIndex], 1));
                        }
                    }
                    if (this.options.allDaySlot) {
                        view.addDaySlotCollection(this._dates[0], kendo.date.addDays(this._dates[this._dates.length - 1], 1));
                    }
                }
                this._timeSlotGroups(groupCount, columnCount);
                if (this.options.allDaySlot) {
                    this._daySlotGroups(groupCount, columnCount);
                }
            },
            options: {
                name: 'MultiDayView',
                selectedDateFormat: '{0:D}',
                selectedShortDateFormat: '{0:d}',
                selectedMobileDateFormat: '{0:MMM} {0:dd} - {1:dd}',
                allDaySlot: true,
                showWorkHours: false,
                title: '',
                startTime: kendo.date.today(),
                endTime: kendo.date.today(),
                minorTickCount: 2,
                majorTick: 60,
                majorTimeHeaderTemplate: '<span class=\'k-time-text\'>#=kendo.toString(date, \'h:mm\')#</span> ' + '<span class=\'k-time-period\'>#=kendo.toString(date, \'tt\')#</span>',
                minorTimeHeaderTemplate: '&\\#8203;',
                groupHeaderTemplate: '#=text#',
                slotTemplate: '&nbsp;',
                allDaySlotTemplate: '&nbsp;',
                eventTemplate: DAY_VIEW_EVENT_TEMPLATE,
                allDayEventTemplate: DAY_VIEW_ALL_DAY_EVENT_TEMPLATE,
                dateHeaderTemplate: DATA_HEADER_TEMPLATE,
                editable: true,
                workDayStart: new Date(1980, 1, 1, 8, 0, 0),
                workDayEnd: new Date(1980, 1, 1, 17, 0, 0),
                workWeekStart: 1,
                workWeekEnd: 5,
                footer: { command: 'workDay' },
                messages: {
                    allDay: 'all day',
                    showFullDay: 'Show full day',
                    showWorkDay: 'Show business hours'
                },
                currentTimeMarker: {
                    updateInterval: 10000,
                    useLocalTimezone: true
                }
            },
            events: [
                'remove',
                'add',
                'edit'
            ],
            _templates: function () {
                var options = this.options, settings = extend({}, kendo.Template, options.templateSettings);
                this.eventTemplate = this._eventTmpl(options.eventTemplate, EVENT_WRAPPER_STRING);
                this.allDayEventTemplate = this._eventTmpl(options.allDayEventTemplate, ALLDAY_EVENT_WRAPPER_STRING);
                this.majorTimeHeaderTemplate = kendo.template(options.majorTimeHeaderTemplate, settings);
                this.minorTimeHeaderTemplate = kendo.template(options.minorTimeHeaderTemplate, settings);
                this.dateHeaderTemplate = kendo.template(options.dateHeaderTemplate, settings);
                this.slotTemplate = kendo.template(options.slotTemplate, settings);
                this.allDaySlotTemplate = kendo.template(options.allDaySlotTemplate, settings);
                this.groupHeaderTemplate = kendo.template(options.groupHeaderTemplate, settings);
            },
            _editable: function () {
                if (this.options.editable) {
                    if (this._isMobile()) {
                        this._touchEditable();
                    } else {
                        this._mouseEditable();
                    }
                }
            },
            _mouseEditable: function () {
                var that = this;
                that.element.on('click' + NS, '.k-event a:has(.k-i-close)', function (e) {
                    that.trigger('remove', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                    e.preventDefault();
                });
                if (that.options.editable.create !== false) {
                    that.element.on('dblclick' + NS, '.k-scheduler-content td', function (e) {
                        if (!$(this).parent().hasClass('k-scheduler-header-all-day')) {
                            var slot = that._slotByPosition(e.pageX, e.pageY);
                            if (slot) {
                                var resourceInfo = that._resourceBySlot(slot);
                                that.trigger('add', {
                                    eventInfo: extend({
                                        start: slot.startDate(),
                                        end: slot.endDate()
                                    }, resourceInfo)
                                });
                            }
                            e.preventDefault();
                        }
                    }).on('dblclick' + NS, '.k-scheduler-header-all-day td', function (e) {
                        var slot = that._slotByPosition(e.pageX, e.pageY);
                        if (slot) {
                            var resourceInfo = that._resourceBySlot(slot);
                            that.trigger('add', {
                                eventInfo: extend({}, {
                                    isAllDay: true,
                                    start: kendo.date.getDate(slot.startDate()),
                                    end: kendo.date.getDate(slot.startDate())
                                }, resourceInfo)
                            });
                        }
                        e.preventDefault();
                    });
                }
                if (that.options.editable.update !== false) {
                    that.element.on('dblclick' + NS, '.k-event', function (e) {
                        that.trigger('edit', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                        e.preventDefault();
                    });
                }
            },
            _touchEditable: function () {
                var that = this;
                var threshold = 0;
                if (kendo.support.mobileOS.android) {
                    threshold = 5;
                }
                if (that.options.editable.create !== false) {
                    that._addUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        filter: '.k-scheduler-content td',
                        useClickAsTap: !kendo.support.browser.edge,
                        tap: function (e) {
                            if (that._scrolling) {
                                return;
                            }
                            if (!$(e.target).parent().hasClass('k-scheduler-header-all-day')) {
                                var x = e.x.location !== undefined ? e.x.location : e.x;
                                var y = e.y.location !== undefined ? e.y.location : e.y;
                                var slot = that._slotByPosition(x, y);
                                if (slot) {
                                    var resourceInfo = that._resourceBySlot(slot);
                                    that.trigger('add', {
                                        eventInfo: extend({
                                            start: slot.startDate(),
                                            end: slot.endDate()
                                        }, resourceInfo)
                                    });
                                }
                                e.preventDefault();
                            }
                        }
                    });
                    that._allDayUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        useClickAsTap: !kendo.support.browser.edge,
                        filter: '.k-scheduler-header-all-day td',
                        tap: function (e) {
                            if (that._scrolling) {
                                return;
                            }
                            var x = e.x.location !== undefined ? e.x.location : e.x;
                            var y = e.y.location !== undefined ? e.y.location : e.y;
                            var slot = that._slotByPosition(x, y);
                            if (slot) {
                                var resourceInfo = that._resourceBySlot(slot);
                                that.trigger('add', {
                                    eventInfo: extend({}, {
                                        isAllDay: true,
                                        start: kendo.date.getDate(slot.startDate()),
                                        end: kendo.date.getDate(slot.startDate())
                                    }, resourceInfo)
                                });
                            }
                            e.preventDefault();
                        }
                    });
                }
                if (that.options.editable.update !== false) {
                    that._editUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        useClickAsTap: !kendo.support.browser.edge,
                        filter: '.k-event',
                        tap: function (e) {
                            if (that._scrolling) {
                                return;
                            }
                            var eventElement = $(e.target).closest('.k-event');
                            var touchElement = $(e.touch.initialTouch);
                            if (touchElement.hasClass('k-i-close')) {
                                that.trigger('remove', { uid: eventElement.attr(kendo.attr('uid')) });
                            } else if (!eventElement.hasClass('k-event-active')) {
                                that.trigger('edit', { uid: eventElement.attr(kendo.attr('uid')) });
                            }
                            e.preventDefault();
                        }
                    });
                }
            },
            _layout: function (dates) {
                var columns = [];
                var rows = [];
                var options = this.options;
                var that = this;
                var byDate = that._isGroupedByDate();
                for (var idx = 0; idx < dates.length; idx++) {
                    var column = {};
                    column.text = that.dateHeaderTemplate({
                        date: dates[idx],
                        isMobile: that._isMobile()
                    });
                    if (kendo.date.isToday(dates[idx])) {
                        column.className = 'k-today';
                    }
                    columns.push(column);
                }
                var resources = this.groupedResources;
                if (options.allDaySlot) {
                    rows.push({
                        text: options.messages.allDay,
                        allDay: true,
                        cellContent: function (idx) {
                            var groupIndex = idx;
                            idx = resources.length && that._groupOrientation() !== 'vertical' ? idx % dates.length : idx;
                            return that.allDaySlotTemplate({
                                date: dates[idx],
                                resources: function () {
                                    return that._resourceBySlot({ groupIndex: groupIndex });
                                }
                            });
                        }
                    });
                }
                this._forTimeRange(this.startTime(), this.endTime(), function (date, majorTick, middleRow, lastSlotRow) {
                    var template = majorTick ? that.majorTimeHeaderTemplate : that.minorTimeHeaderTemplate;
                    var row = {
                        text: template({ date: date }),
                        className: lastSlotRow ? 'k-slot-cell' : ''
                    };
                    rows.push(row);
                });
                if (resources.length) {
                    if (this._groupOrientation() === 'vertical') {
                        if (byDate) {
                            rows = this._createDateLayout(columns, rows);
                            columns = this._createColumnsLayout(resources, null, this.groupHeaderTemplate);
                        } else {
                            rows = this._createRowsLayout(resources, rows, this.groupHeaderTemplate);
                        }
                    } else {
                        if (byDate) {
                            columns = this._createColumnsLayout(resources, columns, this.groupHeaderTemplate, columns);
                        } else {
                            columns = this._createColumnsLayout(resources, columns, this.groupHeaderTemplate);
                        }
                    }
                }
                return {
                    columns: columns,
                    rows: rows
                };
            },
            _footer: function () {
                var options = this.options;
                if (options.footer !== false) {
                    var html = '<div class="k-header k-scheduler-footer">';
                    var command = options.footer.command;
                    if (this._isMobile()) {
                        html += '<span class="k-state-default k-scheduler-today"><a href="#" class="k-link">';
                        html += options.messages.today + '</a></span>';
                    }
                    if (command && command === 'workDay') {
                        if (this._isMobile()) {
                            html += '<span class="k-state-default k-scheduler-fullday"><a href="#" class="k-link">';
                            html += (options.showWorkHours ? options.messages.showFullDay : options.messages.showWorkDay) + '</a></span>';
                        } else {
                            html += '<ul class="k-reset k-header">';
                            html += '<li class="k-state-default k-scheduler-fullday"><a href="#" class="k-link"><span class="k-icon k-i-clock"></span>';
                            html += (options.showWorkHours ? options.messages.showFullDay : options.messages.showWorkDay) + '</a></li>';
                            html += '</ul>';
                        }
                    } else {
                        html += '&nbsp;';
                    }
                    html += '</div>';
                    this.footer = $(html).appendTo(this.element);
                    var that = this;
                    this.footer.on('click' + NS, '.k-scheduler-fullday', function (e) {
                        e.preventDefault();
                        that.trigger('navigate', {
                            view: that.name || options.name,
                            date: options.date,
                            isWorkDay: !options.showWorkHours
                        });
                    });
                    this.footer.on('click' + NS, '.k-scheduler-today', function (e) {
                        e.preventDefault();
                        var timezone = that.options.timezone;
                        var action = 'today';
                        var currentDate = new Date();
                        var date;
                        if (timezone) {
                            var timezoneOffset = kendo.timezone.offset(currentDate, timezone);
                            date = kendo.timezone.convert(currentDate, currentDate.getTimezoneOffset(), timezoneOffset);
                        } else {
                            date = currentDate;
                        }
                        that.trigger('navigate', {
                            view: that.name || options.name,
                            action: action,
                            date: date
                        });
                    });
                }
            },
            _forTimeRange: function (min, max, action, after) {
                min = toInvariantTime(min);
                max = toInvariantTime(max);
                var that = this, msMin = getMilliseconds(min), msMax = getMilliseconds(max), minorTickCount = that.options.minorTickCount, msMajorInterval = that.options.majorTick * MS_PER_MINUTE, msInterval = msMajorInterval / minorTickCount || 1, start = new Date(+min), startDay = start.getDate(), msStart, idx = 0, length, html = '';
                length = MS_PER_DAY / msInterval;
                if (msMin != msMax) {
                    if (msMin > msMax) {
                        msMax += MS_PER_DAY;
                    }
                    length = (msMax - msMin) / msInterval;
                }
                length = Math.round(length);
                for (; idx < length; idx++) {
                    var majorTickDivider = idx % (msMajorInterval / msInterval), isMajorTickRow = majorTickDivider === 0, isMiddleRow = majorTickDivider < minorTickCount - 1, isLastSlotRow = majorTickDivider === minorTickCount - 1;
                    html += action(start, isMajorTickRow, isMiddleRow, isLastSlotRow);
                    setTime(start, msInterval, false);
                }
                if (msMax) {
                    msStart = getMilliseconds(start);
                    if (startDay < start.getDate()) {
                        msStart += MS_PER_DAY;
                    }
                    if (msStart > msMax) {
                        start = new Date(+max);
                    }
                }
                if (after) {
                    html += after(start);
                }
                return html;
            },
            _content: function (dates) {
                var that = this;
                var options = that.options;
                var start = that.startTime();
                var end = this.endTime();
                var groupsCount = 1;
                var rowCount = 1;
                var columnCount = dates.length;
                var html = '';
                var resources = this.groupedResources;
                var allDaySlotTemplate = this.allDaySlotTemplate;
                var isVerticalGroupped = false;
                var allDayVerticalGroupRow;
                var byDate = that._isGroupedByDate();
                var dateID = 0;
                if (resources.length) {
                    isVerticalGroupped = that._groupOrientation() === 'vertical';
                    if (isVerticalGroupped) {
                        rowCount = this._rowCountForLevel(this.rowLevels.length - 2);
                        if (byDate) {
                            groupsCount = this._columnCountForLevel(this.columnLevels.length - 1);
                        }
                        if (options.allDaySlot) {
                            allDayVerticalGroupRow = function (groupIndex) {
                                var result = '<tr class="k-scheduler-header-all-day">';
                                var dateGroupIndex = byDate ? 0 : groupIndex;
                                var resources = function () {
                                    return that._resourceBySlot({ groupIndex: dateGroupIndex });
                                };
                                if (byDate) {
                                    for (; dateGroupIndex < groupsCount; dateGroupIndex++) {
                                        result += '<td>' + allDaySlotTemplate({
                                            date: dates[dateID],
                                            resources: resources
                                        }) + '</td>';
                                    }
                                } else {
                                    for (var idx = 0; idx < dates.length; idx++) {
                                        result += '<td>' + allDaySlotTemplate({
                                            date: dates[idx],
                                            resources: resources
                                        }) + '</td>';
                                    }
                                }
                                return result + '</tr>';
                            };
                        }
                    } else {
                        if (byDate) {
                            groupsCount = this._columnCountForLevel(this.columnLevels.length - 1) / this._columnCountForLevel(0);
                        } else {
                            groupsCount = this._columnCountForLevel(this.columnLevels.length - 2);
                        }
                    }
                }
                html += '<tbody>';
                var appendRow = function (date, majorTick, middleRow) {
                    var content = '';
                    var groupIdx = 0;
                    var idx, length;
                    content = '<tr' + (middleRow ? ' class="k-middle-row"' : '') + '>';
                    if (byDate) {
                        for (idx = 0, length = columnCount; idx < length; idx++) {
                            for (groupIdx = 0; groupIdx < groupsCount; groupIdx++) {
                                var dateIndex = idx;
                                if (isVerticalGroupped) {
                                    dateIndex = dateID;
                                }
                                content = that._addCellsToContent(content, dates, date, dateIndex, groupIdx, rowIdx);
                            }
                            if (isVerticalGroupped) {
                                break;
                            }
                        }
                    } else {
                        for (; groupIdx < groupsCount; groupIdx++) {
                            for (idx = 0, length = columnCount; idx < length; idx++) {
                                content = that._addCellsToContent(content, dates, date, idx, groupIdx, rowIdx);
                            }
                        }
                    }
                    content += '</tr>';
                    return content;
                };
                for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
                    html += allDayVerticalGroupRow ? allDayVerticalGroupRow(rowIdx) : '';
                    html += this._forTimeRange(start, end, appendRow);
                    if (isVerticalGroupped) {
                        dateID++;
                    }
                }
                html += '</tbody>';
                this.content.find('table').append(html);
            },
            _addCellsToContent: function (content, dates, date, idx, groupIdx, rowIdx) {
                var that = this;
                var classes = '';
                var tmplDate;
                var slotTemplate = this.slotTemplate;
                var isVerticalGroupped = this._groupOrientation() === 'vertical';
                var resources = function (groupIndex) {
                    return function () {
                        return that._resourceBySlot({ groupIndex: groupIndex });
                    };
                };
                if (kendo.date.isToday(dates[idx])) {
                    classes += 'k-today';
                }
                if (kendo.date.getMilliseconds(date) < kendo.date.getMilliseconds(this.options.workDayStart) || kendo.date.getMilliseconds(date) >= kendo.date.getMilliseconds(this.options.workDayEnd) || !this._isWorkDay(dates[idx])) {
                    classes += ' k-nonwork-hour';
                }
                content += '<td' + (classes !== '' ? ' class="' + classes + '"' : '') + '>';
                tmplDate = kendo.date.getDate(dates[idx]);
                kendo.date.setTime(tmplDate, kendo.date.getMilliseconds(date));
                content += slotTemplate({
                    date: tmplDate,
                    resources: resources(isVerticalGroupped && !that._isGroupedByDate() ? rowIdx : groupIdx)
                });
                content += '</td>';
                return content;
            },
            _isWorkDay: function (date) {
                var day = date.getDay();
                var workDays = this._workDays;
                for (var i = 0; i < workDays.length; i++) {
                    if (workDays[i] === day) {
                        return true;
                    }
                }
                return false;
            },
            _render: function (dates) {
                var that = this;
                dates = dates || [];
                this._dates = dates;
                this._startDate = dates[0];
                this._endDate = dates[dates.length - 1 || 0];
                this.createLayout(this._layout(dates));
                this._content(dates);
                this._footer();
                this.refreshLayout();
                var allDayHeader = this.element.find('.k-scheduler-header-all-day td');
                if (allDayHeader.length) {
                    this._allDayHeaderHeight = allDayHeader.first()[0].clientHeight;
                }
                that.element.on('click' + NS, '.k-nav-day', function (e) {
                    var th = $(e.currentTarget).closest('th');
                    var offset = th.offset();
                    var additioanlWidth = 0;
                    var additionalHeight = outerHeight(th);
                    if (that._isGroupedByDate()) {
                        if (that._isVerticallyGrouped()) {
                            additioanlWidth = outerWidth(that.times);
                            additionalHeight = 0;
                        } else {
                            additionalHeight = outerHeight(that.datesHeader);
                        }
                    }
                    var slot = that._slotByPosition(offset.left + additioanlWidth, offset.top + additionalHeight);
                    that.trigger('navigate', {
                        view: 'day',
                        date: slot.startDate()
                    });
                });
            },
            startTime: function () {
                var options = this.options;
                return options.showWorkHours ? options.workDayStart : options.startTime;
            },
            endTime: function () {
                var options = this.options;
                return options.showWorkHours ? options.workDayEnd : options.endTime;
            },
            startDate: function () {
                return this._startDate;
            },
            endDate: function () {
                return this._endDate;
            },
            _end: function (isAllDay) {
                var time = getMilliseconds(this.endTime()) || MS_PER_DAY;
                if (isAllDay) {
                    time = 0;
                }
                return new Date(this._endDate.getTime() + time);
            },
            nextDate: function () {
                return kendo.date.nextDay(this.endDate());
            },
            previousDate: function () {
                return kendo.date.previousDay(this.startDate());
            },
            calculateDateRange: function () {
                this._render([this.options.date]);
            },
            destroy: function () {
                var that = this;
                if (that._currentTimeUpdateTimer) {
                    clearInterval(that._currentTimeUpdateTimer);
                }
                if (that.datesHeader) {
                    that.datesHeader.off(NS);
                }
                if (that.element) {
                    that.element.off(NS);
                }
                if (that.footer) {
                    that.footer.remove();
                }
                SchedulerView.fn.destroy.call(this);
                if (this._isMobile() && that.options.editable) {
                    if (that.options.editable.create !== false) {
                        that._addUserEvents.destroy();
                        that._allDayUserEvents.destroy();
                    }
                    if (that.options.editable.update !== false) {
                        that._editUserEvents.destroy();
                    }
                }
            },
            inRange: function (options) {
                var inRange = SchedulerView.fn.inRange.call(this, options);
                if (options.isAllDay) {
                    return inRange;
                }
                var startTime = getMilliseconds(this.startTime());
                var endTime = getMilliseconds(this.endTime()) || kendo.date.MS_PER_DAY;
                var start = getMilliseconds(options.start);
                var end = getMilliseconds(options.end) || kendo.date.MS_PER_DAY;
                return inRange && startTime <= start && end <= endTime;
            },
            selectionByElement: function (cell) {
                var offset = cell.offset();
                return this._slotByPosition(offset.left, offset.top);
            },
            _timeSlotInterval: function () {
                var options = this.options;
                return options.majorTick / options.minorTickCount * MS_PER_MINUTE;
            },
            _timeSlotIndex: function (date) {
                var options = this.options;
                var eventStartTime = getMilliseconds(date);
                var startTime = getMilliseconds(this.startTime());
                var timeSlotInterval = options.majorTick / options.minorTickCount * MS_PER_MINUTE;
                return (eventStartTime - startTime) / timeSlotInterval;
            },
            _slotIndex: function (date, multiday) {
                if (multiday) {
                    return this._dateSlotIndex(date);
                }
                return this._timeSlotIndex(date);
            },
            _dateSlotIndex: function (date, overlaps) {
                var idx;
                var length;
                var slots = this._dates || [];
                var slotStart;
                var slotEnd;
                var offset = 1;
                for (idx = 0, length = slots.length; idx < length; idx++) {
                    slotStart = kendo.date.getDate(slots[idx]);
                    slotEnd = new Date(kendo.date.getDate(slots[idx]).getTime() + MS_PER_DAY - (overlaps ? 0 : 1));
                    if (isInDateRange(date, slotStart, slotEnd)) {
                        return idx * offset;
                    }
                }
                return -1;
            },
            _positionAllDayEvent: function (element, slotRange) {
                var slotWidth = slotRange.innerWidth();
                var startIndex = slotRange.start.index;
                var endIndex = slotRange.end.index;
                var allDayEvents = SchedulerView.collidingEvents(slotRange.events(), startIndex, endIndex);
                var currentColumnCount = this._headerColumnCount || 0;
                var leftOffset = 2;
                var rightOffset = startIndex !== endIndex ? 5 : 4;
                var eventHeight = this._allDayHeaderHeight;
                var start = slotRange.startSlot();
                element.css({
                    left: start.offsetLeft + leftOffset,
                    width: slotWidth - rightOffset
                });
                slotRange.addEvent({
                    slotIndex: startIndex,
                    start: startIndex,
                    end: endIndex,
                    element: element
                });
                allDayEvents.push({
                    slotIndex: startIndex,
                    start: startIndex,
                    end: endIndex,
                    element: element
                });
                var rows = SchedulerView.createRows(allDayEvents);
                if (rows.length && rows.length > currentColumnCount) {
                    this._headerColumnCount = rows.length;
                }
                var top = slotRange.start.offsetTop;
                for (var idx = 0, length = rows.length; idx < length; idx++) {
                    var rowEvents = rows[idx].events;
                    for (var j = 0, eventLength = rowEvents.length; j < eventLength; j++) {
                        $(rowEvents[j].element).css({ top: top + idx * eventHeight });
                    }
                }
            },
            _arrangeColumns: function (element, top, height, slotRange) {
                var startSlot = slotRange.start;
                element = {
                    element: element,
                    slotIndex: startSlot.index,
                    start: top,
                    end: top + height
                };
                var columns, slotWidth = startSlot.clientWidth, eventRightOffset = slotWidth * 0.1, columnEvents, eventElements = slotRange.events(), slotEvents = SchedulerView.collidingEvents(eventElements, element.start, element.end);
                slotRange.addEvent(element);
                slotEvents.push(element);
                columns = SchedulerView.createColumns(slotEvents);
                var columnWidth = (slotWidth - eventRightOffset) / columns.length;
                for (var idx = 0, length = columns.length; idx < length; idx++) {
                    columnEvents = columns[idx].events;
                    for (var j = 0, eventLength = columnEvents.length; j < eventLength; j++) {
                        var calculatedWidth = columnWidth - 4;
                        columnEvents[j].element[0].style.width = (calculatedWidth > 0 ? calculatedWidth : columnWidth) + 'px';
                        columnEvents[j].element[0].style.left = (this._isRtl ? eventRightOffset : 0) + startSlot.offsetLeft + idx * columnWidth + 2 + 'px';
                    }
                }
            },
            _positionEvent: function (event, element, slotRange) {
                var start = event._startTime || event.start;
                var end = event._endTime || event.end;
                var rect = slotRange.innerRect(start, end, false);
                var height = rect.bottom - rect.top - 2;
                if (height < 0) {
                    height = 0;
                }
                element.css({
                    top: rect.top,
                    height: height
                });
                this._arrangeColumns(element, rect.top, element[0].clientHeight, slotRange);
            },
            _createEventElement: function (event, isOneDayEvent, head, tail) {
                var template = isOneDayEvent ? this.eventTemplate : this.allDayEventTemplate;
                var options = this.options;
                var editable = options.editable;
                var isMobile = this._isMobile();
                var showDelete = editable && editable.destroy !== false && !isMobile;
                var resizable = editable && editable.resize !== false;
                var startDate = getDate(this.startDate());
                var endDate = getDate(this.endDate());
                var startTime = getMilliseconds(this.startTime());
                var endTime = getMilliseconds(this.endTime());
                var eventStartTime = event._time('start');
                var eventEndTime = event._time('end');
                var middle;
                if (startTime >= endTime) {
                    endTime = getMilliseconds(new Date(this.endTime().getTime() + MS_PER_DAY - 1));
                }
                if (!isOneDayEvent && !event.isAllDay) {
                    endDate = new Date(endDate.getTime() + MS_PER_DAY);
                }
                var eventStartDate = event.start;
                var eventEndDate = event.end;
                if (event.isAllDay) {
                    eventEndDate = getDate(event.end);
                }
                if (!isInDateRange(getDate(eventStartDate), startDate, endDate) && !isInDateRange(eventEndDate, startDate, endDate) || isOneDayEvent && eventStartTime < startTime && eventEndTime > endTime) {
                    middle = true;
                } else if (getDate(eventStartDate) < startDate || isOneDayEvent && eventStartTime < startTime) {
                    tail = true;
                } else if (eventEndDate > endDate && !isOneDayEvent || isOneDayEvent && eventEndTime > endTime) {
                    head = true;
                }
                var resources = this.eventResources(event);
                if (event._startTime && eventStartTime !== kendo.date.getMilliseconds(event.start)) {
                    eventStartDate = new Date(eventStartTime);
                    eventStartDate = kendo.timezone.apply(eventStartDate, 'Etc/UTC');
                }
                if (event._endTime && eventEndTime !== kendo.date.getMilliseconds(event.end)) {
                    eventEndDate = new Date(eventEndTime);
                    eventEndDate = kendo.timezone.apply(eventEndDate, 'Etc/UTC');
                }
                var data = extend({}, {
                    ns: kendo.ns,
                    resizable: resizable,
                    showDelete: showDelete,
                    middle: middle,
                    head: head,
                    tail: tail,
                    singleDay: this._dates.length == 1,
                    resources: resources,
                    inverseColor: false,
                    messages: options.messages
                }, event, {
                    start: eventStartDate,
                    end: eventEndDate
                });
                var element = $(template(data));
                this.angular('compile', function () {
                    return {
                        elements: element,
                        data: [{ dataItem: data }]
                    };
                });
                return element;
            },
            _isInTimeSlot: function (event) {
                var slotStartTime = this.startTime(), slotEndTime = this.endTime(), startTime = event._startTime || event.start, endTime = event._endTime || event.end;
                if (getMilliseconds(slotEndTime) === getMilliseconds(kendo.date.getDate(slotEndTime))) {
                    slotEndTime = kendo.date.getDate(slotEndTime);
                    setTime(slotEndTime, MS_PER_DAY - 1);
                }
                if (event._date('end') > event._date('start')) {
                    endTime = +event._date('end') + (MS_PER_DAY - 1);
                }
                endTime = event._endTime ? endTime - event._date('end') : getMilliseconds(new Date(endTime));
                startTime = event._startTime ? startTime - event._date('start') : getMilliseconds(new Date(startTime));
                slotEndTime = getMilliseconds(slotEndTime);
                slotStartTime = getMilliseconds(slotStartTime);
                if (slotStartTime === startTime && startTime === endTime) {
                    return true;
                }
                var overlaps = startTime !== slotEndTime;
                return isInTimeRange(startTime, slotStartTime, slotEndTime, overlaps) || isInTimeRange(endTime, slotStartTime, slotEndTime, overlaps) || isInTimeRange(slotStartTime, startTime, endTime) || isInTimeRange(slotEndTime, startTime, endTime);
            },
            _isInDateSlot: function (event) {
                var groups = this.groups[0];
                var slotStart = groups.firstSlot().start;
                var slotEnd = groups.lastSlot().end - 1;
                var startTime = kendo.date.toUtcTime(event.start);
                var endTime = kendo.date.toUtcTime(event.end);
                return (isInDateRange(startTime, slotStart, slotEnd) || isInDateRange(endTime, slotStart, slotEnd) || isInDateRange(slotStart, startTime, endTime) || isInDateRange(slotEnd, startTime, endTime)) && (!isInDateRange(endTime, slotStart, slotStart) || isInDateRange(endTime, startTime, startTime) || event.isAllDay);
            },
            _updateAllDayHeaderHeight: function (height) {
                if (this._height !== height) {
                    this._height = height;
                    var allDaySlots = this.element.find('.k-scheduler-header-all-day td');
                    if (allDaySlots.length) {
                        allDaySlots.parent().add(this.element.find('.k-scheduler-times-all-day').parent()).height(height);
                        for (var groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                            this.groups[groupIndex].refresh();
                        }
                    }
                }
            },
            _renderEvents: function (events, groupIndex) {
                var allDayEventContainer = this.datesHeader.find('.k-scheduler-header-wrap > div');
                var byDate = this._isGroupedByDate();
                var event;
                var idx;
                var length;
                for (idx = 0, length = events.length; idx < length; idx++) {
                    event = events[idx];
                    if (this._isInDateSlot(event)) {
                        var isMultiDayEvent = event.isAllDay || event.duration() >= MS_PER_DAY;
                        var container = isMultiDayEvent && !this._isVerticallyGrouped() ? allDayEventContainer : this.content;
                        var element, ranges, range, start, end, group;
                        if (!isMultiDayEvent) {
                            if (this._isInTimeSlot(event)) {
                                group = this.groups[groupIndex];
                                if (!group._continuousEvents) {
                                    group._continuousEvents = [];
                                }
                                ranges = group.slotRanges(event);
                                var rangeCount = ranges.length;
                                for (var rangeIndex = 0; rangeIndex < rangeCount; rangeIndex++) {
                                    range = ranges[rangeIndex];
                                    start = event.start;
                                    end = event.end;
                                    if (rangeCount > 1) {
                                        if (rangeIndex === 0) {
                                            end = range.end.endDate();
                                        } else if (rangeIndex == rangeCount - 1) {
                                            start = range.start.startDate();
                                        } else {
                                            start = range.start.startDate();
                                            end = range.end.endDate();
                                        }
                                    }
                                    var occurrence = event.clone({
                                        start: start,
                                        end: end,
                                        _startTime: event._startTime,
                                        _endTime: event.endTime
                                    });
                                    if (this._isInTimeSlot(occurrence)) {
                                        var head = range.head;
                                        element = this._createEventElement(event, !isMultiDayEvent, head, range.tail);
                                        element.appendTo(container);
                                        this._inverseEventColor(element);
                                        this._positionEvent(occurrence, element, range);
                                        addContinuousEvent(group, range, element, false);
                                    }
                                }
                            }
                        } else if (this.options.allDaySlot) {
                            group = this.groups[groupIndex];
                            if (!group._continuousEvents) {
                                group._continuousEvents = [];
                            }
                            ranges = group.slotRanges(event);
                            if (ranges.length) {
                                range = ranges[0];
                                var startIndex = range.start.index;
                                var endIndex = range.end.index;
                                if (byDate && startIndex !== endIndex) {
                                    start = range.start.start;
                                    end = range.end.end;
                                    var newStart = new Date(start);
                                    var newEnd = new Date(start);
                                    for (var i = range.start.index; i <= range.end.index; i++) {
                                        element = this._createEventElement(event, !isMultiDayEvent, i !== endIndex, i !== startIndex);
                                        var dateRange = group.daySlotRanges(newStart, newEnd, true)[0];
                                        newEnd.setDate(newEnd.getDate() + 1);
                                        newStart.setDate(newStart.getDate() + 1);
                                        this._positionAllDayEvent(element, dateRange);
                                        addContinuousEvent(group, dateRange, element, true);
                                        element.appendTo(container);
                                        this._inverseEventColor(element);
                                    }
                                } else {
                                    element = this._createEventElement(event, !isMultiDayEvent);
                                    this._positionAllDayEvent(element, ranges[0]);
                                    addContinuousEvent(group, ranges[0], element, true);
                                    element.appendTo(container);
                                    this._inverseEventColor(element);
                                }
                            }
                        }
                    }
                }
            },
            render: function (events) {
                this._headerColumnCount = 0;
                this._groups();
                this.element.find('.k-event').remove();
                events = new kendo.data.Query(events).sort([
                    {
                        field: 'start',
                        dir: 'asc'
                    },
                    {
                        field: 'end',
                        dir: 'desc'
                    }
                ]).toArray();
                var eventsByResource = [];
                this._eventsByResource(events, this.groupedResources, eventsByResource);
                var eventsPerDate = $.map(this._dates, function (date) {
                    return Math.max.apply(null, $.map(eventsByResource, function (events) {
                        return $.grep(events, function (event) {
                            return event.isMultiDay() && isInDateRange(date, getDate(event.start), getDate(event.end));
                        }).length;
                    }));
                });
                var height = Math.max.apply(null, eventsPerDate);
                this._updateAllDayHeaderHeight((height + 1) * this._allDayHeaderHeight);
                for (var groupIndex = 0; groupIndex < eventsByResource.length; groupIndex++) {
                    this._renderEvents(eventsByResource[groupIndex], groupIndex);
                }
                this.refreshLayout();
                this._currentTime(false);
                this.trigger('activate');
            },
            _eventsByResource: function (events, resources, result) {
                var resource = resources[0];
                if (resource) {
                    var view = resource.dataSource.view();
                    for (var itemIdx = 0; itemIdx < view.length; itemIdx++) {
                        var value = this._resourceValue(resource, view[itemIdx]);
                        var eventsFilteredByResource = new kendo.data.Query(events).filter({
                            field: resource.field,
                            operator: SchedulerView.groupEqFilter(value)
                        }).toArray();
                        if (resources.length > 1) {
                            this._eventsByResource(eventsFilteredByResource, resources.slice(1), result);
                        } else {
                            result.push(eventsFilteredByResource);
                        }
                    }
                } else {
                    result.push(events);
                }
            },
            _columnOffsetForResource: function (index) {
                return this._columnCountForLevel(index) / this._columnCountForLevel(index - 1);
            },
            _columnCountForLevel: function (level) {
                var columnLevel = this.columnLevels[level];
                return columnLevel ? columnLevel.length : 0;
            },
            _rowCountForLevel: function (level) {
                var rowLevel = this.rowLevels[level];
                return rowLevel ? rowLevel.length : 0;
            },
            clearSelection: function () {
                this.content.add(this.datesHeader).find('.k-state-selected').removeAttr('id').attr('aria-selected', false).removeClass('k-state-selected');
            },
            _updateDirection: function (selection, ranges, multiple, reverse, vertical) {
                var isDaySlot = selection.isAllDay;
                var startSlot = ranges[0].start;
                var endSlot = ranges[ranges.length - 1].end;
                if (multiple) {
                    if (vertical) {
                        if (!isDaySlot && startSlot.index === endSlot.index && startSlot.collectionIndex === endSlot.collectionIndex) {
                            selection.backward = reverse;
                        }
                    } else {
                        if (isDaySlot && startSlot.index === endSlot.index || !isDaySlot && startSlot.collectionIndex === endSlot.collectionIndex) {
                            selection.backward = reverse;
                        }
                    }
                }
            },
            _changeViewPeriod: function (selection, reverse, vertical) {
                if (!vertical) {
                    var date = reverse ? this.previousDate() : this.nextDate();
                    var start = selection.start;
                    var end = selection.end;
                    var verticalByDate = this._isGroupedByDate() && this._isVerticallyGrouped();
                    var group = this.groups[selection.groupIndex];
                    var collection = reverse ? group._timeSlotCollections : group._getCollections(group.daySlotCollectionCount());
                    var slots = collection[collection.length - 1]._slots;
                    var slotIndex = !reverse && !group.daySlotCollectionCount() ? 0 : slots.length - 1;
                    var endMilliseconds;
                    var newDateStart, newDateEnd;
                    newDateStart = new Date(date);
                    newDateEnd = new Date(date);
                    if (this._isInRange(newDateStart, newDateEnd)) {
                        return false;
                    }
                    selection.start = newDateStart;
                    selection.end = newDateEnd;
                    if (verticalByDate) {
                        var newStart = new Date(slots[slotIndex].startDate());
                        var newEnd = new Date(slots[slotIndex].endDate());
                        endMilliseconds = getMilliseconds(newEnd) ? getMilliseconds(newEnd) : MS_PER_DAY;
                        setTime(selection.start, getMilliseconds(newStart));
                        setTime(selection.end, endMilliseconds);
                        if (group.daySlotCollectionCount()) {
                            selection.isAllDay = !selection.isAllDay;
                        }
                    } else {
                        endMilliseconds = selection.isAllDay || !getMilliseconds(end) ? MS_PER_DAY : getMilliseconds(end);
                        setTime(selection.start, getMilliseconds(start));
                        setTime(selection.end, endMilliseconds);
                    }
                    if (!this._isVerticallyGrouped()) {
                        selection.groupIndex = reverse ? this.groups.length - 1 : 0;
                    }
                    selection.events = [];
                    return true;
                }
            }
        });
        extend(true, ui, {
            MultiDayView: MultiDayView,
            DayView: MultiDayView.extend({
                options: {
                    name: 'DayView',
                    title: 'Day',
                    selectedMobileDateFormat: '{0:MMM d}'
                },
                name: 'day'
            }),
            WeekView: MultiDayView.extend({
                options: {
                    name: 'WeekView',
                    title: 'Week',
                    selectedDateFormat: '{0:D} - {1:D}',
                    selectedShortDateFormat: '{0:d} - {1:d}'
                },
                name: 'week',
                calculateDateRange: function () {
                    var selectedDate = this.options.date, start = kendo.date.dayOfWeek(selectedDate, this.calendarInfo().firstDay, -1), idx, length, dates = [];
                    for (idx = 0, length = 7; idx < length; idx++) {
                        dates.push(start);
                        start = kendo.date.nextDay(start);
                    }
                    this._render(dates);
                }
            }),
            WorkWeekView: MultiDayView.extend({
                options: {
                    name: 'WorkWeekView',
                    title: 'Work Week',
                    selectedDateFormat: '{0:D} - {1:D}',
                    selectedShortDateFormat: '{0:d} - {1:d}'
                },
                name: 'workWeek',
                nextDate: function () {
                    var weekStart = kendo.date.dayOfWeek(kendo.date.nextDay(this.startDate()), this.calendarInfo().firstDay, 1);
                    return kendo.date.addDays(weekStart, this._workDays[0]);
                },
                previousDate: function () {
                    var weekStart = kendo.date.dayOfWeek(this.startDate(), this.calendarInfo().firstDay, -1);
                    var workDays = this._workDays;
                    return kendo.date.addDays(weekStart, workDays[workDays.length - 1] - 7);
                },
                calculateDateRange: function () {
                    var selectedDate = this.options.date, dayOfWeek = kendo.date.dayOfWeek, weekStart = dayOfWeek(selectedDate, this.calendarInfo().firstDay, -1), start = dayOfWeek(weekStart, this.options.workWeekStart, 1), end = dayOfWeek(start, this.options.workWeekEnd, 1), dates = [];
                    while (start <= end) {
                        dates.push(start);
                        start = kendo.date.nextDay(start);
                    }
                    this._render(dates);
                }
            })
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.agendaview', ['kendo.scheduler.view'], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.agendaview',
        name: 'Scheduler Agenda View',
        category: 'web',
        description: 'The Scheduler Agenda View',
        depends: ['scheduler.view'],
        hidden: true
    };
    (function ($) {
        var kendo = window.kendo, ui = kendo.ui, NS = '.kendoAgendaView';
        var EVENT_WRAPPER_FORMAT = '<div class="k-task" title="#:(data.title || "").replace(/"/g,"\'")#" data-#=kendo.ns#uid="#=uid#">' + '# if (resources[0]) {#' + '<span class="k-scheduler-mark" style="background-color:#=resources[0].color#"></span>' + '# } #' + '# if (data.isException()) { #' + '<span class="k-icon k-i-non-recurrence"></span>' + '# } else if (data.isRecurring()) {#' + '<span class="k-icon k-i-reload"></span>' + '# } #' + '<span class="k-scheduler-task-text">{0}</span>' + '#if (showDelete) {#' + '<a href="\\#" class="k-link k-event-delete" title="${data.messages.destroy}" aria-label="${data.messages.destroy}"><span class="k-icon k-i-close"></span></a>' + '#}#' + '</div>';
        var EVENT_DATE_TEMPLATE = '# if (!isMobile) { #' + '<strong class="k-scheduler-agendaday">' + '#=kendo.toString(date, "dd")#' + '</strong>' + '<em class="k-scheduler-agendaweek">' + '#=kendo.toString(date,"dddd")#' + '</em>' + '<span class="k-scheduler-agendadate">' + '#=kendo.toString(date, "y")#' + '</span>' + '# } else { #' + '<div class="k-scheduler-datecolumn-wrap">' + '<span class="k-mobile-scheduler-agendadate">' + '<span class="k-mobile-scheduler-agendaday">#=kendo.toString(date, "dd")#</span>' + '&nbsp' + '<span class="k-mobile-scheduler-agendamonth">#=kendo.toString(date, "MMMM")#</span>' + '</span>' + '<span class="k-mobile-scheduler-agendaweekday">' + '#=kendo.toString(date, "dddd")#' + '</span>' + '</div>' + '# } #';
        var EVENT_GROUP_TEMPLATE = '# if (!isMobile) { #' + '<strong class="k-scheduler-adgendagroup">' + '#=value#' + '</strong>' + '# } else { #' + '<span class="k-scheduler-group-text">' + '#=value#' + '</span>' + '# } #';
        var AgendaGroupedView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _getColumns: function (groupHeaders, columns) {
                return groupHeaders.concat(columns);
            },
            _getGroupsInDay: function () {
                return [];
            },
            _getSumOfItemsForDate: function () {
                return 0;
            },
            _renderTaskGroupsCells: function (headerCells, groups, taskGroupIndex, taskIndex) {
                var view = this._view;
                if (taskGroupIndex === 0 && taskIndex === 0 && groups.length) {
                    view._renderTaskGroupsCells(headerCells, groups);
                }
            },
            _renderDateCell: function (tableRow, groups, tasks, date, taskGroupIndex, tasksGroups) {
                var view = this._view;
                var isMobile = view._isMobile();
                tableRow.push(kendo.format('<td class="k-scheduler-datecolumn{3}{2}" rowspan="{0}">{1}</td>', tasks.length, view._dateTemplate({
                    date: date,
                    isMobile: isMobile
                }), taskGroupIndex == tasksGroups.length - 1 && !groups.length ? ' k-last' : '', !groups.length ? ' k-first' : ''));
            },
            _renderDates: function () {
                return undefined;
            },
            _getParents: function (parentGroups) {
                return parentGroups.splice(0);
            },
            _getGroupsByDate: function () {
                return undefined;
            },
            _renderTaskGroups: function (table, items, parents) {
                var view = this._view;
                table.append(view._renderTaskGroups(items, parents));
            }
        });
        var AgendaGroupedByDateView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _getColumns: function (groupHeaders, columns) {
                var view = this._view;
                if (view._isMobile()) {
                    return groupHeaders.concat(columns);
                } else {
                    var date = columns.slice(0, 1);
                    var columnsWithoutDate = columns.slice(1);
                    return date.concat(groupHeaders).concat(columnsWithoutDate);
                }
            },
            _compareDateGroups: function (currentGroup, prevGroup, index) {
                if (currentGroup[index].text == prevGroup[index].text) {
                    if (index === 0) {
                        return true;
                    } else {
                        return this._compareDateGroups(currentGroup, prevGroup, index - 1);
                    }
                }
                return false;
            },
            _getGroupsInDay: function (tasksGroups, groups) {
                var groupsInDay = [];
                var prevGroup = null;
                for (var tasksGroupIdx = 0; tasksGroupIdx < tasksGroups.length; tasksGroupIdx++) {
                    for (var itemsIdx = 0; itemsIdx < tasksGroups[tasksGroupIdx].items.length; itemsIdx++) {
                        var idx = 0;
                        if (groupsInDay.length === 0) {
                            for (idx; idx < groups[tasksGroupIdx].length; idx++) {
                                groupsInDay.push([1]);
                            }
                        } else {
                            for (idx; idx < groups[tasksGroupIdx].length; idx++) {
                                if (this._compareDateGroups(groups[tasksGroupIdx], prevGroup, idx)) {
                                    groupsInDay[idx][groupsInDay[idx].length - 1]++;
                                } else {
                                    var lastItemValue = groupsInDay[idx][groupsInDay[idx].length - 1] - 1;
                                    for (var i = 0; i < lastItemValue; i++) {
                                        groupsInDay[idx].push(0);
                                    }
                                    groupsInDay[idx].push(1);
                                }
                            }
                        }
                        prevGroup = groups[tasksGroupIdx];
                    }
                }
                return groupsInDay;
            },
            _getSumOfItemsForDate: function (tasksGroups) {
                var sumOfItemsForDate = 0;
                for (var i = 0; i < tasksGroups.length; i++) {
                    sumOfItemsForDate += tasksGroups[i].items.length;
                }
                return sumOfItemsForDate;
            },
            _renderTaskGroupsCells: function (headerCells, groups, taskGroupIndex, taskIndex, groupsInDay, sumOfItemsForDate, date, groupsRowSpanIndex) {
                var view = this._view;
                var isMobile = view._isMobile();
                if (!isMobile) {
                    if (taskGroupIndex === 0 && taskIndex === 0) {
                        headerCells.push(kendo.format('<td class="k-scheduler-datecolumn k-first" rowspan="{0}">{1}</td>', sumOfItemsForDate, view._dateTemplate({
                            date: date,
                            isMobile: isMobile
                        })));
                    }
                    for (var idx = 0; idx < groups[taskGroupIndex].length; idx++) {
                        if (groupsInDay[idx][groupsRowSpanIndex]) {
                            headerCells.push(kendo.format('<td class="k-scheduler-groupcolumn" rowspan="{0}">{1}</td>', groupsInDay[idx][groupsRowSpanIndex], view._groupTemplate({
                                value: groups[taskGroupIndex][idx].text,
                                isMobile: isMobile
                            }), groups[taskGroupIndex][idx].className));
                        }
                    }
                } else {
                    if (taskGroupIndex === 0 && taskIndex === 0 && groups.length) {
                        view._renderTaskGroupsCells(headerCells, groups);
                    }
                }
            },
            _renderDateCell: function () {
                return undefined;
            },
            _renderDates: function (table) {
                var view = this._view;
                var sortedArray = view._groupsByDate.sort(function (a, b) {
                    return a.array[0].value.getTime() - b.array[0].value.getTime();
                });
                for (var i = 0; i < sortedArray.length; i++) {
                    table.append(view._renderTaskGroups(sortedArray[i].array, sortedArray[i].groups));
                }
            },
            _getParents: function (parentGroups) {
                return parentGroups.slice(0);
            },
            _getGroupsByDate: function (groups, idx, parents) {
                var view = this._view;
                if (groups[idx].items) {
                    for (var taskGroupIndex = 0; taskGroupIndex < groups[idx].items.length; taskGroupIndex++) {
                        var date = groups[idx].items[taskGroupIndex].value;
                        var dateExists = false;
                        for (var i = 0; i < view._groupsByDate.length; i++) {
                            if (view._groupsByDate[i].array[0].value.getTime() === date.getTime()) {
                                dateExists = true;
                                view._groupsByDate[i].array.push(groups[idx].items[taskGroupIndex]);
                                view._groupsByDate[i].groups.push(parents);
                            }
                        }
                        if (!dateExists) {
                            view._groupsByDate.push({
                                array: [groups[idx].items[taskGroupIndex]],
                                groups: [parents]
                            });
                        }
                    }
                }
            },
            _renderTaskGroups: function () {
                return undefined;
            }
        });
        kendo.ui.scheduler.AgendaGroupedView = AgendaGroupedView;
        kendo.ui.scheduler.AgendaGroupedByDateView = AgendaGroupedByDateView;
        ui.AgendaView = ui.SchedulerView.extend({
            init: function (element, options) {
                ui.SchedulerView.fn.init.call(this, element, options);
                this._groupedView = this._getGroupedView();
                options = this.options;
                if (options.editable) {
                    options.editable = $.extend({ 'delete': true }, options.editable, {
                        create: false,
                        update: false
                    }, { messages: options.messages });
                }
                this.title = options.title;
                this._eventTemplate = this._eventTmpl(options.eventTemplate, EVENT_WRAPPER_FORMAT);
                this._dateTemplate = kendo.template(options.eventDateTemplate);
                this._groupTemplate = kendo.template(options.eventGroupTemplate);
                this._timeTemplate = kendo.template(options.eventTimeTemplate);
                this.element.on('mouseenter' + NS, '.k-scheduler-agenda .k-scheduler-content tr', '_mouseenter').on('mouseleave' + NS, '.k-scheduler-agenda .k-scheduler-content tr', '_mouseleave').on('click' + NS, '.k-scheduler-agenda .k-scheduler-content .k-link:has(.k-i-close)', '_remove');
                this._renderLayout(options.date);
            },
            name: 'agenda',
            _getGroupedView: function () {
                if (this._isGroupedByDate()) {
                    return new kendo.ui.scheduler.AgendaGroupedByDateView(this);
                } else {
                    return new kendo.ui.scheduler.AgendaGroupedView(this);
                }
            },
            _mouseenter: function (e) {
                $(e.currentTarget).addClass('k-state-hover');
            },
            _mouseleave: function (e) {
                $(e.currentTarget).removeClass('k-state-hover');
            },
            _remove: function (e) {
                e.preventDefault();
                this.trigger('remove', { uid: $(e.currentTarget).closest('.k-task').attr(kendo.attr('uid')) });
            },
            nextDate: function () {
                return kendo.date.nextDay(this.startDate());
            },
            startDate: function () {
                return this._startDate;
            },
            endDate: function () {
                return this._endDate;
            },
            previousDate: function () {
                return kendo.date.previousDay(this.startDate());
            },
            _renderLayout: function (date) {
                this._startDate = date;
                this._endDate = kendo.date.addDays(date, 7);
                this.createLayout(this._layout());
                this._footer();
                this.table.addClass('k-scheduler-agenda');
            },
            _layout: function () {
                var columns = [
                    {
                        text: this.options.messages.time,
                        className: 'k-scheduler-timecolumn'
                    },
                    { text: this.options.messages.event }
                ];
                if (!this._isMobile()) {
                    columns.splice(0, 0, {
                        text: this.options.messages.date,
                        className: 'k-scheduler-datecolumn'
                    });
                }
                var resources = this.groupedResources;
                if (resources.length) {
                    var groupHeaders = [];
                    for (var idx = 0; idx < resources.length; idx++) {
                        groupHeaders.push({
                            text: '',
                            className: 'k-scheduler-groupcolumn'
                        });
                    }
                    columns = this._groupedView._getColumns(groupHeaders, columns);
                }
                return { columns: columns };
            },
            _tasks: function (events) {
                var tasks = [];
                for (var idx = 0; idx < events.length; idx++) {
                    var event = events[idx];
                    var start = event.start;
                    var end = event.isAllDay ? kendo.date.getDate(event.end) : event.end;
                    var eventDurationInDays = Math.ceil((end - kendo.date.getDate(start)) / kendo.date.MS_PER_DAY);
                    if (event.isAllDay) {
                        eventDurationInDays += 1;
                    }
                    var task = event.clone();
                    task.startDate = kendo.date.getDate(start);
                    if (task.startDate >= this.startDate()) {
                        tasks.push(task);
                    }
                    if (eventDurationInDays > 1) {
                        task.end = kendo.date.nextDay(start);
                        task.head = true;
                        for (var day = 1; day < eventDurationInDays; day++) {
                            start = task.end;
                            task = event.clone();
                            task.start = task.startDate = kendo.date.getDate(start);
                            task.end = kendo.date.nextDay(start);
                            if (day == eventDurationInDays - 1) {
                                task.end = new Date(task.start.getFullYear(), task.start.getMonth(), task.start.getDate(), end.getHours(), end.getMinutes(), end.getSeconds(), end.getMilliseconds());
                                task.tail = true;
                            } else {
                                task.isAllDay = true;
                                task.middle = true;
                            }
                            if (kendo.date.getDate(task.end) <= this.endDate() && task.start >= this.startDate() || kendo.date.getDate(task.start).getTime() == this.endDate().getTime()) {
                                tasks.push(task);
                            }
                        }
                    }
                }
                return new kendo.data.Query(tasks).sort([
                    {
                        field: 'start',
                        dir: 'asc'
                    },
                    {
                        field: 'end',
                        dir: 'asc'
                    }
                ]).groupBy({ field: 'startDate' }).toArray();
            },
            _renderTaskGroups: function (tasksGroups, groups) {
                var tableRows = [];
                var editable = this.options.editable;
                var showDelete = editable && editable.destroy !== false && !this._isMobile();
                var isMobile = this._isMobile();
                var sumOfItemsForDate = this._groupedView._getSumOfItemsForDate(tasksGroups);
                var groupsInDay = this._groupedView._getGroupsInDay(tasksGroups, groups);
                var groupsRowSpanIndex = 0;
                for (var taskGroupIndex = 0; taskGroupIndex < tasksGroups.length; taskGroupIndex++) {
                    var date = tasksGroups[taskGroupIndex].value;
                    var tasks = tasksGroups[taskGroupIndex].items;
                    var today = kendo.date.isToday(date);
                    for (var taskIndex = 0; taskIndex < tasks.length; taskIndex++) {
                        var task = tasks[taskIndex];
                        var tableRow = [];
                        var headerCells = !isMobile ? tableRow : [];
                        this._groupedView._renderTaskGroupsCells(headerCells, groups, taskGroupIndex, taskIndex, groupsInDay, sumOfItemsForDate, date, groupsRowSpanIndex);
                        groupsRowSpanIndex++;
                        if (taskIndex === 0) {
                            if (isMobile) {
                                headerCells.push(kendo.format('<td class="k-scheduler-datecolumn {1}" colspan="2">{0}</td>', this._dateTemplate({
                                    date: date,
                                    isMobile: isMobile
                                }), !this.groupedResources.length ? 'k-first' : ''));
                                tableRows.push('<tr role="row" aria-selected="false"' + (today ? ' class="k-today">' : '>') + headerCells.join('') + '</tr>');
                            } else {
                                this._groupedView._renderDateCell(tableRow, groups, tasks, date, taskGroupIndex, tasksGroups);
                            }
                        }
                        if (task.head) {
                            task.format = '{0:t}';
                        } else if (task.tail) {
                            task.format = '{1:t}';
                        } else {
                            task.format = '{0:t}-{1:t}';
                        }
                        task.resources = this.eventResources(task);
                        tableRow.push(kendo.format('<td class="k-scheduler-timecolumn {4}"><div>{0}{1}{2}</div></td><td>{3}</td>', task.tail || task.middle ? '<span class="k-icon k-i-arrow-60-left"></span>' : '', this._timeTemplate(task.clone({
                            start: task._startTime || task.start,
                            end: task.endTime || task.end
                        })), task.head || task.middle ? '<span class="k-icon k-i-arrow-60-right"></span>' : '', this._eventTemplate(task.clone({
                            showDelete: showDelete,
                            messages: this.options.messages
                        })), !this.groupedResources.length && isMobile ? 'k-first' : ''));
                        tableRows.push('<tr role="row" aria-selected="false"' + (today ? ' class="k-today">' : '>') + tableRow.join('') + '</tr>');
                    }
                }
                return tableRows.join('');
            },
            _renderTaskGroupsCells: function (headerCells, groups) {
                var isMobile = this._isMobile();
                for (var idx = 0; idx < groups.length; idx++) {
                    headerCells.push(kendo.format('<td class="k-scheduler-groupcolumn{2}" rowspan="{0}">{1}</td>', groups[idx].rowSpan, this._groupTemplate({
                        value: groups[idx].text,
                        isMobile: isMobile
                    }), groups[idx].className));
                }
            },
            render: function (events) {
                var table = this.content.find('table').empty();
                var groups = [];
                if (events.length > 0) {
                    var resources = this.groupedResources;
                    if (resources.length) {
                        groups = this._createGroupConfiguration(events, resources, null);
                        this._groupsByDate = [];
                        this._renderGroups(groups, table, []);
                        this._groupedView._renderDates(table);
                    } else {
                        groups = this._tasks(events);
                        table.append(this._renderTaskGroups(groups, []));
                    }
                }
                var items = this._eventsList = flattenTaskGroups(groups);
                this._angularItems(table, items);
                this.refreshLayout();
                this.trigger('activate');
            },
            _angularItems: function (table, items) {
                this.angular('compile', function () {
                    var data = [], elements = items.map(function (item) {
                            data.push({ dataItem: item });
                            return table.find('.k-task[' + kendo.attr('uid') + '=' + item.uid + ']');
                        });
                    return {
                        elements: elements,
                        data: data
                    };
                });
            },
            _renderGroups: function (groups, table, parentGroups) {
                for (var idx = 0, length = groups.length; idx < length; idx++) {
                    var parents = this._groupedView._getParents(parentGroups);
                    parents.push(groups[idx]);
                    this._groupedView._getGroupsByDate(groups, idx, parents);
                    if (groups[idx].groups) {
                        this._renderGroups(groups[idx].groups, table, parents);
                    } else {
                        this._groupedView._renderTaskGroups(table, groups[idx].items, parents);
                    }
                }
            },
            _createGroupConfiguration: function (events, resources, parent) {
                var resource = resources[0];
                var configuration = [];
                var data = resource.dataSource.view();
                var isMobile = this._isMobile();
                for (var dataIndex = 0; dataIndex < data.length; dataIndex++) {
                    var value = resourceValue(resource, data[dataIndex]);
                    var tmp = new kendo.data.Query(events).filter({
                        field: resource.field,
                        operator: ui.SchedulerView.groupEqFilter(value)
                    }).toArray();
                    if (tmp.length) {
                        var tasks = this._tasks(tmp);
                        var className = parent ? '' : ' k-first';
                        if (dataIndex === data.length - 1 && (!parent || parent.className.indexOf('k-last') > -1)) {
                            className += ' k-last';
                        }
                        var obj = {
                            text: kendo.getter(resource.dataTextField)(data[dataIndex]),
                            value: value,
                            rowSpan: 0,
                            className: className
                        };
                        if (resources.length > 1) {
                            obj.groups = this._createGroupConfiguration(tmp, resources.slice(1), obj);
                            if (parent) {
                                parent.rowSpan += obj.rowSpan;
                            }
                        } else {
                            obj.items = tasks;
                            var span = rowSpan(obj.items);
                            if (isMobile) {
                                span += obj.items.length;
                            }
                            obj.rowSpan = span;
                            if (parent) {
                                parent.rowSpan += span;
                            }
                        }
                        configuration.push(obj);
                    }
                }
                return configuration;
            },
            selectionByElement: function (cell) {
                var index, event;
                cell = $(cell);
                if (cell.hasClass('k-scheduler-datecolumn') || !this._eventsList.length) {
                    return;
                }
                if (cell.is('.k-task')) {
                    cell = cell.closest('td');
                }
                if (this._isMobile()) {
                    var parent = cell.parent();
                    index = parent.parent().children().filter(function () {
                        return $(this).children(':not(.k-scheduler-datecolumn)').length;
                    }).index(parent);
                } else {
                    index = cell.parent().index();
                }
                event = this._eventsList[index];
                return {
                    index: index,
                    start: event.start,
                    end: event.end,
                    isAllDay: event.isAllDay,
                    uid: event.uid
                };
            },
            select: function (selection) {
                this.clearSelection();
                var row = this.table.find('.k-task').eq(selection.index).closest('tr').addClass('k-state-selected').attr('aria-selected', true)[0];
                this.current(row);
            },
            move: function (selection, key) {
                var handled = false;
                var index = selection.index;
                if (key == kendo.keys.UP) {
                    index--;
                    handled = true;
                } else if (key == kendo.keys.DOWN) {
                    index++;
                    handled = true;
                }
                if (handled) {
                    var event = this._eventsList[index];
                    if (event) {
                        selection.start = event.start;
                        selection.end = event.end;
                        selection.isAllDay = event.isAllDay;
                        selection.events = [event.uid];
                        selection.index = index;
                    }
                }
                return handled;
            },
            moveToEvent: function () {
                return false;
            },
            constrainSelection: function (selection) {
                var event = this._eventsList[0];
                if (event) {
                    selection.start = event.start;
                    selection.end = event.end;
                    selection.isAllDay = event.isAllDay;
                    selection.events = [event.uid];
                    selection.index = 0;
                }
            },
            isInRange: function () {
                return true;
            },
            destroy: function () {
                if (this.element) {
                    this.element.off(NS);
                }
                ui.SchedulerView.fn.destroy.call(this);
            },
            options: {
                title: 'Agenda',
                name: 'agenda',
                editable: true,
                selectedDateFormat: '{0:D}-{1:D}',
                selectedShortDateFormat: '{0:d} - {1:d}',
                selectedMobileDateFormat: '{0: MMM} {0:dd} - {1:dd}',
                eventTemplate: '#:title#',
                eventTimeTemplate: '#if(data.isAllDay) {#' + '#=this.options.messages.allDay#' + '#} else { #' + '#=kendo.format(format, start, end)#' + '# } #',
                eventDateTemplate: EVENT_DATE_TEMPLATE,
                eventGroupTemplate: EVENT_GROUP_TEMPLATE,
                messages: {
                    event: 'Event',
                    date: 'Date',
                    time: 'Time',
                    allDay: 'all day'
                }
            }
        });
        function rowSpan(tasks) {
            var result = 0;
            for (var idx = 0, length = tasks.length; idx < length; idx++) {
                result += tasks[idx].items.length;
            }
            return result;
        }
        function resourceValue(resource, item) {
            if (resource.valuePrimitive) {
                item = kendo.getter(resource.dataValueField)(item);
            }
            return item;
        }
        function flattenTaskGroups(groups) {
            var idx = 0, length = groups.length, item, result = [];
            for (; idx < length; idx++) {
                item = groups[idx];
                if (item.groups) {
                    item = flattenGroup(item.groups);
                    result = result.concat(item);
                } else {
                    result = result.concat(flattenGroup(item.items));
                }
            }
            return result;
        }
        function flattenGroup(groups) {
            var items = [].concat(groups), item = items.shift(), result = [], push = [].push;
            while (item) {
                if (item.groups) {
                    push.apply(items, item.groups);
                } else if (item.items) {
                    push.apply(items, item.items);
                } else {
                    push.call(result, item);
                }
                item = items.shift();
            }
            return result;
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.monthview', ['kendo.scheduler.view'], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.monthview',
        name: 'Scheduler Month View',
        category: 'web',
        description: 'The Scheduler Month View',
        depends: ['scheduler.view'],
        hidden: true
    };
    (function ($) {
        var kendo = window.kendo, ui = kendo.ui, SchedulerView = ui.SchedulerView, NS = '.kendoMonthView', extend = $.extend, getDate = kendo.date.getDate, MS_PER_DAY = kendo.date.MS_PER_DAY, NUMBER_OF_ROWS = 6, NUMBER_OF_COLUMNS = 7, INVERSE_COLOR_CLASS = 'k-event-inverse', DAY_TEMPLATE = kendo.template('<span class="k-link k-nav-day">#:kendo.toString(date, "dd")#</span>'), EVENT_WRAPPER_STRING = '<div role="gridcell" aria-selected="false" data-#=ns#uid="#=uid#"' + '#if (resources[0]) { #' + 'style="background-color:#=resources[0].color #; border-color: #=resources[0].color#"' + 'class="k-event"' + '#} else {#' + 'class="k-event"' + '#}#' + '>' + '<span class="k-event-actions">' + '# if(data.tail || data.middle) {#' + '<span class="k-icon k-i-arrow-60-left"></span>' + '#}#' + '# if(data.isException()) {#' + '<span class="k-icon k-i-non-recurrence"></span>' + '# } else if(data.isRecurring()) {#' + '<span class="k-icon k-i-reload"></span>' + '#}#' + '</span>' + '{0}' + '<span class="k-event-actions">' + '#if (showDelete) {#' + '<a href="\\#" class="k-link k-event-delete" title="${data.messages.destroy}" aria-label="${data.messages.destroy}"><span class="k-icon k-i-close"></span></a>' + '#}#' + '# if(data.head || data.middle) {#' + '<span class="k-icon k-i-arrow-60-right"></span>' + '#}#' + '</span>' + '# if(resizable && !data.tail && !data.middle) {#' + '<span class="k-resize-handle k-resize-w"></span>' + '#}#' + '# if(resizable && !data.head && !data.middle) {#' + '<span class="k-resize-handle k-resize-e"></span>' + '#}#' + '</div>', EVENT_TEMPLATE = kendo.template('<div title="#=title.replace(/"/g,"&\\#34;")#">' + '<div class="k-event-template">#:title#</div>' + '</div>');
        var MORE_BUTTON_TEMPLATE = kendo.template('<div style="width:#=width#px;left:#=left#px;top:#=top#px" class="k-more-events k-button"><span>...</span></div>');
        var MonthGroupedView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _verticalRowCountForLevel: function (level) {
                var view = this._view;
                return view._rowCountForLevel(level);
            },
            _horizontalGroupCountForLevel: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level);
            },
            _getCalendarRowsLength: function (cellsPerRow, cellCount) {
                return cellCount / cellsPerRow;
            },
            _createRows: function (start, startIdx, horizontalGroupCount, verticalGroupIndex) {
                var view = this._view;
                var cellsPerRow = NUMBER_OF_COLUMNS;
                var isVerticallyGrouped = view._isVerticallyGrouped();
                var html = '';
                for (var groupIdx = 0; groupIdx < horizontalGroupCount; groupIdx++) {
                    html += view._createRow(start, startIdx, cellsPerRow, isVerticallyGrouped ? verticalGroupIndex : groupIdx);
                }
                return html;
            },
            _adjustStartDate: function (start) {
                return kendo.date.addDays(start, NUMBER_OF_COLUMNS);
            },
            _getContent: function (content, startDate, resources) {
                return content({
                    date: startDate,
                    resources: resources
                });
            },
            _getTimeSlotByPosition: function (x, y, groupIndex) {
                var group = this._view.groups[groupIndex];
                return group.daySlotByPosition(x, y);
            },
            _nextSlotStartDate: function (startDate) {
                return kendo.date.nextDay(startDate);
            },
            _createRowsLayout: function (resources, rows, groupHeaderTemplate) {
                var view = this._view;
                return view._createRowsLayout(resources, rows, groupHeaderTemplate);
            },
            _createVerticalColumnsLayout: function (resources, rows, groupHeaderTemplate, columns) {
                return columns;
            },
            _createColumnsLayout: function (resources, columns, groupHeaderTemplate) {
                var view = this._view;
                return view._createColumnsLayout(resources, columns, groupHeaderTemplate);
            },
            _verticalGroupCount: function (level) {
                var view = this._view;
                return view._rowCountForLevel(level);
            },
            _horizontalGroupCount: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level) / view._columnOffsetForResource(level);
            },
            _positionEvent: function (event, group, range, rangeCount, start, end, rangeIndex) {
                var view = this._view;
                var isMobile = view._isMobile();
                if (rangeCount > 1) {
                    if (rangeIndex === 0) {
                        end = range.end.endDate();
                    } else if (rangeIndex == rangeCount - 1) {
                        start = range.start.startDate();
                    } else {
                        start = range.start.startDate();
                        end = range.end.endDate();
                    }
                }
                var occurrence = event.clone({
                    start: start,
                    end: end,
                    head: range.head,
                    tail: range.tail
                });
                if (isMobile) {
                    view._positionMobileEvent(range, view._createEventElement(occurrence), group);
                } else {
                    view._positionEvent(range, view._createEventElement(occurrence), group);
                }
            },
            _addDaySlotCollections: function (groupCount, tableRows, startDate) {
                var view = this._view;
                var columnCount = NUMBER_OF_COLUMNS;
                var rowCount = NUMBER_OF_ROWS;
                for (var groupIndex = 0; groupIndex < groupCount; groupIndex++) {
                    var cellCount = 0;
                    var rowMultiplier = 0;
                    if (view._isVerticallyGrouped()) {
                        rowMultiplier = groupIndex;
                    }
                    for (var rowIndex = rowMultiplier * rowCount; rowIndex < (rowMultiplier + 1) * rowCount; rowIndex++) {
                        var group = view.groups[groupIndex];
                        var collection = group.addDaySlotCollection(kendo.date.addDays(startDate, cellCount), kendo.date.addDays(startDate, cellCount + columnCount));
                        var tableRow = tableRows[rowIndex];
                        var cells = tableRow.children;
                        var cellMultiplier = 0;
                        tableRow.setAttribute('role', 'row');
                        if (!view._isVerticallyGrouped()) {
                            cellMultiplier = groupIndex;
                        }
                        for (var cellIndex = cellMultiplier * columnCount; cellIndex < (cellMultiplier + 1) * columnCount; cellIndex++) {
                            var cell = cells[cellIndex];
                            view.addDaySlot(collection, cell, startDate, cellCount);
                            cellCount++;
                        }
                    }
                }
            },
            _changePeriodGroupIndex: function (reverse) {
                var view = this._view;
                return reverse ? view.groups.length - 1 : 0;
            },
            _createResizeHint: function (range) {
                var view = this._view;
                var left = range.startSlot().offsetLeft;
                var top = range.start.offsetTop;
                var width = range.innerWidth();
                var height = range.start.clientHeight - 2;
                var hint = SchedulerView.fn._createResizeHint.call(view, left, top, width, height);
                view._appendResizeHint(hint);
            },
            _createMoveHint: function (range, event) {
                var view = this._view;
                var startSlot = range.startSlot();
                var endSlot = range.endSlot();
                var hint = view._createEventElement(event.clone({
                    head: range.head,
                    tail: range.tail
                }));
                hint.css({
                    left: startSlot.offsetLeft + 2,
                    top: startSlot.offsetTop + startSlot.firstChildHeight,
                    height: view.options.eventHeight,
                    width: range.innerWidth() - (startSlot.index !== endSlot.index ? 5 : 4)
                });
                hint.addClass('k-event-drag-hint');
                if (event.inverseColor) {
                    hint.addClass(INVERSE_COLOR_CLASS);
                }
                view._appendMoveHint(hint);
            }
        });
        var MonthGroupedByDateView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _verticalRowCountForLevel: function () {
                return 1;
            },
            _horizontalGroupCountForLevel: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level + 1) / NUMBER_OF_COLUMNS;
            },
            _createRows: function (start, startIdx, horizontalGroupCount) {
                var view = this._view;
                var cellsPerRow = NUMBER_OF_COLUMNS;
                var isVerticallyGrouped = view._isVerticallyGrouped();
                var html = '';
                var dateIdx = 0;
                if (isVerticallyGrouped) {
                    var verticalStart = new Date(start);
                    var groupCount = view._groupCount();
                    for (dateIdx; dateIdx < NUMBER_OF_ROWS; dateIdx++) {
                        html += view._createRow(verticalStart, startIdx, groupCount, dateIdx);
                        verticalStart = kendo.date.addDays(verticalStart, cellsPerRow);
                    }
                    start = kendo.date.nextDay(start);
                } else {
                    for (dateIdx; dateIdx < cellsPerRow; dateIdx++) {
                        html += view._createRow(start, startIdx, horizontalGroupCount, dateIdx);
                        start = kendo.date.nextDay(start);
                    }
                    start = kendo.date.addDays(start, cellsPerRow);
                }
                return html;
            },
            _adjustStartDate: function (start, isLastRow) {
                var view = this._view;
                var isVerticallyGrouped = view._isVerticallyGrouped();
                if (isVerticallyGrouped) {
                    if (isLastRow) {
                        return kendo.date.addDays(start, NUMBER_OF_COLUMNS * (NUMBER_OF_ROWS - 1) + 1);
                    } else {
                        return kendo.date.nextDay(start);
                    }
                }
                return kendo.date.addDays(start, NUMBER_OF_COLUMNS);
            },
            _getContent: function (content, startDate, resources, cellIdx) {
                if (cellIdx === 0) {
                    return content({
                        date: startDate,
                        resources: resources
                    });
                }
                return '';
            },
            _getTimeSlotByPosition: function (x, y, groupIndex) {
                var group = this._view.groups[groupIndex];
                return group.daySlotByPosition(x, y, true);
            },
            _nextSlotStartDate: function (startDate) {
                return startDate;
            },
            _getCalendarRowsLength: function () {
                var view = this._view;
                var isVerticallyGrouped = view._isVerticallyGrouped();
                return isVerticallyGrouped ? NUMBER_OF_COLUMNS : NUMBER_OF_ROWS;
            },
            _createRowsLayout: function (resources, rows, groupHeaderTemplate, columns) {
                var view = this._view;
                return view._createDateLayout(columns, null, false);
            },
            _createVerticalColumnsLayout: function (resources, rows, groupHeaderTemplate) {
                var view = this._view;
                var resource = resources[0];
                var configuration = [];
                var data = resource.dataSource.view();
                for (var dataIndex = 0; dataIndex < data.length * NUMBER_OF_ROWS; dataIndex++) {
                    var obj = {
                        text: groupHeaderTemplate({
                            text: kendo.htmlEncode(kendo.getter(resource.dataTextField)(data[dataIndex % data.length])),
                            color: kendo.getter(resource.dataColorField)(data[dataIndex % data.length]),
                            field: resource.field,
                            title: resource.title,
                            name: resource.name,
                            value: kendo.getter(resource.dataValueField)(data[dataIndex % data.length])
                        }),
                        className: 'k-slot-cell'
                    };
                    obj.columns = view._createColumnsLayout(resources.slice(1), null, groupHeaderTemplate);
                    configuration.push(obj);
                }
                return configuration;
            },
            _createColumnsLayout: function (resources, columns, groupHeaderTemplate, subColumns) {
                var view = this._view;
                return view._createColumnsLayout(resources, columns, groupHeaderTemplate, subColumns, true);
            },
            _verticalGroupCount: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level) / NUMBER_OF_ROWS;
            },
            _horizontalGroupCount: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level) / NUMBER_OF_COLUMNS;
            },
            _positionEvent: function (event, group, range, rangeCount, start, end) {
                var view = this._view;
                var startIndex = range.start.index;
                var endIndex = range.end.index;
                var isMobile = view._isMobile();
                for (var i = range.start.index; i <= range.end.index; i++) {
                    var currentSlot = range.collection._slots[i];
                    var dateRange = group.daySlotRanges(currentSlot.start, currentSlot.start, true)[0];
                    var occurrence = event.clone({
                        start: i === startIndex ? start : currentSlot.startDate(),
                        end: i === endIndex ? end : currentSlot.endDate(),
                        head: i !== endIndex || range.head,
                        tail: i !== startIndex || range.tail
                    });
                    if (isMobile) {
                        view._positionMobileEvent(dateRange, view._createEventElement(occurrence), group);
                    } else {
                        view._positionEvent(dateRange, view._createEventElement(occurrence), group);
                    }
                }
            },
            _addDaySlotCollections: function (groupCount, tableRows, startDate) {
                var view = this._view;
                var columnCount = NUMBER_OF_COLUMNS;
                var rowCount = NUMBER_OF_ROWS;
                var isVerticallyGrouped = view._isVerticallyGrouped();
                for (var dateIndex = 0; dateIndex < columnCount; dateIndex++) {
                    for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) {
                        var groupIndex = 0;
                        var currentTableIndex = isVerticallyGrouped ? dateIndex : rowIndex;
                        var tableRow = tableRows[currentTableIndex];
                        var cells = tableRow.children;
                        var cellMultiplier = 0;
                        tableRow.setAttribute('role', 'row');
                        if (!view._isVerticallyGrouped()) {
                            cellMultiplier = dateIndex;
                        }
                        for (var cellIndex = cellMultiplier * groupCount; cellIndex < (cellMultiplier + 1) * groupCount; cellIndex++) {
                            var cellCount = rowIndex * columnCount + dateIndex;
                            var currentCellIndex = isVerticallyGrouped ? cellIndex + rowIndex * groupCount : cellIndex;
                            var cell = cells[currentCellIndex];
                            var currentGroupIndex = isVerticallyGrouped ? cellIndex : groupIndex;
                            var group = view.groups[currentGroupIndex];
                            var collection;
                            if (dateIndex === 0) {
                                collection = group.addDaySlotCollection(kendo.date.addDays(startDate, cellCount), kendo.date.addDays(startDate, cellCount + columnCount));
                            } else {
                                collection = group._daySlotCollections[rowIndex];
                            }
                            view.addDaySlot(collection, cell, startDate, cellCount);
                            groupIndex++;
                        }
                    }
                }
            },
            _changePeriodGroupIndex: function (reverse, vertical, selectionGroupIndex) {
                var view = this._view;
                if (vertical && view._isVerticallyGrouped()) {
                    return reverse ? view.groups.length - 1 : 0;
                }
                return selectionGroupIndex;
            },
            _createResizeHint: function (range) {
                var view = this._view;
                var left, top, width, height, hint;
                if (view._isVerticallyGrouped()) {
                    left = range.startSlot().offsetLeft;
                    top = range.start.offsetTop;
                    width = range.startSlot().offsetWidth;
                    height = range.endSlot().offsetTop + range.startSlot().offsetHeight - range.startSlot().offsetTop - 2;
                    hint = SchedulerView.fn._createResizeHint.call(view, left, top, width, height);
                    view._appendResizeHint(hint);
                } else {
                    for (var slotIdx = range.startSlot().index; slotIdx <= range.endSlot().index; slotIdx++) {
                        var slot = range.collection._slots[slotIdx];
                        left = slot.offsetLeft;
                        top = slot.offsetTop;
                        width = slot.offsetWidth;
                        height = slot.offsetHeight - 2;
                        hint = SchedulerView.fn._createResizeHint.call(view, left, top, width, height);
                        view._appendResizeHint(hint);
                    }
                }
            },
            _createMoveHint: function (range, event) {
                var view = this._view;
                var startSlot = range.startSlot();
                var endSlot = range.endSlot();
                for (var slotIdx = startSlot.index; slotIdx <= endSlot.index; slotIdx++) {
                    var slot = range.collection._slots[slotIdx];
                    var hint = view._createEventElement(event.clone({
                        head: range.head,
                        tail: range.tail
                    }));
                    hint.css({
                        left: slot.offsetLeft,
                        top: slot.offsetTop + slot.firstChildHeight,
                        height: view.options.eventHeight,
                        width: slot.offsetWidth - 2
                    });
                    hint.addClass('k-event-drag-hint');
                    if (event.inverseColor) {
                        hint.addClass(INVERSE_COLOR_CLASS);
                    }
                    view._appendMoveHint(hint);
                }
            }
        });
        kendo.ui.scheduler.MonthGroupedView = MonthGroupedView;
        kendo.ui.scheduler.MonthGroupedByDateView = MonthGroupedByDateView;
        ui.MonthView = SchedulerView.extend({
            init: function (element, options) {
                var that = this;
                SchedulerView.fn.init.call(that, element, options);
                that._groupedView = that._getGroupedView();
                that.title = that.options.title;
                that._templates();
                that._editable();
                that._renderLayout(that.options.date);
                that._groups();
            },
            name: 'month',
            _getGroupedView: function () {
                if (this._isGroupedByDate()) {
                    return new kendo.ui.scheduler.MonthGroupedByDateView(this);
                } else {
                    return new kendo.ui.scheduler.MonthGroupedView(this);
                }
            },
            _updateDirection: function (selection, ranges, multiple, reverse, vertical) {
                if (multiple) {
                    var startSlot = ranges[0].start;
                    var endSlot = ranges[ranges.length - 1].end;
                    var isSameSlot = startSlot.index === endSlot.index;
                    var isSameCollection = startSlot.collectionIndex === endSlot.collectionIndex;
                    var updateDirection;
                    if (vertical) {
                        updateDirection = isSameSlot && isSameCollection || isSameCollection;
                    } else {
                        updateDirection = isSameSlot && isSameCollection;
                    }
                    if (updateDirection) {
                        selection.backward = reverse;
                    }
                }
            },
            _changeDate: function (selection, slot, previous) {
                var group = this.groups[selection.groupIndex];
                var collections, index;
                if (previous) {
                    collections = group._getCollections(group.daySlotCollectionCount());
                    index = slot.collectionIndex - 1;
                    if (index >= 0) {
                        return collections[index]._slots[collections[index]._slots.length - 1];
                    }
                } else {
                    collections = group._getCollections(group.daySlotCollectionCount());
                    index = slot.collectionIndex + 1;
                    var slotIndex = 0;
                    if (collections[index] && collections[index]._slots[slotIndex]) {
                        return collections[index]._slots[slotIndex];
                    }
                }
            },
            _getNextHorizontalRange: function (group, method, horizontalRange) {
                var isVertical = this._isVerticallyGrouped();
                horizontalRange.startSlot = group[method](horizontalRange.startSlot, isVertical);
                horizontalRange.endSlot = group[method](horizontalRange.endSlot, isVertical);
                return horizontalRange;
            },
            _getNextVerticalRange: function (group, method, verticalRange, multiple) {
                var isVertical = this._isVerticallyGrouped() && this._isGroupedByDate();
                verticalRange.startSlot = group[method](verticalRange.startSlot, multiple, isVertical);
                verticalRange.endSlot = group[method](verticalRange.endSlot, multiple, isVertical);
                return verticalRange;
            },
            _changeViewPeriod: function (selection, reverse, vertical) {
                var pad = vertical ? 7 : 1;
                var newStart, newEnd;
                if (reverse) {
                    pad *= -1;
                }
                newStart = kendo.date.addDays(selection.start, pad);
                newEnd = kendo.date.addDays(selection.end, pad);
                if (this._isInRange(newStart, newEnd)) {
                    return false;
                }
                selection.start = newStart;
                selection.end = newEnd;
                if (!vertical || vertical && this._isVerticallyGrouped()) {
                    selection.groupIndex = this._groupedView._changePeriodGroupIndex(reverse, vertical, selection.groupIndex);
                }
                selection.events = [];
                return true;
            },
            _continuousSlot: function (selection, ranges, reverse) {
                var index = selection.backward ? 0 : ranges.length - 1;
                var group = this.groups[selection.groupIndex];
                return group.continuousSlot(ranges[index].start, reverse);
            },
            _changeGroupContinuously: function (selection, continuousSlot, multiple, reverse) {
                if (!multiple) {
                    var groupIndex = selection.groupIndex;
                    var lastGroupIndex = this.groups.length - 1;
                    var vertical = this._isVerticallyGrouped();
                    var group = this.groups[groupIndex];
                    if (!continuousSlot && vertical) {
                        continuousSlot = group[reverse ? 'lastSlot' : 'firstSlot']();
                        groupIndex += reverse ? -1 : 1;
                    } else if (continuousSlot && !vertical) {
                        groupIndex = reverse ? lastGroupIndex : 0;
                    }
                    if (groupIndex < 0 || groupIndex > lastGroupIndex) {
                        groupIndex = reverse ? lastGroupIndex : 0;
                        continuousSlot = null;
                    }
                    selection.groupIndex = groupIndex;
                }
                return continuousSlot;
            },
            _normalizeHorizontalSelection: function (selection, ranges, reverse) {
                var slot;
                if (reverse) {
                    slot = ranges[0].start;
                } else {
                    slot = ranges[ranges.length - 1].end;
                }
                return slot;
            },
            _normalizeVerticalSelection: function (selection, ranges) {
                var slot;
                if (selection.backward) {
                    slot = ranges[0].start;
                } else {
                    slot = ranges[ranges.length - 1].end;
                }
                return slot;
            },
            _templates: function () {
                var options = this.options, settings = extend({}, kendo.Template, options.templateSettings);
                this.eventTemplate = this._eventTmpl(options.eventTemplate, EVENT_WRAPPER_STRING);
                this.dayTemplate = kendo.template(options.dayTemplate, settings);
                this.groupHeaderTemplate = kendo.template(options.groupHeaderTemplate, settings);
            },
            dateForTitle: function () {
                return kendo.format(this.options.selectedDateFormat, this._firstDayOfMonth, this._lastDayOfMonth);
            },
            shortDateForTitle: function () {
                return kendo.format(this.options.selectedShortDateFormat, this._firstDayOfMonth, this._lastDayOfMonth);
            },
            mobileDateForTitle: function () {
                return kendo.format(this.options.selectedMobileDateFormat, this._firstDayOfMonth, this._lastDayOfMonth);
            },
            nextDate: function () {
                return kendo.date.nextDay(this._lastDayOfMonth);
            },
            previousDate: function () {
                return kendo.date.previousDay(this._firstDayOfMonth);
            },
            startDate: function () {
                return this._startDate;
            },
            endDate: function () {
                return this._endDate;
            },
            _renderLayout: function (date) {
                var that = this;
                this._firstDayOfMonth = kendo.date.firstDayOfMonth(date);
                this._lastDayOfMonth = kendo.date.lastDayOfMonth(date);
                this._startDate = firstVisibleMonthDay(date, this.calendarInfo());
                this.createLayout(this._layout());
                this._content();
                this.refreshLayout();
                this.content.on('click' + NS, '.k-nav-day,.k-more-events', function (e) {
                    var offset = $(e.currentTarget).offset();
                    var slot = that._slotByPosition(offset.left, offset.top);
                    e.preventDefault();
                    that.trigger('navigate', {
                        view: 'day',
                        date: slot.startDate()
                    });
                });
                this._footer();
            },
            _editable: function () {
                if (this.options.editable) {
                    if (this._isMobile()) {
                        this._touchEditable();
                    } else {
                        this._mouseEditable();
                    }
                }
            },
            _mouseEditable: function () {
                var that = this;
                that.element.on('click' + NS, '.k-scheduler-monthview .k-event a:has(.k-i-close)', function (e) {
                    that.trigger('remove', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                    e.preventDefault();
                });
                if (that.options.editable.create !== false) {
                    that.element.on('dblclick' + NS, '.k-scheduler-monthview .k-scheduler-content td', function (e) {
                        var offset = $(e.currentTarget).offset();
                        var slot = that._slotByPosition(offset.left, offset.top);
                        if (slot) {
                            var resourceInfo = that._resourceBySlot(slot);
                            that.trigger('add', {
                                eventInfo: extend({
                                    isAllDay: true,
                                    start: slot.startDate(),
                                    end: slot.startDate()
                                }, resourceInfo)
                            });
                        }
                        e.preventDefault();
                    });
                }
                if (that.options.editable.update !== false) {
                    that.element.on('dblclick' + NS, '.k-scheduler-monthview .k-event', function (e) {
                        that.trigger('edit', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                        e.preventDefault();
                    });
                }
            },
            _touchEditable: function () {
                var that = this;
                var threshold = 0;
                if (kendo.support.mobileOS.android) {
                    threshold = 5;
                }
                if (that.options.editable.create !== false) {
                    that._addUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        useClickAsTap: !kendo.support.browser.edge,
                        filter: '.k-scheduler-monthview .k-scheduler-content td',
                        tap: function (e) {
                            if (that._scrolling) {
                                return;
                            }
                            var offset = $(e.target).offset();
                            var slot = that._slotByPosition(offset.left, offset.top);
                            if (slot) {
                                var resourceInfo = that._resourceBySlot(slot);
                                that.trigger('add', {
                                    eventInfo: extend({
                                        isAllDay: true,
                                        start: slot.startDate(),
                                        end: slot.startDate()
                                    }, resourceInfo)
                                });
                            }
                            e.preventDefault();
                        }
                    });
                }
            },
            selectionByElement: function (cell) {
                var offset = $(cell).offset();
                return this._slotByPosition(offset.left, offset.top);
            },
            _columnCountForLevel: function (level) {
                var columnLevel = this.columnLevels[level];
                return columnLevel ? columnLevel.length : 0;
            },
            _rowCountForLevel: function (level) {
                var rowLevel = this.rowLevels[level];
                return rowLevel ? rowLevel.length : 0;
            },
            _content: function () {
                var html = '<tbody>';
                var verticalGroupCount = 1;
                var groupedView = this._groupedView;
                var resources = this.groupedResources;
                if (resources.length) {
                    if (this._isVerticallyGrouped()) {
                        verticalGroupCount = groupedView._verticalRowCountForLevel(resources.length - 1);
                    }
                }
                for (var verticalGroupIdx = 0; verticalGroupIdx < verticalGroupCount; verticalGroupIdx++) {
                    html += this._createCalendar(verticalGroupIdx);
                }
                html += '</tbody>';
                this.content.find('table').html(html);
            },
            _createCalendar: function (verticalGroupIndex) {
                var start = this.startDate();
                var cellCount = NUMBER_OF_COLUMNS * NUMBER_OF_ROWS;
                var cellsPerRow = NUMBER_OF_COLUMNS;
                var weekStartDates = [start];
                var html = '';
                var horizontalGroupCount = 1;
                var isVerticallyGrouped = this._isVerticallyGrouped();
                var groupedView = this._groupedView;
                var resources = this.groupedResources;
                if (resources.length) {
                    if (!isVerticallyGrouped) {
                        horizontalGroupCount = groupedView._horizontalGroupCountForLevel(resources.length - 1);
                    }
                }
                this._slotIndices = {};
                var calendarRowsLength = groupedView._getCalendarRowsLength(cellsPerRow, cellCount);
                for (var rowIdx = 0; rowIdx < calendarRowsLength; rowIdx++) {
                    html += '<tr>';
                    weekStartDates.push(start);
                    var startIdx = rowIdx * cellsPerRow;
                    html += groupedView._createRows(start, startIdx, horizontalGroupCount, verticalGroupIndex);
                    start = groupedView._adjustStartDate(start, rowIdx === calendarRowsLength - 1);
                    html += '</tr>';
                }
                this._weekStartDates = weekStartDates;
                this._endDate = kendo.date.previousDay(start);
                return html;
            },
            _createRow: function (startDate, startIdx, cellsPerRow, groupIndex) {
                var that = this;
                var min = that._firstDayOfMonth;
                var max = that._lastDayOfMonth;
                var content = that.dayTemplate;
                var classes = '';
                var html = '';
                var groupedView = this._groupedView;
                var resources = function () {
                    return that._resourceBySlot({ groupIndex: groupIndex });
                };
                for (var cellIdx = 0; cellIdx < cellsPerRow; cellIdx++) {
                    classes = '';
                    if (kendo.date.isToday(startDate)) {
                        classes += 'k-today';
                    }
                    if (!kendo.date.isInDateRange(startDate, min, max)) {
                        classes += ' k-other-month';
                    }
                    html += '<td ';
                    if (classes !== '') {
                        html += 'class="' + classes + '"';
                    }
                    html += '>';
                    html += groupedView._getContent(content, startDate, resources, cellIdx);
                    html += '</td>';
                    that._slotIndices[getDate(startDate).getTime()] = startIdx + cellIdx;
                    startDate = groupedView._nextSlotStartDate(startDate);
                }
                return html;
            },
            _layout: function () {
                var calendarInfo = this.calendarInfo();
                var weekDayNames = this._isMobile() ? calendarInfo.days.namesShort.map(function (name) {
                    return name[0];
                }) : calendarInfo.days.names;
                var names = shiftArray(weekDayNames, calendarInfo.firstDay);
                var columns = $.map(names, function (value) {
                    return { text: value };
                });
                var resources = this.groupedResources;
                var rows;
                var groupedView = this._groupedView;
                if (resources.length) {
                    if (this._isVerticallyGrouped()) {
                        var inner = [];
                        for (var idx = 0; idx < 6; idx++) {
                            inner.push({
                                text: '<div>&nbsp;</div>',
                                className: 'k-hidden k-slot-cell'
                            });
                        }
                        rows = groupedView._createRowsLayout(resources, inner, this.groupHeaderTemplate, columns);
                        columns = groupedView._createVerticalColumnsLayout(resources, inner, this.groupHeaderTemplate, columns);
                    } else {
                        columns = groupedView._createColumnsLayout(resources, columns, this.groupHeaderTemplate, columns);
                    }
                }
                return {
                    columns: columns,
                    rows: rows
                };
            },
            _createEventElement: function (event) {
                var options = this.options;
                var editable = options.editable;
                var isMobile = this._isMobile();
                event.showDelete = editable && editable.destroy !== false && !isMobile;
                event.resizable = editable && editable.resize !== false && !isMobile;
                event.ns = kendo.ns;
                event.resources = this.eventResources(event);
                event.inverseColor = false;
                event.messages = options.messages || { destroy: 'Delete' };
                var element = $(this.eventTemplate(event));
                this.angular('compile', function () {
                    return {
                        elements: element,
                        data: [{ dataItem: event }]
                    };
                });
                return element;
            },
            _isInDateSlot: function (event) {
                var groups = this.groups[0];
                var slotStart = groups.firstSlot().start;
                var slotEnd = groups.lastSlot().end - 1;
                var startTime = kendo.date.toUtcTime(event.start);
                var endTime = kendo.date.toUtcTime(event.end);
                return (isInDateRange(startTime, slotStart, slotEnd) || isInDateRange(endTime, slotStart, slotEnd) || isInDateRange(slotStart, startTime, endTime) || isInDateRange(slotEnd, startTime, endTime)) && (!isInDateRange(endTime, slotStart, slotStart) || isInDateRange(endTime, startTime, startTime) || event.isAllDay);
            },
            _slotIndex: function (date) {
                return this._slotIndices[getDate(date).getTime()];
            },
            _positionMobileEvent: function (slotRange, element, group) {
                var startSlot = slotRange.start;
                if (slotRange.start.offsetLeft > slotRange.end.offsetLeft) {
                    startSlot = slotRange.end;
                }
                var startIndex = slotRange.start.index;
                var endIndex = startIndex;
                var eventCount = 3;
                var events = SchedulerView.collidingEvents(slotRange.events(), startIndex, endIndex);
                events.push({
                    element: element,
                    start: startIndex,
                    end: endIndex
                });
                var rows = SchedulerView.createRows(events);
                var slot = slotRange.collection.at(startIndex);
                var container = slot.container;
                if (!container) {
                    container = $(kendo.format('<div class="k-events-container" style="top:{0};left:{1};width:{2}"/>', startSlot.offsetTop + startSlot.firstChildTop + startSlot.firstChildHeight + 'px', startSlot.offsetLeft + 'px', startSlot.offsetWidth + 'px'));
                    slot.container = container;
                    this.content[0].appendChild(container[0]);
                }
                if (rows.length <= eventCount) {
                    slotRange.addEvent({
                        element: element,
                        start: startIndex,
                        end: endIndex,
                        groupIndex: startSlot.groupIndex
                    });
                    group._continuousEvents.push({
                        element: element,
                        uid: element.attr(kendo.attr('uid')),
                        start: slotRange.start,
                        end: slotRange.end
                    });
                    container[0].appendChild(element[0]);
                }
            },
            _positionEvent: function (slotRange, element, group) {
                var eventHeight = this.options.eventHeight;
                var startSlot = slotRange.start;
                if (slotRange.start.offsetLeft > slotRange.end.offsetLeft) {
                    startSlot = slotRange.end;
                }
                var startIndex = slotRange.start.index;
                var endIndex = slotRange.end.index;
                var eventCount = startSlot.eventCount;
                var events = SchedulerView.collidingEvents(slotRange.events(), startIndex, endIndex);
                var rightOffset = startIndex !== endIndex ? 5 : 4;
                events.push({
                    element: element,
                    start: startIndex,
                    end: endIndex
                });
                var rows = SchedulerView.createRows(events);
                for (var idx = 0, length = Math.min(rows.length, eventCount); idx < length; idx++) {
                    var rowEvents = rows[idx].events;
                    var eventTop = startSlot.offsetTop + startSlot.firstChildTop + startSlot.firstChildHeight + idx * eventHeight + 3 * idx + 'px';
                    for (var j = 0, eventLength = rowEvents.length; j < eventLength; j++) {
                        rowEvents[j].element[0].style.top = eventTop;
                    }
                }
                if (rows.length > eventCount) {
                    for (var slotIndex = startIndex; slotIndex <= endIndex; slotIndex++) {
                        var collection = slotRange.collection;
                        var slot = collection.at(slotIndex);
                        if (slot.more) {
                            continue;
                        }
                        slot.more = $(MORE_BUTTON_TEMPLATE({
                            ns: kendo.ns,
                            start: slotIndex,
                            end: slotIndex,
                            width: slot.clientWidth - 2,
                            left: slot.offsetLeft + 2,
                            top: slot.offsetTop + slot.firstChildTop + slot.firstChildHeight + eventCount * eventHeight + 3 * eventCount
                        }));
                        this.content[0].appendChild(slot.more[0]);
                    }
                } else {
                    slotRange.addEvent({
                        element: element,
                        start: startIndex,
                        end: endIndex,
                        groupIndex: startSlot.groupIndex
                    });
                    element[0].style.width = slotRange.innerWidth() - rightOffset + 'px';
                    element[0].style.left = startSlot.offsetLeft + 2 + 'px';
                    element[0].style.height = eventHeight + 'px';
                    group._continuousEvents.push({
                        element: element,
                        uid: element.attr(kendo.attr('uid')),
                        start: slotRange.start,
                        end: slotRange.end
                    });
                    element.appendTo(this.content);
                    this._inverseEventColor(element);
                }
            },
            _slotByPosition: function (x, y) {
                var offset = this.content.offset();
                x -= offset.left;
                y -= offset.top;
                y += this.content[0].scrollTop;
                x += this.content[0].scrollLeft;
                x = Math.ceil(x);
                y = Math.ceil(y);
                for (var groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                    var slot = this._groupedView._getTimeSlotByPosition(x, y, groupIndex);
                    if (slot) {
                        return slot;
                    }
                }
                return null;
            },
            _appendResizeHint: function (hint) {
                hint.appendTo(this.content);
                this._resizeHint = this._resizeHint.add(hint);
            },
            _updateResizeHint: function (event, groupIndex, startTime, endTime) {
                this._removeResizeHint();
                var group = this.groups[groupIndex];
                var ranges = group.ranges(startTime, endTime, true, event.isAllDay);
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    this._groupedView._createResizeHint(ranges[rangeIndex]);
                }
                this._resizeHint.find('.k-label-top,.k-label-bottom').text('');
                this._resizeHint.first().addClass('k-first').find('.k-label-top').text(kendo.toString(kendo.timezone.toLocalDate(startTime), 'M/dd'));
                this._resizeHint.last().addClass('k-last').find('.k-label-bottom').text(kendo.toString(kendo.timezone.toLocalDate(endTime), 'M/dd'));
            },
            _updateMoveHint: function (event, groupIndex, distance) {
                var start = kendo.date.toUtcTime(event.start) + distance;
                var end = start + event.duration();
                var group = this.groups[groupIndex];
                var ranges = group.ranges(start, end, true, event.isAllDay);
                this._removeMoveHint(event.uid);
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    this._groupedView._createMoveHint(ranges[rangeIndex], event);
                }
            },
            _appendMoveHint: function (hint) {
                hint.appendTo(this.content);
                this._moveHint = this._moveHint.add(hint);
            },
            _groups: function () {
                var groupCount = this._groupCount();
                var tableRows = this.content[0].getElementsByTagName('tr');
                var startDate = this.startDate();
                this.groups = [];
                for (var idx = 0; idx < groupCount; idx++) {
                    this._addResourceView(idx);
                }
                this._groupedView._addDaySlotCollections(groupCount, tableRows, startDate);
            },
            addDaySlot: function (collection, cell, startDate, cellCount) {
                var clientHeight = cell.clientHeight;
                var firstChildHeight = cell.children.length ? cell.children[0].offsetHeight + 3 : 0;
                var start = kendo.date.addDays(startDate, cellCount);
                var end = kendo.date.MS_PER_DAY;
                if (startDate.getHours() !== start.getHours()) {
                    end += (startDate.getHours() - start.getHours()) * kendo.date.MS_PER_HOUR;
                }
                start = kendo.date.toUtcTime(start);
                end += start;
                var eventCount = Math.floor((clientHeight - firstChildHeight - this.options.moreButtonHeight) / (this.options.eventHeight + 3));
                cell.setAttribute('role', 'gridcell');
                cell.setAttribute('aria-selected', false);
                collection.addDaySlot(cell, start, end, eventCount);
            },
            render: function (events) {
                this.content.children('.k-event,.k-more-events,.k-events-container').remove();
                this._groups();
                events = new kendo.data.Query(events).sort([
                    {
                        field: 'start',
                        dir: 'asc'
                    },
                    {
                        field: 'end',
                        dir: 'desc'
                    }
                ]).toArray();
                var resources = this.groupedResources;
                if (resources.length) {
                    this._renderGroups(events, resources, 0, 1);
                } else {
                    this._renderEvents(events, 0);
                }
                this.refreshLayout();
                this.trigger('activate');
            },
            _renderEvents: function (events, groupIndex) {
                var event;
                var idx;
                var length;
                var range;
                var start;
                var end;
                for (idx = 0, length = events.length; idx < length; idx++) {
                    event = events[idx];
                    if (this._isInDateSlot(event)) {
                        var group = this.groups[groupIndex];
                        var view = this._groupedView._view;
                        var isMobile = view._isMobile();
                        if (!group._continuousEvents) {
                            group._continuousEvents = [];
                        }
                        var ranges = group.slotRanges(event, true);
                        var rangeCount = ranges.length;
                        if (isMobile) {
                            range = ranges[0];
                            start = range.start.start;
                            end = range.end.end;
                            var rangeStart = new Date(range.start.start);
                            var rangeEnd = ranges[ranges.length - 1].end.end;
                            var newStart = new Date(rangeStart);
                            var newEnd = new Date(end);
                            while (rangeStart.getTime() <= rangeEnd && event.end >= kendo.timezone.toLocalDate(rangeStart) && event.start <= kendo.timezone.toLocalDate(rangeEnd)) {
                                var dateRange = group.daySlotRanges(newStart.getTime(), newEnd.getTime(), true)[0];
                                newEnd.setDate(newEnd.getDate() + 1);
                                newStart.setDate(newStart.getDate() + 1);
                                if (dateRange) {
                                    dateRange.head = null;
                                    dateRange.middle = null;
                                    dateRange.tail = null;
                                    this._groupedView._positionEvent(event, group, dateRange, 1, start, end, 0);
                                }
                                rangeStart = kendo.date.addDays(rangeStart, 1);
                            }
                        } else {
                            for (var rangeIndex = 0; rangeIndex < rangeCount; rangeIndex++) {
                                range = ranges[rangeIndex];
                                start = event.start;
                                end = event.end;
                                this._groupedView._positionEvent(event, group, range, rangeCount, start, end, rangeIndex);
                            }
                        }
                    }
                }
            },
            _renderGroups: function (events, resources, offset, columnLevel) {
                var resource = resources[0];
                if (resource) {
                    var view = resource.dataSource.view();
                    for (var itemIdx = 0; itemIdx < view.length; itemIdx++) {
                        var value = this._resourceValue(resource, view[itemIdx]);
                        var tmp = new kendo.data.Query(events).filter({
                            field: resource.field,
                            operator: SchedulerView.groupEqFilter(value)
                        }).toArray();
                        if (resources.length > 1) {
                            offset = this._renderGroups(tmp, resources.slice(1), offset++, columnLevel + 1);
                        } else {
                            this._renderEvents(tmp, offset++);
                        }
                    }
                }
                return offset;
            },
            _groupCount: function () {
                var resources = this.groupedResources;
                var groupedView = this._groupedView;
                if (resources.length) {
                    if (this._isVerticallyGrouped()) {
                        return groupedView._verticalGroupCount(resources.length - 1);
                    } else {
                        return groupedView._horizontalGroupCount(resources.length);
                    }
                }
                return 1;
            },
            _columnOffsetForResource: function (index) {
                return this._columnCountForLevel(index) / this._columnCountForLevel(index - 1);
            },
            destroy: function () {
                if (this.table) {
                    this.table.removeClass('k-scheduler-monthview');
                }
                if (this.content) {
                    this.content.off(NS);
                }
                if (this.element) {
                    this.element.off(NS);
                }
                SchedulerView.fn.destroy.call(this);
                if (this._isMobile() && this.options.editable) {
                    if (this.options.editable.create !== false) {
                        this._addUserEvents.destroy();
                    }
                }
            },
            events: [
                'remove',
                'add',
                'edit',
                'navigate'
            ],
            options: {
                title: 'Month',
                name: 'month',
                eventHeight: 25,
                moreButtonHeight: 13,
                editable: true,
                selectedDateFormat: '{0:y}',
                selectedShortDateFormat: '{0:y}',
                selectedMobileDateFormat: '{0:MMMM}',
                groupHeaderTemplate: '#=text#',
                dayTemplate: DAY_TEMPLATE,
                eventTemplate: EVENT_TEMPLATE
            }
        });
        function shiftArray(array, idx) {
            return array.slice(idx).concat(array.slice(0, idx));
        }
        function firstVisibleMonthDay(date, calendarInfo) {
            var firstDay = calendarInfo.firstDay, firstVisibleDay = new Date(date.getFullYear(), date.getMonth(), 0, date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
            while (firstVisibleDay.getDay() != firstDay) {
                kendo.date.setTime(firstVisibleDay, -1 * MS_PER_DAY);
            }
            return firstVisibleDay;
        }
        function isInDateRange(value, min, max) {
            var msMin = min, msMax = max, msValue;
            msValue = value;
            return msValue >= msMin && msValue <= msMax;
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.recurrence', [
        'kendo.dropdownlist',
        'kendo.datepicker',
        'kendo.numerictextbox'
    ], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.recurrence',
        name: 'Recurrence',
        category: 'web',
        depends: [
            'dropdownlist',
            'datepicker',
            'numerictextbox'
        ],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, timezone = kendo.timezone, Class = kendo.Class, ui = kendo.ui, Widget = ui.Widget, DropDownList = ui.DropDownList, kendoDate = kendo.date, setTime = kendoDate.setTime, setDayOfWeek = kendoDate.setDayOfWeek, adjustDST = kendoDate.adjustDST, firstDayOfMonth = kendoDate.firstDayOfMonth, getMilliseconds = kendoDate.getMilliseconds, DAYS_IN_LEAPYEAR = [
                0,
                31,
                60,
                91,
                121,
                152,
                182,
                213,
                244,
                274,
                305,
                335,
                366
            ], DAYS_IN_YEAR = [
                0,
                31,
                59,
                90,
                120,
                151,
                181,
                212,
                243,
                273,
                304,
                334,
                365
            ], MONTHS = [
                31,
                28,
                31,
                30,
                31,
                30,
                31,
                31,
                30,
                31,
                30,
                31
            ], WEEK_DAYS = {
                0: 'SU',
                1: 'MO',
                2: 'TU',
                3: 'WE',
                4: 'TH',
                5: 'FR',
                6: 'SA'
            }, WEEK_DAYS_IDX = {
                'SU': 0,
                'MO': 1,
                'TU': 2,
                'WE': 3,
                'TH': 4,
                'FR': 5,
                'SA': 6
            }, DATE_FORMATS = [
                'yyyy-MM-ddTHH:mm:ss.fffzzz',
                'yyyy-MM-ddTHH:mm:sszzz',
                'yyyy-MM-ddTHH:mm:ss',
                'yyyy-MM-ddTHH:mm',
                'yyyy-MM-ddTHH',
                'yyyy-MM-dd',
                'yyyyMMddTHHmmssfffzzz',
                'yyyyMMddTHHmmsszzz',
                'yyyyMMddTHHmmss',
                'yyyyMMddTHHmm',
                'yyyyMMddTHH',
                'yyyyMMdd'
            ], RULE_NAMES = [
                'months',
                'weeks',
                'yearDays',
                'monthDays',
                'weekDays',
                'hours',
                'minutes',
                'seconds'
            ], RULE_NAMES_LENGTH = RULE_NAMES.length, RECURRENCE_DATE_FORMAT = 'yyyyMMddTHHmmssZ', limitation = {
                months: function (date, end, rule) {
                    var monthRules = rule.months, months = ruleValues(monthRules, date.getMonth() + 1), changed = false;
                    if (months !== null) {
                        if (months.length) {
                            date.setMonth(months[0] - 1, 1);
                        } else {
                            date.setFullYear(date.getFullYear() + 1, monthRules[0] - 1, 1);
                        }
                        changed = true;
                    }
                    return changed;
                },
                monthDays: function (date, end, rule) {
                    var monthLength, month, days, changed = false, hours = date.getHours(), normalize = function (monthDay) {
                            if (monthDay < 0) {
                                monthDay = monthLength + monthDay + 1;
                            }
                            return monthDay;
                        };
                    while (date <= end) {
                        month = date.getMonth();
                        monthLength = getMonthLength(date);
                        days = ruleValues(rule.monthDays, date.getDate(), normalize);
                        if (days === null) {
                            return changed;
                        }
                        changed = true;
                        if (days.length) {
                            date.setMonth(month, days.sort(numberSortPredicate)[0]);
                            adjustDST(date, hours);
                            if (month === date.getMonth()) {
                                break;
                            }
                        } else {
                            date.setMonth(month + 1, 1);
                        }
                    }
                    return changed;
                },
                yearDays: function (date, end, rule) {
                    var year, yearDays, changed = false, hours = date.getHours(), normalize = function (yearDay) {
                            if (yearDay < 0) {
                                yearDay = year + yearDay;
                            }
                            return yearDay;
                        };
                    while (date < end) {
                        year = leapYear(date) ? 366 : 365;
                        yearDays = ruleValues(rule.yearDays, dayInYear(date), normalize);
                        if (yearDays === null) {
                            return changed;
                        }
                        changed = true;
                        year = date.getFullYear();
                        if (yearDays.length) {
                            date.setFullYear(year, 0, yearDays.sort(numberSortPredicate)[0]);
                            adjustDST(date, hours);
                            break;
                        } else {
                            date.setFullYear(year + 1, 0, 1);
                        }
                    }
                    return changed;
                },
                weeks: function (date, end, rule) {
                    var weekStart = rule.weekStart, year, weeks, day, changed = false, hours = date.getHours(), normalize = function (week) {
                            if (week < 0) {
                                week = 53 + week;
                            }
                            return week;
                        };
                    while (date < end) {
                        weeks = ruleValues(rule.weeks, weekInYear(date, weekStart), normalize);
                        if (weeks === null) {
                            return changed;
                        }
                        changed = true;
                        year = date.getFullYear();
                        if (weeks.length) {
                            day = weeks.sort(numberSortPredicate)[0] * 7 - 1;
                            date.setFullYear(year, 0, day);
                            setDayOfWeek(date, weekStart, -1);
                            adjustDST(date, hours);
                            break;
                        } else {
                            date.setFullYear(year + 1, 0, 1);
                        }
                    }
                    return changed;
                },
                weekDays: function (date, end, rule) {
                    var weekDays = rule.weekDays;
                    var weekStart = rule.weekStart;
                    var weekDayRules = ruleWeekValues(weekDays, date, weekStart);
                    var hours = date.getHours();
                    var weekDayRule, day;
                    if (weekDayRules === null) {
                        return false;
                    }
                    weekDayRule = weekDayRules[0];
                    if (!weekDayRule) {
                        weekDayRule = weekDays[0];
                        setDayOfWeek(date, weekStart);
                    }
                    day = weekDayRule.day;
                    if (weekDayRule.offset) {
                        while (date <= end && !isInWeek(date, weekDayRule, weekStart)) {
                            if (weekInMonth(date, weekStart) === numberOfWeeks(date, weekStart)) {
                                date.setMonth(date.getMonth() + 1, 1);
                                adjustDST(date, hours);
                            } else {
                                date.setDate(date.getDate() + 7);
                                adjustDST(date, hours);
                                setDayOfWeek(date, weekStart, -1);
                            }
                        }
                    }
                    if (date.getDay() !== day) {
                        setDayOfWeek(date, day);
                    }
                    return true;
                },
                hours: function (date, end, rule) {
                    var hourRules = rule.hours, startTime = rule._startTime, startHours = startTime.getHours(), hours = ruleValues(hourRules, startHours), changed = false;
                    if (hours !== null) {
                        changed = true;
                        date.setHours(startHours);
                        adjustDST(date, startHours);
                        if (hours.length) {
                            hours = hours[0];
                            date.setHours(hours);
                        } else {
                            hours = date.getHours();
                            date.setDate(date.getDate() + 1);
                            adjustDST(date, hours);
                            hours = hourRules[0];
                            date.setHours(hours);
                            adjustDST(date, hours);
                        }
                        if (rule.minutes) {
                            date.setMinutes(0);
                        }
                        startTime.setHours(hours, date.getMinutes());
                    }
                    return changed;
                },
                minutes: function (date, end, rule) {
                    var minuteRules = rule.minutes, currentMinutes = date.getMinutes(), minutes = ruleValues(minuteRules, currentMinutes), hours = rule._startTime.getHours(), changed = false;
                    if (minutes !== null) {
                        changed = true;
                        if (minutes.length) {
                            minutes = minutes[0];
                        } else {
                            hours += 1;
                            minutes = minuteRules[0];
                        }
                        if (rule.seconds) {
                            date.setSeconds(0);
                        }
                        date.setHours(hours, minutes);
                        hours = hours % 24;
                        adjustDST(date, hours);
                        rule._startTime.setHours(hours, minutes, date.getSeconds());
                    }
                    return changed;
                },
                seconds: function (date, end, rule) {
                    var secondRules = rule.seconds, hours = rule._startTime.getHours(), seconds = ruleValues(secondRules, date.getSeconds()), minutes = date.getMinutes(), changed = false;
                    if (seconds !== null) {
                        changed = true;
                        if (seconds.length) {
                            date.setSeconds(seconds[0]);
                        } else {
                            minutes += 1;
                            date.setMinutes(minutes, secondRules[0]);
                            if (minutes > 59) {
                                minutes = minutes % 60;
                                hours = (hours + 1) % 24;
                            }
                        }
                        rule._startTime.setHours(hours, minutes, date.getSeconds());
                    }
                    return changed;
                }
            }, BaseFrequency = Class.extend({
                next: function (date, rule) {
                    var startTime = rule._startTime, day = startTime.getDate(), minutes, seconds;
                    if (rule.seconds) {
                        seconds = date.getSeconds() + 1;
                        date.setSeconds(seconds);
                        startTime.setSeconds(seconds);
                        startTime.setDate(day);
                    } else if (rule.minutes) {
                        minutes = date.getMinutes() + 1;
                        date.setMinutes(minutes);
                        startTime.setMinutes(minutes);
                        startTime.setDate(day);
                    } else {
                        return false;
                    }
                    return true;
                },
                normalize: function (options) {
                    var rule = options.rule;
                    if (options.idx === 4 && rule.hours) {
                        rule._startTime.setHours(0);
                        this._hour(options.date, rule);
                    }
                },
                limit: function (date, end, rule) {
                    var interval = rule.interval, ruleName, firstRule, modified, idx, day;
                    while (date <= end) {
                        modified = firstRule = undefined;
                        day = date.getDate();
                        for (idx = 0; idx < RULE_NAMES_LENGTH; idx++) {
                            ruleName = RULE_NAMES[idx];
                            if (rule[ruleName]) {
                                modified = limitation[ruleName](date, end, rule);
                                if (firstRule !== undefined && modified) {
                                    break;
                                } else {
                                    firstRule = modified;
                                }
                            }
                            if (modified) {
                                this.normalize({
                                    date: date,
                                    rule: rule,
                                    day: day,
                                    idx: idx
                                });
                            }
                        }
                        if ((interval === 1 || !this.interval(rule, date)) && idx === RULE_NAMES_LENGTH) {
                            break;
                        }
                    }
                },
                interval: function (rule, current) {
                    var start = new Date(rule._startPeriod);
                    var date = new Date(current);
                    var hours = current.getHours();
                    var weekStart = rule.weekStart;
                    var interval = rule.interval;
                    var frequency = rule.freq;
                    var modified = false;
                    var excess = 0;
                    var month = 0;
                    var day = 1;
                    var diff;
                    var startTimeHours;
                    if (frequency === 'hourly') {
                        diff = date.getTimezoneOffset() - start.getTimezoneOffset();
                        startTimeHours = rule._startTime.getHours();
                        date = date.getTime();
                        if (hours !== startTimeHours) {
                            date += (startTimeHours - hours) * kendoDate.MS_PER_HOUR;
                        }
                        date -= start;
                        if (diff) {
                            date -= diff * kendoDate.MS_PER_MINUTE;
                        }
                        diff = Math.floor(date / kendoDate.MS_PER_HOUR);
                        excess = intervalExcess(diff, interval);
                        if (excess !== 0) {
                            this._hour(current, rule, excess);
                            modified = true;
                        }
                    } else if (frequency === 'daily') {
                        kendoDate.setTime(date, -start, true);
                        diff = Math.round(date / kendoDate.MS_PER_DAY);
                        excess = intervalExcess(diff, interval);
                        if (excess !== 0) {
                            this._date(current, rule, excess);
                            modified = true;
                        }
                    } else if (frequency === 'weekly') {
                        excess = this._getNumberOfWeeksBetweenDates(start, current);
                        var normalizedCurrentIndex = normalizeDayIndex(current.getDay(), weekStart);
                        var normalizedStartIndex = normalizeDayIndex(start.getDay(), weekStart);
                        if (normalizedCurrentIndex < normalizedStartIndex) {
                            excess += 1;
                        }
                        excess = intervalExcess(excess, interval);
                        if (excess !== 0) {
                            kendoDate.setDayOfWeek(current, rule.weekStart, -1);
                            current.setDate(current.getDate() + excess * 7);
                            adjustDST(current, hours);
                            modified = true;
                        }
                    } else if (frequency === 'monthly') {
                        diff = current.getFullYear() - start.getFullYear();
                        diff = current.getMonth() - start.getMonth() + diff * 12;
                        excess = intervalExcess(diff, interval);
                        if (excess !== 0) {
                            day = rule._hasRuleValue ? 1 : current.getDate();
                            current.setFullYear(current.getFullYear(), current.getMonth() + excess, day);
                            adjustDST(current, hours);
                            modified = true;
                        }
                    } else if (frequency === 'yearly') {
                        diff = current.getFullYear() - start.getFullYear();
                        excess = intervalExcess(diff, interval);
                        if (!rule.months) {
                            month = current.getMonth();
                        }
                        if (!rule.yearDays && !rule.monthDays && !rule.weekDays) {
                            day = current.getDate();
                        }
                        if (excess !== 0) {
                            current.setFullYear(current.getFullYear() + excess, month, day);
                            adjustDST(current, hours);
                            modified = true;
                        }
                    }
                    return modified;
                },
                _getNumberOfWeeksBetweenDates: function (first, second) {
                    var weeks = (second - first) / 604800000;
                    var exactWeeks = Math.floor(weeks);
                    if (weeks - exactWeeks > 0.99) {
                        exactWeeks = Math.round(weeks);
                    }
                    return exactWeeks;
                },
                _hour: function (date, rule, interval) {
                    var startTime = rule._startTime, hours = startTime.getHours();
                    if (interval) {
                        hours += interval;
                    }
                    date.setHours(hours);
                    hours = hours % 24;
                    startTime.setHours(hours);
                    adjustDST(date, hours);
                },
                _date: function (date, rule, interval) {
                    var hours = date.getHours();
                    date.setDate(date.getDate() + interval);
                    if (!adjustDST(date, hours)) {
                        this._hour(date, rule);
                    }
                }
            }), HourlyFrequency = BaseFrequency.extend({
                next: function (date, rule) {
                    if (!BaseFrequency.fn.next(date, rule)) {
                        this._hour(date, rule, 1);
                    }
                },
                normalize: function (options) {
                    var rule = options.rule;
                    if (options.idx === 4) {
                        rule._startTime.setHours(0);
                        this._hour(options.date, rule);
                    }
                }
            }), DailyFrequency = BaseFrequency.extend({
                next: function (date, rule) {
                    if (!BaseFrequency.fn.next(date, rule)) {
                        this[rule.hours ? '_hour' : '_date'](date, rule, 1);
                    }
                }
            }), WeeklyFrequency = DailyFrequency.extend({
                setup: function (rule, eventStartDate) {
                    if (!rule.weekDays) {
                        rule.weekDays = [{
                                day: eventStartDate.getDay(),
                                offset: 0
                            }];
                    }
                }
            }), MonthlyFrequency = BaseFrequency.extend({
                next: function (date, rule) {
                    var day, hours;
                    if (!BaseFrequency.fn.next(date, rule)) {
                        if (rule.hours) {
                            this._hour(date, rule, 1);
                        } else if (rule.monthDays || rule.weekDays || rule.yearDays || rule.weeks) {
                            this._date(date, rule, 1);
                        } else {
                            day = date.getDate();
                            hours = date.getHours();
                            date.setMonth(date.getMonth() + 1);
                            adjustDST(date, hours);
                            while (date.getDate() !== day) {
                                date.setDate(day);
                                adjustDST(date, hours);
                            }
                            this._hour(date, rule);
                        }
                    }
                },
                normalize: function (options) {
                    var rule = options.rule, date = options.date, hours = date.getHours();
                    if (options.idx === 0 && !rule.monthDays && !rule.weekDays) {
                        date.setDate(options.day);
                        adjustDST(date, hours);
                    } else {
                        BaseFrequency.fn.normalize(options);
                    }
                },
                setup: function (rule, eventStartDate, date) {
                    if (!rule.monthDays && !rule.weekDays) {
                        date.setDate(eventStartDate.getDate());
                    }
                }
            }), YearlyFrequency = MonthlyFrequency.extend({
                next: function (date, rule) {
                    var day, hours = date.getHours();
                    if (!BaseFrequency.fn.next(date, rule)) {
                        if (rule.hours) {
                            this._hour(date, rule, 1);
                        } else if (rule.monthDays || rule.weekDays || rule.yearDays || rule.weeks) {
                            this._date(date, rule, 1);
                        } else if (rule.months) {
                            day = date.getDate();
                            date.setMonth(date.getMonth() + 1);
                            adjustDST(date, hours);
                            while (date.getDate() !== day) {
                                date.setDate(day);
                                adjustDST(date, hours);
                            }
                            this._hour(date, rule);
                        } else {
                            date.setFullYear(date.getFullYear() + 1);
                            adjustDST(date, hours);
                            this._hour(date, rule);
                        }
                    }
                },
                setup: function () {
                }
            }), frequencies = {
                'hourly': new HourlyFrequency(),
                'daily': new DailyFrequency(),
                'weekly': new WeeklyFrequency(),
                'monthly': new MonthlyFrequency(),
                'yearly': new YearlyFrequency()
            }, CLICK = 'click', CHANGE = 'change';
        function intervalExcess(diff, interval) {
            var excess;
            if (diff !== 0 && diff < interval) {
                excess = interval - diff;
            } else {
                excess = diff % interval;
                if (excess) {
                    excess = interval - excess;
                }
            }
            return excess;
        }
        function dayInYear(date) {
            var month = date.getMonth();
            var days = leapYear(date) ? DAYS_IN_LEAPYEAR[month] : DAYS_IN_YEAR[month];
            return days + date.getDate();
        }
        function weekInYear(date, weekStart) {
            var year, days;
            date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
            adjustDST(date, 0);
            year = date.getFullYear();
            if (weekStart !== undefined) {
                setDayOfWeek(date, weekStart, -1);
                date.setDate(date.getDate() + 4);
            } else {
                date.setDate(date.getDate() + (4 - (date.getDay() || 7)));
            }
            adjustDST(date, 0);
            days = Math.floor((date.getTime() - new Date(year, 0, 1, -6)) / 86400000);
            return 1 + Math.floor(days / 7);
        }
        function weekInMonth(date, weekStart) {
            var firstWeekDay = firstDayOfMonth(date).getDay();
            var firstWeekLength = 7 - (firstWeekDay + 7 - (weekStart || 7)) || 7;
            if (firstWeekLength < 0) {
                firstWeekLength += 7;
            }
            return Math.ceil((date.getDate() - firstWeekLength) / 7) + 1;
        }
        function normalizeDayIndex(weekDay, weekStart) {
            return weekDay + (weekDay < weekStart ? 7 : 0);
        }
        function normalizeOffset(date, rule, weekStart) {
            var offset = rule.offset;
            if (!offset) {
                return weekInMonth(date, weekStart);
            }
            var lastDate = new Date(date.getFullYear(), date.getMonth() + 1, 0);
            var weeksInMonth = weekInMonth(lastDate, weekStart);
            var day = normalizeDayIndex(rule.day, weekStart);
            var skipFirst = day < normalizeDayIndex(new Date(date.getFullYear(), date.getMonth(), 1).getDay(), weekStart);
            var skipLast = day > normalizeDayIndex(lastDate.getDay(), weekStart);
            if (offset < 0) {
                offset = weeksInMonth + (offset + 1 - (skipLast ? 1 : 0));
            } else if (skipFirst) {
                offset += 1;
            }
            weeksInMonth -= skipLast ? 1 : 0;
            if (offset < (skipFirst ? 1 : 0) || offset > weeksInMonth) {
                return null;
            }
            return offset;
        }
        function numberOfWeeks(date, weekStart) {
            return weekInMonth(new Date(date.getFullYear(), date.getMonth() + 1, 0), weekStart);
        }
        function isInWeek(date, rule, weekStart) {
            return weekInMonth(date, weekStart) === normalizeOffset(date, rule, weekStart);
        }
        function ruleWeekValues(weekDays, date, weekStart) {
            var currentDay = normalizeDayIndex(date.getDay(), weekStart);
            var length = weekDays.length;
            var ruleWeekOffset;
            var weekDay, day;
            var weekNumber;
            var result = [];
            var idx = 0;
            for (; idx < length; idx++) {
                weekDay = weekDays[idx];
                weekNumber = weekInMonth(date, weekStart);
                ruleWeekOffset = normalizeOffset(date, weekDay, weekStart);
                if (ruleWeekOffset === null) {
                    continue;
                }
                if (weekNumber < ruleWeekOffset) {
                    result.push(weekDay);
                } else if (weekNumber === ruleWeekOffset) {
                    day = normalizeDayIndex(weekDay.day, weekStart);
                    if (currentDay < day) {
                        result.push(weekDay);
                    } else if (currentDay === day) {
                        return null;
                    }
                }
            }
            return result;
        }
        function ruleValues(rules, value, normalize) {
            var idx = 0, length = rules.length, availableRules = [], ruleValue;
            for (; idx < length; idx++) {
                ruleValue = rules[idx];
                if (normalize) {
                    ruleValue = normalize(ruleValue);
                }
                if (value === ruleValue) {
                    return null;
                } else if (value < ruleValue) {
                    availableRules.push(ruleValue);
                }
            }
            return availableRules;
        }
        function parseArray(list, range) {
            var idx = 0, length = list.length, value;
            for (; idx < length; idx++) {
                value = parseInt(list[idx], 10);
                if (isNaN(value) || value < range.start || value > range.end || value === 0 && range.start < 0) {
                    return null;
                }
                list[idx] = value;
            }
            return list.sort(numberSortPredicate);
        }
        function parseWeekDayList(list) {
            var idx = 0, length = list.length, value, valueLength, day;
            for (; idx < length; idx++) {
                value = list[idx];
                valueLength = value.length;
                day = value.substring(valueLength - 2).toUpperCase();
                day = WEEK_DAYS_IDX[day];
                if (day === undefined) {
                    return null;
                }
                list[idx] = {
                    offset: parseInt(value.substring(0, valueLength - 2), 10) || 0,
                    day: day
                };
            }
            return list;
        }
        function serializeWeekDayList(list) {
            var idx = 0, length = list.length, value, valueString, result = [];
            for (; idx < length; idx++) {
                value = list[idx];
                if (typeof value === 'string') {
                    valueString = value;
                } else {
                    valueString = '' + WEEK_DAYS[value.day];
                    if (value.offset) {
                        valueString = value.offset + valueString;
                    }
                }
                result.push(valueString);
            }
            return result.toString();
        }
        function getMonthLength(date) {
            var month = date.getMonth();
            if (month === 1) {
                if (new Date(date.getFullYear(), 1, 29).getMonth() === 1) {
                    return 29;
                }
                return 28;
            }
            return MONTHS[month];
        }
        function leapYear(year) {
            year = year.getFullYear();
            return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
        }
        function numberSortPredicate(a, b) {
            return a - b;
        }
        function parseExceptions(exceptions, zone) {
            var idx = 0, length, date, dates = [];
            if (exceptions) {
                exceptions = exceptions.split(exceptions.indexOf(';') !== -1 ? ';' : ',');
                length = exceptions.length;
                for (; idx < length; idx++) {
                    date = parseUTCDate(exceptions[idx], zone);
                    if (date) {
                        dates.push(date);
                    }
                }
            }
            return dates;
        }
        function isException(exceptions, date, zone) {
            var dates = $.isArray(exceptions) ? exceptions : parseExceptions(exceptions, zone), dateTime = date.getTime() - date.getMilliseconds(), idx = 0, length = dates.length;
            for (; idx < length; idx++) {
                if (dates[idx].getTime() === dateTime) {
                    return true;
                }
            }
            return false;
        }
        function toExceptionString(dates, zone) {
            var idx = 0;
            var length;
            var date;
            var result = [].concat(dates);
            for (length = result.length; idx < length; idx++) {
                date = result[idx];
                date = kendo.timezone.convert(date, zone || date.getTimezoneOffset(), 'Etc/UTC');
                result[idx] = kendo.toString(date, RECURRENCE_DATE_FORMAT);
            }
            return result.join(',');
        }
        function startPeriodByFreq(start, rule) {
            var date = new Date(start);
            switch (rule.freq) {
            case 'yearly':
                date.setFullYear(date.getFullYear(), 0, 1);
                break;
            case 'monthly':
                date.setFullYear(date.getFullYear(), date.getMonth(), 1);
                break;
            case 'weekly':
                setDayOfWeek(date, rule.weekStart, -1);
                break;
            default:
                break;
            }
            if (rule.hours) {
                date.setHours(0);
            }
            if (rule.minutes) {
                date.setMinutes(0);
            }
            if (rule.seconds) {
                date.setSeconds(0);
            }
            return date;
        }
        function endPeriodByFreq(start, rule) {
            var date = new Date(start);
            switch (rule.freq) {
            case 'yearly':
                date.setFullYear(date.getFullYear(), 11, 31);
                break;
            case 'monthly':
                date.setFullYear(date.getFullYear(), date.getMonth() + 1, 0);
                break;
            case 'weekly':
                setDayOfWeek(date, rule.weekStart, -1);
                date.setDate(date.getDate() + 6);
                break;
            default:
                break;
            }
            if (rule.hours) {
                date.setHours(23);
            }
            if (rule.minutes) {
                date.setMinutes(59);
            }
            if (rule.seconds) {
                date.setSeconds(59);
            }
            return date;
        }
        function eventsByPosition(periodEvents, start, positions) {
            var periodEventsLength = periodEvents.length;
            var events = [];
            var position;
            var event;
            for (var idx = 0, length = positions.length; idx < length; idx++) {
                position = positions[idx];
                if (position < 0) {
                    position = periodEventsLength + position;
                } else {
                    position -= 1;
                }
                event = periodEvents[position];
                if (event && event.start >= start) {
                    events.push(event);
                }
            }
            return events;
        }
        function removeExceptionDates(periodEvents, exceptionDates, zone) {
            var events = [];
            var event;
            for (var idx = 0; idx < periodEvents.length; idx++) {
                event = periodEvents[idx];
                if (!isException(exceptionDates, event.start, zone)) {
                    events.push(event);
                }
            }
            return events;
        }
        function expand(event, start, end, zone) {
            var rule = parseRule(event.recurrenceRule, zone), startTime, endTime, endDate, hours, minutes, seconds, durationMS, startPeriod, inPeriod, ruleStart, ruleEnd, useEventStart, freqName, exceptionDates, eventStartTime, eventStartMS, eventStart, count, freq, positions, currentIdx, periodEvents, events = [], shiftedStart, shiftedEnd, shiftedStartTime, shifterEndTime;
            if (!rule) {
                return [event];
            }
            positions = rule.positions;
            currentIdx = positions ? 0 : 1;
            ruleStart = rule.start;
            ruleEnd = rule.end;
            if (ruleStart || ruleEnd) {
                event = event.clone({
                    start: ruleStart ? new Date(ruleStart.value[0]) : undefined,
                    end: ruleEnd ? new Date(ruleEnd.value[0]) : undefined
                });
            }
            eventStart = event.start;
            eventStartMS = eventStart.getTime();
            eventStartTime = getMilliseconds(eventStart);
            exceptionDates = parseExceptions(event.recurrenceException, zone);
            if (!exceptionDates[0] && rule.exdates) {
                exceptionDates = rule.exdates.value;
                event.set('recurrenceException', toExceptionString(exceptionDates, zone));
            }
            startPeriod = start = new Date(start);
            end = new Date(end);
            freqName = rule.freq;
            freq = frequencies[freqName];
            count = rule.count;
            if (rule.until && rule.until < end) {
                end = new Date(rule.until);
            }
            useEventStart = freqName === 'yearly' || freqName === 'monthly' || freqName === 'weekly';
            if (start < eventStartMS || count || rule.interval > 1 || useEventStart || (freqName === 'daily' || freqName === 'hourly') && !rule.seconds) {
                start = new Date(eventStartMS);
            } else {
                hours = start.getHours();
                minutes = start.getMinutes();
                seconds = start.getSeconds();
                if (!rule.hours) {
                    hours = eventStart.getHours();
                }
                if (!rule.minutes) {
                    minutes = eventStart.getMinutes();
                }
                if (!rule.seconds) {
                    seconds = eventStart.getSeconds();
                }
                start.setHours(hours, minutes, seconds, eventStart.getMilliseconds());
            }
            rule._startPeriod = new Date(start);
            if (positions) {
                start = startPeriodByFreq(start, rule);
                end = endPeriodByFreq(end, rule);
                var diff = getMilliseconds(end) - getMilliseconds(start);
                if (diff < 0) {
                    hours = start.getHours();
                    end.setHours(hours, start.getMinutes(), start.getSeconds(), start.getMilliseconds());
                    kendoDate.adjustDST(end, hours);
                }
                rule._startPeriod = new Date(start);
                rule._endPeriod = endPeriodByFreq(start, rule);
            }
            durationMS = event.duration();
            rule._startTime = startTime = kendoDate.toInvariantTime(start);
            if (freq.setup) {
                freq.setup(rule, eventStart, start);
            }
            freq.limit(start, end, rule);
            while (start <= end) {
                endDate = new Date(start);
                setTime(endDate, durationMS);
                inPeriod = start >= startPeriod || endDate > startPeriod;
                if (inPeriod && !isException(exceptionDates, start, zone) || positions) {
                    startTime = kendoDate.toUtcTime(kendoDate.getDate(start)) + getMilliseconds(rule._startTime);
                    endTime = startTime + durationMS;
                    if (eventStartMS !== start.getTime() || eventStartTime !== getMilliseconds(rule._startTime)) {
                        if (!event.isAllDay) {
                            var startZone = event.startTimezone || event.endTimezone;
                            var endZone = event.endTimezone || event.startTimezone;
                            if (zone && startZone || !zone && !startZone) {
                                var startOffsetDiff = getZoneOffset(start, zone) - getZoneOffset(event.start, zone);
                                var endOffsetDiff = getZoneOffset(endDate, zone) - getZoneOffset(event.end, zone);
                                var startTZOffsetDiff = getZoneOffset(start, startZone) - getZoneOffset(event.start, startZone);
                                var endTZOffsetDiff = getZoneOffset(endDate, endZone) - getZoneOffset(event.end, endZone);
                                if (startOffsetDiff !== startTZOffsetDiff) {
                                    var offsetTicksStart = (startOffsetDiff - startTZOffsetDiff) * 60000;
                                    shiftedStart = new Date(start.getTime() - offsetTicksStart);
                                    shiftedStartTime = startTime - offsetTicksStart;
                                }
                                if (endOffsetDiff !== endTZOffsetDiff) {
                                    var offsetTicksEnd = (endOffsetDiff - endTZOffsetDiff) * 60000;
                                    shiftedEnd = new Date(endDate.getTime() - offsetTicksEnd);
                                    shifterEndTime = endTime - offsetTicksEnd;
                                }
                            }
                        }
                        events.push(event.toOccurrence({
                            start: shiftedStart || new Date(start),
                            end: shiftedEnd || endDate,
                            _startTime: shiftedStartTime || startTime,
                            _endTime: shifterEndTime || endTime
                        }));
                        shiftedStart = shiftedEnd = shiftedStartTime = shifterEndTime = null;
                    } else {
                        event._startTime = startTime;
                        event._endTime = endTime;
                        events.push(event);
                    }
                }
                if (positions) {
                    freq.next(start, rule);
                    freq.limit(start, end, rule);
                    if (start > rule._endPeriod) {
                        periodEvents = eventsByPosition(events.slice(currentIdx), eventStart, positions);
                        periodEvents = removeExceptionDates(periodEvents, exceptionDates, zone);
                        events = events.slice(0, currentIdx).concat(periodEvents);
                        rule._endPeriod = endPeriodByFreq(start, rule);
                        currentIdx = events.length;
                    }
                    if (count && count === currentIdx) {
                        break;
                    }
                } else {
                    if (count && count === currentIdx) {
                        break;
                    }
                    currentIdx += 1;
                    var isMissingDSTHour = isDSTMissingHour(start);
                    freq.next(start, rule);
                    if (isMissingDSTHour && rule.freq !== 'hourly' && kendoDate.toInvariantTime(event.start).getTime() !== kendoDate.toInvariantTime(start).getTime()) {
                        rule._startTime = startTime = new Date(start.getTime() - 3600000);
                    }
                    freq.limit(start, end, rule);
                }
            }
            return events;
        }
        function isDSTMissingHour(date) {
            var dateOffset = date.getTimezoneOffset();
            var dateMinusHour = new Date(date.getTime() - 3600000);
            var dateMinusHourOffset = dateMinusHour.getTimezoneOffset();
            return dateOffset < dateMinusHourOffset;
        }
        function getZoneOffset(date, zone) {
            return zone ? kendo.timezone.offset(date, zone) : date.getTimezoneOffset();
        }
        function parseUTCDate(value, zone) {
            value = kendo.parseDate(value, DATE_FORMATS);
            if (value && zone) {
                value = timezone.apply(value, zone);
            }
            return value;
        }
        function parseDateRule(dateRule, zone) {
            var pairs = dateRule.split(';');
            var pair;
            var property;
            var value;
            var tzid;
            var valueIdx, valueLength;
            for (var idx = 0, length = pairs.length; idx < length; idx++) {
                pair = pairs[idx].split(':');
                property = pair[0];
                value = pair[1];
                if (property.indexOf('TZID') !== -1) {
                    tzid = property.substring(property.indexOf('TZID')).split('=')[1];
                }
                if (value) {
                    value = value.split(',');
                    for (valueIdx = 0, valueLength = value.length; valueIdx < valueLength; valueIdx++) {
                        value[valueIdx] = parseUTCDate(value[valueIdx], tzid || zone);
                    }
                }
            }
            if (value) {
                return {
                    value: value,
                    tzid: tzid
                };
            }
        }
        function parseRule(recur, zone) {
            var instance = {};
            var splits, value;
            var idx = 0, length;
            var ruleValue = false;
            var rule, part, parts;
            var property, weekStart, weekDays;
            var predicate = function (a, b) {
                var day1 = a.day, day2 = b.day;
                if (day1 < weekStart) {
                    day1 += 7;
                }
                if (day2 < weekStart) {
                    day2 += 7;
                }
                return day1 - day2;
            };
            if (!recur) {
                return null;
            }
            parts = recur.split('\n');
            if (!parts[1] && (recur.indexOf('DTSTART') !== -1 || recur.indexOf('DTEND') !== -1 || recur.indexOf('EXDATE') !== -1)) {
                parts = recur.split(' ');
            }
            for (idx = 0, length = parts.length; idx < length; idx++) {
                part = $.trim(parts[idx]);
                if (part.indexOf('DTSTART') !== -1) {
                    instance.start = parseDateRule(part, zone);
                } else if (part.indexOf('DTEND') !== -1) {
                    instance.end = parseDateRule(part, zone);
                } else if (part.indexOf('EXDATE') !== -1) {
                    instance.exdates = parseDateRule(part, zone);
                } else if (part.indexOf('RRULE') !== -1) {
                    rule = part.substring(6);
                } else if ($.trim(part)) {
                    rule = part;
                }
            }
            rule = rule.split(';');
            for (idx = 0, length = rule.length; idx < length; idx++) {
                property = rule[idx];
                splits = property.split('=');
                value = $.trim(splits[1]).split(',');
                switch ($.trim(splits[0]).toUpperCase()) {
                case 'FREQ':
                    instance.freq = value[0].toLowerCase();
                    break;
                case 'UNTIL':
                    instance.until = parseUTCDate(value[0], zone);
                    break;
                case 'COUNT':
                    instance.count = parseInt(value[0], 10);
                    break;
                case 'INTERVAL':
                    instance.interval = parseInt(value[0], 10);
                    break;
                case 'BYSECOND':
                    instance.seconds = parseArray(value, {
                        start: 0,
                        end: 60
                    });
                    ruleValue = true;
                    break;
                case 'BYMINUTE':
                    instance.minutes = parseArray(value, {
                        start: 0,
                        end: 59
                    });
                    ruleValue = true;
                    break;
                case 'BYHOUR':
                    instance.hours = parseArray(value, {
                        start: 0,
                        end: 23
                    });
                    ruleValue = true;
                    break;
                case 'BYMONTHDAY':
                    instance.monthDays = parseArray(value, {
                        start: -31,
                        end: 31
                    });
                    ruleValue = true;
                    break;
                case 'BYYEARDAY':
                    instance.yearDays = parseArray(value, {
                        start: -366,
                        end: 366
                    });
                    ruleValue = true;
                    break;
                case 'BYMONTH':
                    instance.months = parseArray(value, {
                        start: 1,
                        end: 12
                    });
                    ruleValue = true;
                    break;
                case 'BYDAY':
                    instance.weekDays = weekDays = parseWeekDayList(value);
                    ruleValue = true;
                    break;
                case 'BYWEEKNO':
                    instance.weeks = parseArray(value, {
                        start: -53,
                        end: 53
                    });
                    ruleValue = true;
                    break;
                case 'BYSETPOS':
                    instance.positions = parseArray(value, {
                        start: -366,
                        end: 366
                    });
                    break;
                case 'WKST':
                    instance.weekStart = weekStart = WEEK_DAYS_IDX[value[0]];
                    break;
                }
            }
            if (instance.freq === undefined || instance.count !== undefined && instance.until) {
                return null;
            }
            if (!instance.interval) {
                instance.interval = 1;
            }
            if (weekStart === undefined) {
                instance.weekStart = weekStart = kendo.culture().calendar.firstDay;
            }
            if (weekDays) {
                instance.weekDays = weekDays.sort(predicate);
            }
            if (instance.positions && !ruleValue) {
                instance.positions = null;
            }
            instance._hasRuleValue = ruleValue;
            return instance;
        }
        function serializeDateRule(dateRule, zone) {
            var value = dateRule.value;
            var tzid = dateRule.tzid || '';
            var length = value.length;
            var idx = 0;
            var val;
            for (; idx < length; idx++) {
                val = value[idx];
                val = timezone.convert(val, tzid || zone || val.getTimezoneOffset(), 'Etc/UTC');
                value[idx] = kendo.toString(val, 'yyyyMMddTHHmmssZ');
            }
            if (tzid) {
                tzid = ';TZID=' + tzid;
            }
            return tzid + ':' + value.join(',') + ' ';
        }
        function serialize(rule, zone) {
            var weekStart = rule.weekStart;
            var ruleString = 'FREQ=' + rule.freq.toUpperCase();
            var exdates = rule.exdates || '';
            var start = rule.start || '';
            var end = rule.end || '';
            var until = rule.until;
            if (rule.interval > 1) {
                ruleString += ';INTERVAL=' + rule.interval;
            }
            if (rule.count) {
                ruleString += ';COUNT=' + rule.count;
            }
            if (until) {
                until = timezone.convert(until, zone || until.getTimezoneOffset(), 'Etc/UTC');
                ruleString += ';UNTIL=' + kendo.toString(until, 'yyyyMMddTHHmmssZ');
            }
            if (rule.months) {
                ruleString += ';BYMONTH=' + rule.months;
            }
            if (rule.weeks) {
                ruleString += ';BYWEEKNO=' + rule.weeks;
            }
            if (rule.yearDays) {
                ruleString += ';BYYEARDAY=' + rule.yearDays;
            }
            if (rule.monthDays) {
                ruleString += ';BYMONTHDAY=' + rule.monthDays;
            }
            if (rule.weekDays) {
                ruleString += ';BYDAY=' + serializeWeekDayList(rule.weekDays);
            }
            if (rule.hours) {
                ruleString += ';BYHOUR=' + rule.hours;
            }
            if (rule.minutes) {
                ruleString += ';BYMINUTE=' + rule.minutes;
            }
            if (rule.seconds) {
                ruleString += ';BYSECOND=' + rule.seconds;
            }
            if (rule.positions) {
                ruleString += ';BYSETPOS=' + rule.positions;
            }
            if (weekStart !== undefined) {
                ruleString += ';WKST=' + WEEK_DAYS[weekStart];
            }
            if (start) {
                start = 'DTSTART' + serializeDateRule(start, zone);
            }
            if (end) {
                end = 'DTEND' + serializeDateRule(end, zone);
            }
            if (exdates) {
                exdates = 'EXDATE' + serializeDateRule(exdates, zone);
            }
            if (start || end || exdates) {
                ruleString = start + end + exdates + 'RRULE:' + ruleString;
            }
            return ruleString;
        }
        kendo.recurrence = {
            rule: {
                parse: parseRule,
                serialize: serialize
            },
            expand: expand,
            dayInYear: dayInYear,
            weekInYear: weekInYear,
            weekInMonth: weekInMonth,
            numberOfWeeks: numberOfWeeks,
            isException: isException,
            toExceptionString: toExceptionString
        };
        var weekDayCheckBoxes = function (firstDay) {
            var shortNames = kendo.culture().calendar.days.namesShort, length = shortNames.length, result = '', idx = 0, values = [];
            for (; idx < length; idx++) {
                values.push(idx);
            }
            shortNames = shortNames.slice(firstDay).concat(shortNames.slice(0, firstDay));
            values = values.slice(firstDay).concat(values.slice(0, firstDay));
            for (idx = 0; idx < length; idx++) {
                result += '<label class="k-check"><input class="k-recur-weekday-checkbox" type="checkbox" value="' + values[idx] + '" /> ' + shortNames[idx] + '</label>';
            }
            return result;
        };
        var mobileWeekDayCheckBoxes = function (firstDay) {
            var shortNames = kendo.culture().calendar.days.names, length = shortNames.length, result = '', idx = 0, values = [];
            for (; idx < length; idx++) {
                values.push(idx);
            }
            shortNames = shortNames.slice(firstDay).concat(shortNames.slice(0, firstDay));
            values = values.slice(firstDay).concat(values.slice(0, firstDay));
            for (idx = 0; idx < length; idx++) {
                result += '<li class="k-item"><label class="k-label">';
                result += '<span class="k-item-title">' + shortNames[idx] + '</span>';
                result += '<input class="k-recur-weekday-checkbox k-check" type="checkbox" value="' + values[idx] + '" />';
                result += '</label></li>';
            }
            return result;
        };
        var RECURRENCE_VIEW_TEMPLATE = kendo.template('# if (frequency !== "never") { #' + '<div class="k-edit-label"><label>#:messages.repeatEvery#</label></div>' + '<div class="k-edit-field"><input class="k-recur-interval" title="#:messages.interval#"/>#:messages.interval#</div>' + '# } #' + '# if (frequency === "weekly") { #' + '<div class="k-edit-label"><label>#:messages.repeatOn#</label></div>' + '<div class="k-edit-field">#=weekDayCheckBoxes(firstWeekDay)#</div>' + '# } else if (frequency === "monthly") { #' + '<div class="k-edit-label"><label>#:messages.repeatOn#</label></div>' + '<div class="k-edit-field">' + '<ul class="k-reset">' + '<li>' + '<label><input class="k-recur-month-radio" type="radio" name="month" value="monthday" title="#:messages.day#" />#:messages.day#</label>' + '<input class="k-recur-monthday" title="#:messages.day#" />' + '</li>' + '<li>' + '<input class="k-recur-month-radio" type="radio" name="month" value="weekday" title="#:messages.repeatOn#" />' + '<input class="k-recur-weekday-offset" title="#:messages.repeatOn#" /><input class="k-recur-weekday" title="#:messages.day#" />' + '</li>' + '</ul>' + '</div>' + '# } else if (frequency === "yearly") { #' + '<div class="k-edit-label"><label>#:messages.repeatOn#</label></div>' + '<div class="k-edit-field">' + '<ul class="k-reset">' + '<li>' + '<input class="k-recur-year-radio" type="radio" name="year" value="monthday" title="#:messages.repeatOn#" />' + '<input class="k-recur-month" title="#:messages.repeatOn#" /><input class="k-recur-monthday" title="#:messages.day#" />' + '</li>' + '<li>' + '<input class="k-recur-year-radio" type="radio" name="year" value="weekday" title="#:messages.repeatOn#" />' + '<input class="k-recur-weekday-offset" title="#:messages.repeatOn#" /><input class="k-recur-weekday" title="#:messages.day#"  />#:messages.of#<input class="k-recur-month" title="#:messages.of#"/>' + '</li>' + '</ul>' + '</div>' + '# } #' + '# if (frequency !== "never") { #' + '<div class="k-edit-label"><label>#:end.label#</label></div>' + '<div class="k-edit-field">' + '<ul class="k-reset">' + '<li>' + '<label><input class="k-recur-end-never" type="radio" name="end" value="never" />#:end.never#</label>' + '</li>' + '<li>' + '<label><input class="k-recur-end-count" type="radio" name="end" value="count" />#:end.after#</label>' + '<input class="k-recur-count" title="#:end.occurrence#" />#:end.occurrence#' + '</li>' + '<li>' + '<label><input class="k-recur-end-until" type="radio" name="end" value="until" />#:end.on#</label>' + '<input class="k-recur-until" title="#:end.on#" />' + '</li>' + '</ul>' + '</div>' + '# } #');
        var DAY_RULE = [
            {
                day: 0,
                offset: 0
            },
            {
                day: 1,
                offset: 0
            },
            {
                day: 2,
                offset: 0
            },
            {
                day: 3,
                offset: 0
            },
            {
                day: 4,
                offset: 0
            },
            {
                day: 5,
                offset: 0
            },
            {
                day: 6,
                offset: 0
            }
        ];
        var WEEKDAY_RULE = [
            {
                day: 1,
                offset: 0
            },
            {
                day: 2,
                offset: 0
            },
            {
                day: 3,
                offset: 0
            },
            {
                day: 4,
                offset: 0
            },
            {
                day: 5,
                offset: 0
            }
        ];
        var WEEKEND_RULE = [
            {
                day: 0,
                offset: 0
            },
            {
                day: 6,
                offset: 0
            }
        ];
        var BaseRecurrenceEditor = Widget.extend({
            init: function (element, options) {
                var start;
                var that = this;
                var frequencies = options && options.frequencies;
                Widget.fn.init.call(that, element, options);
                that.wrapper = that.element;
                options = that.options;
                options.start = start = options.start || kendoDate.today();
                if (frequencies) {
                    options.frequencies = frequencies;
                }
                if (typeof start === 'string') {
                    options.start = kendo.parseDate(start, 'yyyyMMddTHHmmss');
                }
                if (options.firstWeekDay === null) {
                    options.firstWeekDay = kendo.culture().calendar.firstDay;
                }
                that._namespace = '.' + options.name;
            },
            options: {
                value: '',
                start: '',
                timezone: '',
                spinners: true,
                firstWeekDay: null,
                frequencies: [
                    'never',
                    'daily',
                    'weekly',
                    'monthly',
                    'yearly'
                ],
                mobile: false,
                messages: {
                    recurrenceEditorTitle: 'Recurrence editor',
                    frequencies: {
                        never: 'Never',
                        hourly: 'Hourly',
                        daily: 'Daily',
                        weekly: 'Weekly',
                        monthly: 'Monthly',
                        yearly: 'Yearly'
                    },
                    hourly: {
                        repeatEvery: 'Repeat every: ',
                        interval: ' hour(s)'
                    },
                    daily: {
                        repeatEvery: 'Repeat every: ',
                        interval: ' day(s)'
                    },
                    weekly: {
                        interval: ' week(s)',
                        repeatEvery: 'Repeat every: ',
                        repeatOn: 'Repeat on: '
                    },
                    monthly: {
                        repeatEvery: 'Repeat every: ',
                        repeatOn: 'Repeat on: ',
                        interval: ' month(s)',
                        day: 'Day '
                    },
                    yearly: {
                        repeatEvery: 'Repeat every: ',
                        repeatOn: 'Repeat on: ',
                        interval: ' year(s)',
                        of: ' of '
                    },
                    end: {
                        label: 'End:',
                        mobileLabel: 'Ends',
                        never: 'Never',
                        after: 'After ',
                        occurrence: ' occurrence(s)',
                        on: 'On '
                    },
                    offsetPositions: {
                        first: 'first',
                        second: 'second',
                        third: 'third',
                        fourth: 'fourth',
                        last: 'last'
                    },
                    weekdays: {
                        day: 'day',
                        weekday: 'weekday',
                        weekend: 'weekend day'
                    }
                }
            },
            events: ['change'],
            _initInterval: function () {
                var that = this;
                var rule = that._value;
                that._container.find('.k-recur-interval').kendoNumericTextBox({
                    spinners: that.options.spinners,
                    value: rule.interval || 1,
                    decimals: 0,
                    format: '#',
                    min: 1,
                    change: function () {
                        rule.interval = this.value();
                        that._trigger();
                    }
                });
            },
            _weekDayRule: function (clear) {
                var that = this;
                var weekday = (that._weekDay.element || that._weekDay).val();
                var offset = Number((that._weekDayOffset.element || that._weekDayOffset).val());
                var weekDays = null;
                var positions = null;
                if (!clear) {
                    if (weekday === 'day') {
                        weekDays = DAY_RULE;
                        positions = offset;
                    } else if (weekday === 'weekday') {
                        weekDays = WEEKDAY_RULE;
                        positions = offset;
                    } else if (weekday === 'weekend') {
                        weekDays = WEEKEND_RULE;
                        positions = offset;
                    } else {
                        weekDays = [{
                                offset: offset,
                                day: Number(weekday)
                            }];
                    }
                }
                that._value.weekDays = weekDays;
                that._value.positions = positions;
            },
            _weekDayView: function () {
                var that = this;
                var weekDays = that._value.weekDays;
                var positions = that._value.positions;
                var weekDayOffsetWidget = that._weekDayOffset;
                var weekDayOffset;
                var weekDayValue;
                var length;
                var method;
                if (weekDays) {
                    length = weekDays.length;
                    if (positions) {
                        if (length === 7) {
                            weekDayValue = 'day';
                            weekDayOffset = positions;
                        } else if (length === 5) {
                            weekDayValue = 'weekday';
                            weekDayOffset = positions;
                        } else if (length === 2) {
                            weekDayValue = 'weekend';
                            weekDayOffset = positions;
                        }
                    }
                    if (!weekDayValue) {
                        weekDays = weekDays[0];
                        weekDayValue = weekDays.day;
                        weekDayOffset = weekDays.offset || '';
                    }
                    method = weekDayOffsetWidget.value ? 'value' : 'val';
                    weekDayOffsetWidget[method](weekDayOffset);
                    that._weekDay[method](weekDayValue);
                }
            },
            _initWeekDay: function () {
                var that = this, data;
                var weekdayMessage = that.options.messages.weekdays;
                var offsetMessage = that.options.messages.offsetPositions;
                var weekDayInput = that._container.find('.k-recur-weekday');
                var change = function () {
                    that._weekDayRule();
                    that._trigger();
                };
                if (weekDayInput[0]) {
                    that._weekDayOffset = new DropDownList(that._container.find('.k-recur-weekday-offset'), {
                        change: change,
                        dataTextField: 'text',
                        dataValueField: 'value',
                        dataSource: [
                            {
                                text: offsetMessage.first,
                                value: '1'
                            },
                            {
                                text: offsetMessage.second,
                                value: '2'
                            },
                            {
                                text: offsetMessage.third,
                                value: '3'
                            },
                            {
                                text: offsetMessage.fourth,
                                value: '4'
                            },
                            {
                                text: offsetMessage.last,
                                value: '-1'
                            }
                        ]
                    });
                    data = [
                        {
                            text: weekdayMessage.day,
                            value: 'day'
                        },
                        {
                            text: weekdayMessage.weekday,
                            value: 'weekday'
                        },
                        {
                            text: weekdayMessage.weekend,
                            value: 'weekend'
                        }
                    ];
                    that._weekDay = new DropDownList(weekDayInput, {
                        value: that.options.start.getDay(),
                        change: change,
                        dataTextField: 'text',
                        dataValueField: 'value',
                        dataSource: data.concat($.map(kendo.culture().calendar.days.names, function (dayName, idx) {
                            return {
                                text: dayName,
                                value: idx
                            };
                        }))
                    });
                    that._weekDayView();
                }
            },
            _initWeekDays: function () {
                var that = this;
                var rule = that._value;
                var weekDays = that._container.find('.k-recur-weekday-checkbox');
                if (weekDays[0]) {
                    weekDays.on(CLICK + that._namespace, function () {
                        rule.weekDays = $.map(weekDays.filter(':checked'), function (checkbox) {
                            return {
                                day: Number(checkbox.value),
                                offset: 0
                            };
                        });
                        if (!that.options.mobile) {
                            that._trigger();
                        }
                    });
                    if (rule.weekDays) {
                        var idx, weekDay;
                        var i = 0, l = weekDays.length;
                        var length = rule.weekDays.length;
                        for (; i < l; i++) {
                            weekDay = weekDays[i];
                            for (idx = 0; idx < length; idx++) {
                                if (weekDay.value == rule.weekDays[idx].day) {
                                    weekDay.checked = true;
                                }
                            }
                        }
                    }
                }
            },
            _initMonthDay: function () {
                var that = this;
                var rule = that._value;
                var monthDayInput = that._container.find('.k-recur-monthday');
                if (monthDayInput[0]) {
                    that._monthDay = new kendo.ui.NumericTextBox(monthDayInput, {
                        spinners: that.options.spinners,
                        min: 1,
                        max: 31,
                        decimals: 0,
                        format: '#',
                        value: rule.monthDays ? rule.monthDays[0] : that.options.start.getDate(),
                        change: function () {
                            var value = this.value();
                            rule.monthDays = value ? [value] : value;
                            that._trigger();
                        }
                    });
                }
            },
            _initCount: function () {
                var that = this, input = that._container.find('.k-recur-count'), rule = that._value;
                that._count = input.kendoNumericTextBox({
                    spinners: that.options.spinners,
                    value: rule.count || 1,
                    decimals: 0,
                    format: '#',
                    min: 1,
                    change: function () {
                        rule.count = this.value();
                        that._trigger();
                    }
                }).data('kendoNumericTextBox');
            },
            _initUntil: function () {
                var that = this, input = that._container.find('.k-recur-until'), start = that.options.start, rule = that._value, until = rule.until;
                that._until = input.kendoDatePicker({
                    min: until && until < start ? until : start,
                    value: until || new Date(start.getFullYear(), start.getMonth(), start.getDate(), 23, 59, 59),
                    change: function () {
                        var date = this.value();
                        rule.until = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
                        that._trigger();
                    }
                }).data('kendoDatePicker');
            },
            _trigger: function () {
                if (!this.options.mobile) {
                    this.trigger('change');
                }
            }
        });
        var RecurrenceEditor = BaseRecurrenceEditor.extend({
            init: function (element, options) {
                var that = this;
                BaseRecurrenceEditor.fn.init.call(that, element, options);
                that._initFrequency();
                that._initContainer();
                that.value(that.options.value);
            },
            options: { name: 'RecurrenceEditor' },
            events: ['change'],
            destroy: function () {
                var that = this;
                that._frequency.destroy();
                that._container.find('input[type=radio],input[type=checkbox]').off(CLICK + that._namespace);
                kendo.destroy(that._container);
                BaseRecurrenceEditor.fn.destroy.call(that);
            },
            value: function (value) {
                var that = this;
                var timezone = that.options.timezone;
                var freq;
                if (value === undefined) {
                    if (!that._value.freq) {
                        return '';
                    }
                    return serialize(that._value, timezone);
                }
                that._value = parseRule(value, timezone) || {};
                freq = that._value.freq;
                if (freq) {
                    that._frequency.value(freq);
                } else {
                    that._frequency.select(0);
                }
                that._initView(that._frequency.value());
            },
            _initContainer: function () {
                var element = this.element, container = $('<div class="k-recur-view" />'), editContainer = element.parent('.k-edit-field');
                if (editContainer[0]) {
                    container.insertAfter(editContainer);
                } else {
                    element.append(container);
                }
                this._container = container;
            },
            _initFrequency: function () {
                var that = this, options = that.options, frequencies = options.frequencies, messages = options.messages.frequencies, ddl = $('<input />').attr({ title: options.messages.recurrenceEditorTitle }), frequency;
                frequencies = $.map(frequencies, function (frequency) {
                    return {
                        text: messages[frequency],
                        value: frequency
                    };
                });
                frequency = frequencies[0];
                if (frequency && frequency.value === 'never') {
                    frequency.value = '';
                }
                that.element.append(ddl);
                that._frequency = new DropDownList(ddl, {
                    dataTextField: 'text',
                    dataValueField: 'value',
                    dataSource: frequencies,
                    change: function () {
                        that._value = {};
                        that._initView(that._frequency.value());
                        that.trigger('change');
                    }
                });
            },
            _initView: function (frequency) {
                var that = this;
                var rule = that._value;
                var options = that.options;
                var data = {
                    frequency: frequency || 'never',
                    weekDayCheckBoxes: weekDayCheckBoxes,
                    firstWeekDay: options.firstWeekDay,
                    messages: options.messages[frequency],
                    end: options.messages.end
                };
                kendo.destroy(that._container);
                that._container.html(RECURRENCE_VIEW_TEMPLATE(data));
                if (!frequency) {
                    that._value = {};
                    return;
                }
                rule.freq = frequency;
                if (frequency === 'weekly' && !rule.weekDays) {
                    rule.weekDays = [{
                            day: options.start.getDay(),
                            offset: 0
                        }];
                }
                that._initInterval();
                that._initWeekDays();
                that._initMonthDay();
                that._initWeekDay();
                that._initMonth();
                that._initCount();
                that._initUntil();
                that._period();
                that._end();
            },
            _initMonth: function () {
                var that = this;
                var rule = that._value;
                var month = rule.months || [that.options.start.getMonth() + 1];
                var monthInputs = that._container.find('.k-recur-month');
                var options;
                if (monthInputs[0]) {
                    options = {
                        change: function () {
                            rule.months = [Number(this.value())];
                            that.trigger('change');
                        },
                        dataTextField: 'text',
                        dataValueField: 'value',
                        dataSource: $.map(kendo.culture().calendar.months.names, function (monthName, idx) {
                            return {
                                text: monthName,
                                value: idx + 1
                            };
                        })
                    };
                    that._month1 = new DropDownList(monthInputs[0], options);
                    that._month2 = new DropDownList(monthInputs[1], options);
                    if (month) {
                        month = month[0];
                        that._month1.value(month);
                        that._month2.value(month);
                    }
                }
            },
            _end: function () {
                var that = this;
                var rule = that._value;
                var container = that._container;
                var namespace = that._namespace;
                var click = function (e) {
                    that._toggleEnd(e.currentTarget.value);
                    that.trigger('change');
                };
                var endRule;
                that._buttonNever = container.find('.k-recur-end-never').on(CLICK + namespace, click);
                that._buttonCount = container.find('.k-recur-end-count').on(CLICK + namespace, click);
                that._buttonUntil = container.find('.k-recur-end-until').on(CLICK + namespace, click);
                if (rule.count) {
                    endRule = 'count';
                } else if (rule.until) {
                    endRule = 'until';
                }
                that._toggleEnd(endRule);
            },
            _period: function () {
                var that = this;
                var rule = that._value;
                var monthly = rule.freq === 'monthly';
                var toggleRule = monthly ? that._toggleMonthDay : that._toggleYear;
                var selector = '.k-recur-' + (monthly ? 'month' : 'year') + '-radio';
                var radioButtons = that._container.find(selector);
                if (!monthly && rule.freq !== 'yearly') {
                    return;
                }
                radioButtons.on(CLICK + that._namespace, function (e) {
                    toggleRule.call(that, e.currentTarget.value);
                    that.trigger('change');
                });
                that._buttonMonthDay = radioButtons.eq(0);
                that._buttonWeekDay = radioButtons.eq(1);
                toggleRule.call(that, rule.weekDays ? 'weekday' : 'monthday');
            },
            _toggleEnd: function (endRule) {
                var that = this;
                var count, until;
                var enableCount, enableUntil;
                if (endRule === 'count') {
                    that._buttonCount.prop('checked', true);
                    enableCount = true;
                    enableUntil = false;
                    count = that._count.value();
                    until = null;
                } else if (endRule === 'until') {
                    that._buttonUntil.prop('checked', true);
                    enableCount = false;
                    enableUntil = true;
                    count = null;
                    until = that._until.value();
                } else {
                    that._buttonNever.prop('checked', true);
                    enableCount = enableUntil = false;
                    count = until = null;
                }
                if (that._count) {
                    that._count.enable(enableCount);
                }
                if (that._until) {
                    that._until.enable(enableUntil);
                }
                that._value.count = count;
                that._value.until = until;
            },
            _toggleMonthDay: function (monthRule) {
                var that = this;
                var enableMonthDay = false;
                var enableWeekDay = true;
                var clear = false;
                var monthDays;
                if (monthRule === 'monthday') {
                    that._buttonMonthDay.prop('checked', true);
                    monthDays = [that._monthDay.value()];
                    enableMonthDay = true;
                    enableWeekDay = false;
                    clear = true;
                } else {
                    that._buttonWeekDay.prop('checked', true);
                    monthDays = null;
                }
                that._weekDay.enable(enableWeekDay);
                that._weekDayOffset.enable(enableWeekDay);
                that._monthDay.enable(enableMonthDay);
                that._value.monthDays = monthDays;
                that._weekDayRule(clear);
            },
            _toggleYear: function (yearRule) {
                var that = this;
                var enableMonth1 = false;
                var enableMonth2 = true;
                var month;
                if (yearRule === 'monthday') {
                    enableMonth1 = true;
                    enableMonth2 = false;
                    month = that._month1.value();
                } else {
                    month = that._month2.value();
                }
                that._month1.enable(enableMonth1);
                that._month2.enable(enableMonth2);
                that._value.months = [month];
                that._toggleMonthDay(yearRule);
            }
        });
        ui.plugin(RecurrenceEditor);
        var RECURRENCE_HEADER_TEMPLATE = kendo.template('<div data-role="content"><ul><li class="k-item"><label class="k-label"><span class="k-item-title">#:headerTitle#</span>' + '<div class="k-recur-pattern"></div></label></li>' + '<li class="k-item k-recur-view"></li></ul></div>');
        var RECURRENCE_REPEAT_PATTERN_TEMPLATE = kendo.template('# if (frequency !== "never") { #' + '<label class="k-label">' + '<span class="k-item-title">#:messages.repeatEvery#</span>' + '<div class="k-recur-editor-wrap">' + '<input class="k-recur-interval" type="number" pattern="\\\\d*"/>' + '# if (messages.interval.length) { #' + '<label class="k-recur-editor-text">#:messages.interval#</label>' + '# } #' + '</div>' + '</label>' + '# } #' + '# if (frequency === "weekly") { #' + '<ul class="k-recur-items-wrap">' + '<li class="k-item k-no-click"><label class="k-label"><span class="k-item-title">#:messages.repeatOn#</span></label></li>' + '#=weekDayCheckBoxes(firstWeekDay)#' + '</ul>' + '# } else if (frequency === "monthly") { #' + '<ul class="k-recur-items-wrap">' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-item-title">#:messages.repeatBy#</span>' + '<div class="k-repeat-rule"></div>' + '</label>' + '</li>' + '<li class="k-monthday-view k-item" style="display:none">' + '<label class="k-label">' + '<span class="k-item-title">#:messages.day#</span>' + '<div><input class="k-recur-monthday" type="number" title="#:messages.day#" pattern="\\\\d*"/></div>' + '</label>' + '</li>' + '<li class="k-weekday-view k-item" style="display:none">' + '<ul class="k-recur-items-wrap">' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-item-title">#:messages.every#</span>' + '<div><select class="k-recur-weekday-offset" title="#:messages.every#"></select></div>' + '</label>' + '</li>' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-item-title">#:messages.day#</span>' + '<div><select class="k-recur-weekday" title="#:messages.day#"></select></div>' + '</label>' + '</li>' + '</ul>' + '</li>' + '</ul>' + '# } else if (frequency === "yearly") { #' + '<ul class="k-recur-items-wrap">' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-item-title">#:messages.repeatBy#</span>' + '<div class="k-repeat-rule"></div>' + '</label>' + '</li>' + '<li class="k-monthday-view k-item" style="display:none">' + '<label class="k-label">' + '<span class="k-item-title">#:messages.day#</span>' + '<div><input class="k-recur-monthday" type="number" title="#:messages.day#" pattern="\\\\d*"/></div>' + '</label>' + '</li>' + '<li class="k-weekday-view k-item" style="display:none">' + '<ul class="k-recur-items-wrap">' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-item-title">#:messages.every#</span>' + '<div><select class="k-recur-weekday-offset" title="#:messages.every#"></select></div>' + '</label>' + '</li>' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-item-title">#:messages.day#</span>' + '<div><select class="k-recur-weekday" title="#:messages.day#"></select></div>' + '</label>' + '</li>' + '</ul>' + '</li>' + '<li class="k-item">' + '<label class="k-label">' + '<span class="k-item-title">#:messages.month#</span>' + '<div><select class="k-recur-month" title="#:messages.month#"></select></div>' + '</label>' + '</li>' + '</ul>' + '# } #');
        var RECURRENCE_END_PATTERN_TEMPLATE = kendo.template('# if (endPattern === "count") { #' + '<label class="k-label">' + '<span class="k-item-title">#:messages.after#</span>' + '<div><input class="k-recur-count" type="number" pattern="\\\\d*" /></div>' + '</label>' + '# } else if (endPattern === "until") { #' + '<label class="k-label">' + '<span class="k-item-title">#:messages.on#</span>' + '<div><input type="date" class="k-recur-until" /></div>' + '</label>' + '# } #');
        var RECURRENCE_GROUP_BUTTON_TEMPLATE = kendo.template('<select class="k-scheduler-select">' + '#for (var i = 0, length = dataSource.length; i < length; i++) {#' + '<option value="#=dataSource[i].value#" #= value === dataSource[i].value  ? "selected" : "" #>#:dataSource[i].text#</option>' + '#}#' + '</select>');
        var MobileRecurrenceEditor = BaseRecurrenceEditor.extend({
            init: function (element, options) {
                var that = this;
                BaseRecurrenceEditor.fn.init.call(that, element, options);
                options = that.options;
                that._optionTemplate = kendo.template('<option value="#:value#">#:text#</option>');
                that.value(options.value);
                that._pane = options.pane;
                that._initRepeatButton();
                that._initParentRepeatEnd();
                that._defaultValue = that._value;
            },
            options: {
                name: 'MobileRecurrenceEditor',
                animations: {
                    left: 'slide',
                    right: 'slide:right'
                },
                mobile: true,
                messages: {
                    cancel: 'Cancel',
                    update: 'Save',
                    endTitle: 'Repeat ends',
                    repeatTitle: 'Repeat pattern',
                    headerTitle: 'Repeat event',
                    end: {
                        patterns: {
                            never: 'Never',
                            after: 'After...',
                            on: 'On...'
                        },
                        never: 'Never',
                        after: 'End repeat after',
                        on: 'End repeat on'
                    },
                    daily: { interval: '' },
                    hourly: { interval: '' },
                    weekly: { interval: '' },
                    monthly: {
                        interval: '',
                        repeatBy: 'Repeat by: ',
                        dayOfMonth: 'Day of the month',
                        dayOfWeek: 'Day of the week',
                        repeatEvery: 'Repeat every',
                        every: 'Every',
                        day: 'Day '
                    },
                    yearly: {
                        interval: '',
                        repeatBy: 'Repeat by: ',
                        dayOfMonth: 'Day of the month',
                        dayOfWeek: 'Day of the week',
                        repeatEvery: 'Repeat every: ',
                        every: 'Every',
                        month: 'Month',
                        day: 'Day'
                    }
                }
            },
            events: ['change'],
            value: function (value) {
                var that = this;
                var timezone = that.options.timezone;
                if (value === undefined) {
                    if (!that._value.freq) {
                        return '';
                    }
                    return serialize(that._value, timezone);
                }
                that._value = parseRule(value, timezone) || {};
            },
            destroy: function () {
                this._destroyView();
                kendo.destroy(this._endFields);
                this.element.off(CLICK + this._namespace);
                BaseRecurrenceEditor.fn.destroy.call(this);
            },
            _initInterval: function () {
                var that = this;
                var rule = that._value;
                that._container.find('.k-recur-interval').val(that._value.interval || 1).on(CHANGE + that._namespace, function (e) {
                    rule.interval = e.target.value;
                    that._trigger();
                });
            },
            _initRepeatButton: function () {
                var that = this;
                var freq = that.options.messages.frequencies[this._value.freq || 'never'];
                that._chevronButton = $('<span class="k-icon k-i-arrow-chevron-right"></span>');
                that._repeatValue = $('<span class="">' + freq + '</span>');
                that.element.append(that._repeatValue).append(that._chevronButton);
                that.element.parents('li.k-item').on(CLICK + that._namespace, function (e) {
                    e.preventDefault();
                    that._createView('repeat');
                    that._pane.navigate(that._view, that.options.animations.left);
                });
            },
            _endLiItem: function () {
                var that = this;
                return '<li class="k-item"><label class="k-label"><span class="k-item-title">' + that.options.messages.end.mobileLabel + '</span><label></li>';
            },
            _initParentRepeatEnd: function () {
                var that = this;
                var endLabelField = $(that._endLiItem()).insertAfter(that.element.parents('li.k-item'));
                var endEditField = $('<div class="k-scheduler-recur-end-wrap"><span class="k-scheduler-recur-end"></span></div>').appendTo(endLabelField.find('.k-label'));
                endLabelField.on(CLICK + that._namespace, function (e) {
                    e.preventDefault();
                    that._navigateToView('repeat');
                });
                that._endParentLabelField = endLabelField.toggle(!!that._value.freq);
                that._endParentEndButton = endEditField.find('.k-scheduler-recur-end').text(that._endText());
            },
            _initRepeatEnd: function () {
                var that = this;
                var endLabelField = $(that._endLiItem()).insertAfter(that._container);
                var endEditField = $('<div class="k-scheduler-recur-end-wrap"><span class="k-scheduler-recur-end"></span><span class="k-icon k-i-arrow-chevron-right"></span></div>').appendTo(endLabelField.find('.k-label'));
                endLabelField.on(CLICK + that._namespace, function (e) {
                    e.preventDefault();
                    that._navigateToView('end');
                });
                that._endLabelField = endLabelField.toggleClass('k-state-disabled', !that._value.freq);
                that._endButton = endEditField.find('.k-scheduler-recur-end').text(that._endText());
            },
            _navigateToView: function (viewName) {
                var that = this;
                that._createView(viewName);
                that._pane.navigate(that._view, that.options.animations.left);
            },
            _endText: function () {
                var rule = this._value;
                var messages = this.options.messages.end;
                var text = messages.never;
                if (rule.count) {
                    text = kendo.format('{0} {1}', messages.after, rule.count);
                } else if (rule.until) {
                    text = kendo.format('{0} {1:d}', messages.on, rule.until);
                }
                return text;
            },
            _initFrequency: function () {
                var that = this;
                var frequencyMessages = that.options.messages.frequencies;
                var html = RECURRENCE_GROUP_BUTTON_TEMPLATE({
                    dataSource: $.map(this.options.frequencies, function (frequency) {
                        return {
                            text: frequencyMessages[frequency],
                            value: frequency !== 'never' ? frequency : ''
                        };
                    }),
                    value: that._value.freq || '',
                    ns: kendo.ns
                });
                that._view.element.find('.k-recur-pattern').append(html);
                that._view.element.find('.k-scheduler-select').on(CHANGE + that._namespace, function (e) {
                    var value = e.target.value;
                    that._value = { freq: value };
                    that._initRepeatView(true);
                });
            },
            _initEndNavigation: function () {
                var that = this;
                var endMessages = that.options.messages.end.patterns;
                var rule = that._value;
                var value = '';
                if (rule.count) {
                    value = 'count';
                } else if (rule.until) {
                    value = 'until';
                }
                var html = RECURRENCE_GROUP_BUTTON_TEMPLATE({
                    dataSource: [
                        {
                            text: endMessages.never,
                            value: ''
                        },
                        {
                            text: endMessages.after,
                            value: 'count'
                        },
                        {
                            text: endMessages.on,
                            value: 'until'
                        }
                    ],
                    value: value,
                    ns: kendo.ns
                });
                that._view.element.find('.k-recur-pattern').append(html);
                that._view.element.find('.k-scheduler-select').on(CHANGE + that._namespace, function (e) {
                    var value = e.target.value;
                    var count = null;
                    var until = null;
                    that._initEndView(value);
                    if (that._count.length) {
                        count = that._count.val();
                        until = null;
                    } else if (that._until.length) {
                        count = null;
                        until = that._until.val ? kendo.parseDate(that._until.val(), 'yyyy-MM-dd') : that._until.value();
                    }
                    rule.count = count;
                    rule.until = until;
                });
            },
            _createView: function (viewType) {
                var that = this;
                var options = that.options;
                var messages = options.messages;
                var headerTitle = messages[viewType === 'repeat' ? 'repeatTitle' : 'endTitle'];
                var html = '<div data-role="view" class="k-popup-edit-form k-scheduler-edit-form k-mobile-list" id="recurrence">' + '<div data-role="header" class="k-header">' + '<a href="#" class="k-header-cancel k-scheduler-cancel k-link" title="' + messages.cancel + '"' + 'aria-label="' + messages.cancel + '"><span class="k-icon k-i-arrow-chevron-left"></span></a>' + messages.headerTitle + '<a href="#" class="k-header-done k-scheduler-update k-link" title="' + messages.update + '" ' + 'aria-label="' + messages.update + '"><span class="k-icon k-i-check"></span></a>' + '</div>';
                var returnViewId = that._pane.view().id;
                that._view = that._pane.append(html + RECURRENCE_HEADER_TEMPLATE({ headerTitle: headerTitle }));
                that._view.element.on(CLICK + that._namespace, 'a.k-scheduler-cancel, a.k-scheduler-update', function (e) {
                    e.preventDefault();
                    e.stopPropagation();
                    if ($(this).hasClass('k-scheduler-update')) {
                        that.trigger('change');
                        that._defaultValue = $.extend({}, that._value);
                    } else {
                        that._value = that._defaultValue;
                    }
                    var frequency = that._value.freq;
                    that._endParentEndButton.text(that._endText());
                    that._endParentLabelField.toggle(!!frequency && frequency !== 'never');
                    that._endButton.text(that._endText());
                    that._repeatValue.text(messages.frequencies[frequency || 'never']);
                    that._pane.one('viewShow', function () {
                        that._destroyView();
                    });
                    that._pane.navigate(returnViewId, that.options.animations.right);
                });
                that._container = that._view.element.find('.k-recur-view');
                if (viewType === 'repeat') {
                    that._initFrequency();
                    that._initRepeatView(true);
                    that._initRepeatEnd();
                } else {
                    that._initEndNavigation();
                    that._initEndView();
                }
            },
            _destroyView: function () {
                if (this._view) {
                    this._view.destroy();
                    this._view.element.remove();
                    this._container = null;
                }
                this._view = null;
            },
            _initRepeatView: function (isMobile) {
                var that = this;
                var frequency = that._value.freq || 'never';
                var data = {
                    frequency: frequency,
                    weekDayCheckBoxes: isMobile ? mobileWeekDayCheckBoxes : weekDayCheckBoxes,
                    firstWeekDay: that.options.firstWeekDay,
                    messages: that.options.messages[frequency]
                };
                var html = RECURRENCE_REPEAT_PATTERN_TEMPLATE(data);
                var container = that._container = that._container || this._pane.view().content.find('li.k-recur-view');
                var rule = that._value;
                if (that._endLabelField) {
                    that._endLabelField.toggleClass('k-state-disabled', frequency === 'never');
                }
                kendo.destroy(container);
                container.html(html);
                if (!html) {
                    that._value = {};
                    container.hide();
                    return;
                } else {
                    container.show();
                }
                if (frequency === 'weekly' && !rule.weekDays) {
                    rule.weekDays = [{
                            day: that.options.start.getDay(),
                            offset: 0
                        }];
                }
                that._initInterval();
                that._initMonthDay();
                that._initWeekDays();
                that._initWeekDay();
                that._initMonth();
                that._period();
            },
            _initMonthDay: function () {
                var that = this;
                var rule = that._value;
                var monthDayInput = that._monthDay = that._container.find('.k-recur-monthday');
                monthDayInput.attr({
                    min: 1,
                    max: 31
                }).val(rule.monthDays ? rule.monthDays[0] : that.options.start.getDate()).on(CHANGE + that._namespace, function (e) {
                    rule.count = e.target.value;
                    that._trigger();
                });
            },
            _initCount: function () {
                var that = this, input = that._count = that._container.find('.k-recur-count'), rule = that._value;
                input.val(rule.count || 1).on(CHANGE + that._namespace, function (ev) {
                    rule.count = ev.target.value;
                    that._trigger();
                });
            },
            _initEndView: function (endPattern) {
                var that = this;
                var rule = that._value;
                if (endPattern === undefined) {
                    if (rule.count) {
                        endPattern = 'count';
                    } else if (rule.until) {
                        endPattern = 'until';
                    }
                }
                var data = {
                    endPattern: endPattern,
                    messages: that.options.messages.end
                };
                kendo.destroy(that._container);
                that._container.html(RECURRENCE_END_PATTERN_TEMPLATE(data));
                that._initCount();
                that._initUntil();
            },
            _initWeekDay: function () {
                var that = this, data;
                var weekdayMessage = that.options.messages.weekdays;
                var offsetMessage = that.options.messages.offsetPositions;
                var weekDaySelect = that._container.find('.k-recur-weekday');
                var change = function () {
                    that._weekDayRule();
                    that.trigger('change');
                };
                if (weekDaySelect[0]) {
                    that._weekDayOffset = that._container.find('.k-recur-weekday-offset').html(that._options([
                        {
                            text: offsetMessage.first,
                            value: '1'
                        },
                        {
                            text: offsetMessage.second,
                            value: '2'
                        },
                        {
                            text: offsetMessage.third,
                            value: '3'
                        },
                        {
                            text: offsetMessage.fourth,
                            value: '4'
                        },
                        {
                            text: offsetMessage.last,
                            value: '-1'
                        }
                    ])).change(change);
                    data = [
                        {
                            text: weekdayMessage.day,
                            value: 'day'
                        },
                        {
                            text: weekdayMessage.weekday,
                            value: 'weekday'
                        },
                        {
                            text: weekdayMessage.weekend,
                            value: 'weekend'
                        }
                    ];
                    data = data.concat($.map(kendo.culture().calendar.days.names, function (dayName, idx) {
                        return {
                            text: dayName,
                            value: idx
                        };
                    }));
                    that._weekDay = weekDaySelect.html(that._options(data)).change(change).val(that.options.start.getDay());
                    that._weekDayView();
                }
            },
            _initMonth: function () {
                var that = this;
                var rule = that._value;
                var start = that.options.start;
                var month = rule.months || [start.getMonth() + 1];
                var monthSelect = that._container.find('.k-recur-month');
                var monthNames = kendo.culture().calendar.months.names;
                if (monthSelect[0]) {
                    var data = $.map(monthNames, function (monthName, idx) {
                        return {
                            text: monthName,
                            value: idx + 1
                        };
                    });
                    monthSelect.html(that._options(data)).change(function () {
                        rule.months = [Number(this.value)];
                    });
                    that._monthSelect = monthSelect;
                    if (month) {
                        monthSelect.val(month[0]);
                    }
                }
            },
            _period: function () {
                var that = this;
                var rule = that._value;
                var container = that._container;
                var messages = that.options.messages[rule.freq];
                var repeatRuleGroupButton = container.find('.k-repeat-rule');
                var weekDayView = container.find('.k-weekday-view');
                var monthDayView = container.find('.k-monthday-view');
                if (repeatRuleGroupButton[0]) {
                    var currentValue = rule.weekDays ? 'weekday' : 'monthday';
                    var html = RECURRENCE_GROUP_BUTTON_TEMPLATE({
                        value: currentValue,
                        dataSource: [
                            {
                                text: messages.dayOfMonth,
                                value: 'monthday'
                            },
                            {
                                text: messages.dayOfWeek,
                                value: 'weekday'
                            }
                        ],
                        ns: kendo.ns
                    });
                    var init = function (val) {
                        var weekDayName = that._weekDay.val();
                        var weekDayOffset = that._weekDayOffset.val();
                        var monthDay = that._monthDay.val();
                        var month = that._monthSelect ? that._monthSelect.val() : null;
                        if (val === 'monthday') {
                            rule.weekDays = null;
                            rule.monthDays = monthDay ? [monthDay] : monthDay;
                            rule.months = month ? [Number(month)] : month;
                            weekDayView.hide();
                            monthDayView.show();
                        } else {
                            rule.monthDays = null;
                            rule.months = month ? [Number(month)] : month;
                            rule.weekDays = [{
                                    offset: Number(weekDayOffset),
                                    day: Number(weekDayName)
                                }];
                            weekDayView.show();
                            monthDayView.hide();
                        }
                    };
                    repeatRuleGroupButton.append(html);
                    repeatRuleGroupButton.find('.k-scheduler-select').on(CHANGE + that._namespace, function (e) {
                        init(e.target.value);
                    });
                    init(currentValue);
                }
            },
            _initUntil: function () {
                var that = this;
                var input = that._container.find('.k-recur-until');
                var start = that.options.start;
                var rule = that._value;
                var until = rule.until;
                var min = until && until < start ? until : start;
                if (kendo.support.input.date) {
                    that._until = input.attr('min', kendo.toString(min, 'yyyy-MM-dd')).val(kendo.toString(until || start, 'yyyy-MM-dd')).on('change', function () {
                        rule.until = kendo.parseDate(this.value, 'yyyy-MM-dd');
                    });
                } else {
                    that._until = input.kendoDatePicker({
                        min: min,
                        value: until || start,
                        change: function () {
                            rule.until = this.value();
                        }
                    }).data('kendoDatePicker');
                }
            },
            _options: function (data, optionLabel) {
                var idx = 0;
                var html = '';
                var length = data.length;
                var template = this._optionTemplate;
                if (optionLabel) {
                    html += template({
                        value: '',
                        text: optionLabel
                    });
                }
                for (; idx < length; idx++) {
                    html += template(data[idx]);
                }
                return html;
            }
        });
        ui.plugin(MobileRecurrenceEditor);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.timelineview', ['kendo.scheduler.view'], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.timelineview',
        name: 'Scheduler Timeline View',
        category: 'web',
        description: 'The Scheduler Timeline View',
        depends: ['scheduler.view'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, setTime = kendo.date.setTime, SchedulerView = ui.SchedulerView, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, extend = $.extend, proxy = $.proxy, getDate = kendo.date.getDate, getMilliseconds = kendo.date.getMilliseconds, MS_PER_DAY = kendo.date.MS_PER_DAY, MS_PER_MINUTE = kendo.date.MS_PER_MINUTE, CURRENT_TIME_MARKER_CLASS = 'k-current-time', CURRENT_TIME_MARKER_ARROW_CLASS = 'k-current-time-arrow', SCHEDULER_HEADER_WRAP_CLASS = 'k-scheduler-header-wrap', INVERSE_COLOR_CLASS = 'k-event-inverse', BORDER_SIZE_COEFF = 0.8666, NS = '.kendoTimelineView';
        var EVENT_TEMPLATE = kendo.template('<div>' + '<div class="k-event-template k-event-time">#:kendo.format("{0:t} - {1:t}", start, end)#</div>' + '<div class="k-event-template">${title}</div></div>'), DATA_HEADER_TEMPLATE = kendo.template('<span class=\'k-link k-nav-day\'>#=kendo.format(\'{0:m}\', date)#</span>'), EVENT_WRAPPER_STRING = '<div role="gridcell" aria-selected="false" ' + 'data-#=ns#uid="#=uid#"' + '#if (resources[0]) { #' + 'style="background-color:#=resources[0].color#; border-color: #=resources[0].color#"' + 'class="k-event" ' + '#} else {#' + 'class="k-event"' + '#}#' + '>' + '<span class="k-event-actions">' + '# if(data.tail) {#' + '<span class="k-icon k-i-arrow-60-left"></span>' + '#}#' + '# if(data.isException()) {#' + '<span class="k-icon k-i-non-recurrence"></span>' + '# } else if(data.isRecurring()) {#' + '<span class="k-icon k-i-reload"></span>' + '# } #' + '</span>' + '{0}' + '<span class="k-event-actions">' + '#if (showDelete) {#' + '<a href="\\#" class="k-link k-event-delete" title="${data.messages.destroy}" aria-label="${data.messages.destroy}"><span class="k-icon k-i-close"></span></a>' + '#}#' + '# if(data.head) {#' + '<span class="k-icon k-i-arrow-60-right"></span>' + '#}#' + '</span>' + '#if(resizable && !data.tail){#' + '<span class="k-resize-handle k-resize-w"></span>' + '#}#' + '#if(resizable && !data.head){#' + '<span class="k-resize-handle k-resize-e"></span>' + '#}#' + '</div>';
        function toInvariantTime(date) {
            var staticDate = new Date(1980, 1, 1, 0, 0, 0);
            setTime(staticDate, getMilliseconds(date));
            return staticDate;
        }
        function getWorkDays(options) {
            var workDays = [];
            var dayIndex = options.workWeekStart % 7;
            var workWeekEnd = Math.abs(options.workWeekEnd % 7);
            workDays.push(dayIndex);
            while (workWeekEnd != dayIndex) {
                if (dayIndex > 6) {
                    dayIndex -= 7;
                } else {
                    dayIndex++;
                }
                workDays.push(dayIndex);
            }
            return workDays;
        }
        function setColspan(columnLevel) {
            var count = 0;
            if (columnLevel.columns) {
                for (var i = 0; i < columnLevel.columns.length; i++) {
                    count += setColspan(columnLevel.columns[i]);
                }
                columnLevel.colspan = count;
                return count;
            } else {
                columnLevel.colspan = 1;
                return 1;
            }
        }
        function collidingEvents(elements, left, right) {
            var idx, startPosition, overlaps, endPosition;
            for (idx = elements.length - 1; idx >= 0; idx--) {
                startPosition = elements[idx].rectLeft;
                endPosition = elements[idx].rectRight;
                overlaps = startPosition <= left && endPosition >= left;
                if (overlaps || startPosition >= left && endPosition <= right || left <= startPosition && right >= startPosition) {
                    if (startPosition < left) {
                        left = startPosition;
                    }
                    if (endPosition > right) {
                        right = endPosition;
                    }
                }
            }
            return eventsForSlot(elements, left, right);
        }
        function eventsForSlot(elements, left, right) {
            var events = [];
            for (var idx = 0; idx < elements.length; idx++) {
                var event = {
                    rectLeft: elements[idx].rectLeft,
                    rectRight: elements[idx].rectRight
                };
                if (event.rectLeft < left && event.rectRight > left || event.rectLeft >= left && event.rectRight <= right) {
                    events.push(elements[idx]);
                }
            }
            return events;
        }
        var TimelineGroupedView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _getTimeSlotByPosition: function (x, y, groupIndex) {
                var group = this._view.groups[groupIndex];
                return group.timeSlotByPosition(x, y);
            },
            _hideHeaders: function () {
                var view = this._view;
                view.timesHeader.find('table tr:last').hide();
                view.datesHeader.find('table tr:last').hide();
            },
            _setColspan: function (timeColumn) {
                setColspan(timeColumn);
            },
            _createRowsLayout: function (resources, rows, groupHeaderTemplate) {
                var view = this._view;
                return view._createRowsLayout(resources, rows, groupHeaderTemplate);
            },
            _createVerticalColumnsLayout: function (resources, rows, groupHeaderTemplate, columns) {
                return columns;
            },
            _createColumnsLayout: function (resources, columns, groupHeaderTemplate) {
                var view = this._view;
                return view._createColumnsLayout(resources, columns, groupHeaderTemplate);
            },
            _getRowCount: function () {
                var view = this._view;
                return view._groupCount();
            },
            _getGroupsCount: function () {
                return 1;
            },
            _addContent: function (dates, columnCount, groupsCount, rowCount, start, end, slotTemplate, isVerticalGrouped) {
                var view = this._view;
                var html = '';
                var options = view.options;
                var appendRow = function (date) {
                    var content = '';
                    var classes = '';
                    var tmplDate;
                    var resources = function (groupIndex) {
                        return function () {
                            return view._resourceBySlot({ groupIndex: groupIndex });
                        };
                    };
                    if (kendo.date.isToday(dates[idx])) {
                        classes += 'k-today';
                    }
                    if (kendo.date.getMilliseconds(date) < kendo.date.getMilliseconds(options.workDayStart) || kendo.date.getMilliseconds(date) >= kendo.date.getMilliseconds(options.workDayEnd) || !view._isWorkDay(dates[idx])) {
                        classes += ' k-nonwork-hour';
                    }
                    content += '<td' + (classes !== '' ? ' class="' + classes + '"' : '') + '>';
                    tmplDate = kendo.date.getDate(dates[idx]);
                    kendo.date.setTime(tmplDate, kendo.date.getMilliseconds(date));
                    content += slotTemplate({
                        date: tmplDate,
                        resources: resources(isVerticalGrouped ? rowIdx : groupIdx)
                    });
                    content += '</td>';
                    return content;
                };
                for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
                    html += '<tr>';
                    for (var groupIdx = 0; groupIdx < groupsCount; groupIdx++) {
                        for (var idx = 0, length = columnCount; idx < length; idx++) {
                            html += view._forTimeRange(start, end, appendRow);
                        }
                    }
                    html += '</tr>';
                }
                return html;
            },
            _addTimeSlotsCollections: function (groupCount, datesCount, tableRows, interval, isVerticallyGrouped) {
                var view = this._view;
                var rowCount = tableRows.length;
                if (isVerticallyGrouped) {
                    rowCount = Math.floor(rowCount / groupCount);
                }
                for (var groupIndex = 0; groupIndex < groupCount; groupIndex++) {
                    var rowMultiplier = 0;
                    var group = view.groups[groupIndex];
                    var time;
                    if (isVerticallyGrouped) {
                        rowMultiplier = groupIndex;
                    }
                    var rowIndex = rowMultiplier * rowCount;
                    var cellMultiplier = 0;
                    if (!isVerticallyGrouped) {
                        cellMultiplier = groupIndex;
                    }
                    var cells = tableRows[rowIndex].children;
                    var cellsPerGroup = cells.length / (!isVerticallyGrouped ? groupCount : 1);
                    var cellsPerDay = cellsPerGroup / datesCount;
                    for (var dateIndex = 0; dateIndex < datesCount; dateIndex++) {
                        var cellOffset = dateIndex * cellsPerDay + cellsPerGroup * cellMultiplier;
                        time = getMilliseconds(new Date(+view.startTime()));
                        for (var cellIndex = 0; cellIndex < cellsPerDay; cellIndex++) {
                            view._addTimeSlotToCollection(group, cells, cellIndex, cellOffset, dateIndex, time, interval);
                            time += interval;
                        }
                    }
                }
            },
            _getVerticalGroupCount: function (groupsCount) {
                return groupsCount;
            },
            _getVerticalRowCount: function (eventGroups, groupIndex, maxRowCount) {
                var view = this._view;
                return view._isVerticallyGrouped() ? eventGroups[groupIndex].maxRowCount : maxRowCount;
            },
            _renderEvent: function (eventGroup, event, adjustedEvent, group, range, container) {
                var view = this._view;
                var element;
                element = view._createEventElement(adjustedEvent.occurrence, event, range.head || adjustedEvent.head, range.tail || adjustedEvent.tail);
                element.appendTo(container).css({
                    top: 0,
                    height: view.options.eventHeight
                });
                var eventObject = {
                    start: adjustedEvent.occurrence._startTime || adjustedEvent.occurrence.start,
                    end: adjustedEvent.occurrence._endTime || adjustedEvent.occurrence.end,
                    element: element,
                    uid: event.uid,
                    slotRange: range,
                    rowIndex: 0,
                    offsetTop: 0
                };
                eventGroup.events[event.uid] = eventObject;
                view._inverseEventColor(element);
                view.addContinuousEvent(group, range, element, event.isAllDay);
                view._arrangeRows(eventObject, range, eventGroup);
            },
            _verticalCountForLevel: function (level) {
                var view = this._view;
                return view._rowCountForLevel(level);
            },
            _horizontalCountForLevel: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level);
            },
            _updateCurrentVerticalTimeMarker: function (ranges, currentTime) {
                var view = this._view;
                var elementHtml = '<div class=\'' + CURRENT_TIME_MARKER_CLASS + '\'></div>';
                var headerWrap = view.datesHeader.find('.' + SCHEDULER_HEADER_WRAP_CLASS);
                var left = Math.round(ranges[0].innerRect(currentTime, new Date(currentTime.getTime() + 1), false).left);
                var timesTableMarker = $(elementHtml).prependTo(headerWrap).addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-down');
                timesTableMarker.css({
                    left: view._adjustLeftPosition(left - outerWidth(timesTableMarker) * BORDER_SIZE_COEFF / 2),
                    top: headerWrap.find('tr:last').prev().position().top
                });
                $(elementHtml).prependTo(view.content).css({
                    left: view._adjustLeftPosition(left),
                    width: '1px',
                    height: view.content[0].scrollHeight - 1,
                    top: 0
                });
            },
            _changeGroup: function () {
                return undefined;
            },
            _prevGroupSlot: function (slot, group, isDay) {
                var view = this._view;
                if (view._isVerticallyGrouped()) {
                    return slot;
                } else {
                    var collection = group._collection(0, isDay);
                    return collection.last();
                }
            },
            _nextGroupSlot: function (slot, group, isDay) {
                var view = this._view;
                if (view._isVerticallyGrouped()) {
                    return slot;
                } else {
                    var collection = group._collection(0, isDay);
                    return collection.first();
                }
            },
            _verticalSlots: function (selection, reverse) {
                var view = this._view;
                return view._changeGroup(selection, reverse);
            },
            _verticalMethod: function (reverse) {
                return reverse ? 'leftSlot' : 'rightSlot';
            },
            _normalizeVerticalSelection: function () {
                return undefined;
            },
            _horizontalSlots: function (selection, group, method, startSlot, endSlot, multiple, reverse) {
                var view = this._view;
                var result = {};
                result.startSlot = group[method](startSlot);
                result.endSlot = group[method](endSlot);
                if (!multiple && view._isHorizontallyGrouped() && (!result.startSlot || !result.endSlot)) {
                    result.startSlot = result.endSlot = view._changeGroup(selection, reverse);
                }
                return result;
            },
            _changeVerticalViewPeriod: function () {
                return false;
            },
            _changeHorizontalViewPeriod: function (slots, shift, selection, reverse) {
                var view = this._view;
                if ((!slots.startSlot || !slots.endSlot) && !shift && view._changeViewPeriod(selection, reverse, false)) {
                    return true;
                }
                return false;
            },
            _updateDirection: function (selection, ranges, shift, reverse) {
                var view = this._view;
                view._updateDirection(selection, ranges, shift, reverse, true);
            },
            _createMoveHint: function (range, adjustedEvent) {
                var view = this._view;
                var startSlot = range.start;
                var hint = view._createEventElement(adjustedEvent.occurrence, adjustedEvent.occurrence, false, false);
                hint.addClass('k-event-drag-hint');
                var rect = range.innerRect(adjustedEvent.occurrence.start, adjustedEvent.occurrence.end, view.options.snap);
                var width = rect.right - rect.left - 2;
                if (width < 0) {
                    width = 0;
                }
                var left = view._adjustLeftPosition(rect.left);
                var css = {
                    left: left,
                    top: startSlot.offsetTop,
                    height: startSlot.offsetHeight - 2,
                    width: width
                };
                hint.css(css);
                if (adjustedEvent.occurrence.inverseColor) {
                    hint.addClass(INVERSE_COLOR_CLASS);
                }
                view._appendMoveHint(hint);
            },
            _adjustLeftPosition: function (left) {
                var view = this._view;
                if (view._isRtl) {
                    left -= view.content[0].scrollWidth - view.content[0].clientWidth;
                }
                return left;
            }
        });
        var TimelineGroupedByDateView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _getTimeSlotByPosition: function (x, y, groupIndex) {
                var group = this._view.groups[groupIndex];
                return group.timeSlotByPosition(x, y, true);
            },
            _hideHeaders: function () {
                var view = this._view;
                if (!view._isVerticallyGrouped()) {
                    view.timesHeader.find('table tr').eq(2).hide();
                    view.datesHeader.find('table tr').eq(2).hide();
                } else {
                    view.times.find('.k-last').hide();
                }
            },
            _setColspan: function () {
            },
            _createRowsLayout: function (resources, rows, groupHeaderTemplate, columns) {
                var view = this._view;
                return view._createDateLayout(columns, null, true);
            },
            _createVerticalColumnsLayout: function (resources, rows, groupHeaderTemplate) {
                var view = this._view;
                return view._createColumnsLayout(resources, null, groupHeaderTemplate);
            },
            _createColumnsLayout: function (resources, columns, groupHeaderTemplate, subColumns) {
                var view = this._view;
                return view._createColumnsLayout(resources, columns, groupHeaderTemplate, subColumns, true);
            },
            _getRowCount: function (level) {
                var view = this._view;
                return view._rowCountForLevel(level);
            },
            _getGroupsCount: function () {
                var view = this._view;
                return view._groupCount();
            },
            _addContent: function (dates, columnCount, groupsCount, rowCount, start, end, slotTemplate, isVerticalGrouped) {
                var view = this._view;
                var html = '';
                var options = view.options;
                var appendRow = function (date, isMajorTickColumn, isMiddleColumn, isLastSlotColumn, minorTickColumns, groupIdx) {
                    var content = '';
                    var classes = '';
                    var tmplDate;
                    var workDateIndex = view._isVerticallyGrouped() ? dateIndex : idx;
                    var resources = function (groupIndex) {
                        return function () {
                            return view._resourceBySlot({ groupIndex: groupIndex });
                        };
                    };
                    if (kendo.date.isToday(dates[idx])) {
                        classes += 'k-today';
                    }
                    if (kendo.date.getMilliseconds(date) < kendo.date.getMilliseconds(options.workDayStart) || kendo.date.getMilliseconds(date) >= kendo.date.getMilliseconds(options.workDayEnd) || !view._isWorkDay(dates[workDateIndex])) {
                        classes += ' k-nonwork-hour';
                    }
                    content += '<td' + (classes !== '' ? ' class="' + classes + '"' : '') + '>';
                    tmplDate = kendo.date.getDate(dates[idx]);
                    kendo.date.setTime(tmplDate, kendo.date.getMilliseconds(date));
                    content += slotTemplate({
                        date: tmplDate,
                        resources: resources(groupIdx)
                    });
                    content += '</td>';
                    return content;
                };
                var tempStart = new Date(start), minorTickCount = view.options.minorTickCount, msMajorInterval = view.options.majorTick * MS_PER_MINUTE, msInterval = msMajorInterval / minorTickCount || 1, dateIndex;
                for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
                    html += '<tr>';
                    if (rowIdx % (rowCount / view._dates.length) === 0) {
                        dateIndex = rowIdx / (rowCount / view._dates.length);
                        tempStart = new Date(view._dates[dateIndex]);
                        kendo.date.setTime(tempStart, kendo.date.getMilliseconds(start));
                    }
                    for (var idx = 0, length = columnCount; idx < length; idx++) {
                        html += view._forTimeRange(tempStart, end, appendRow, isVerticalGrouped, groupsCount);
                        if (isVerticalGrouped) {
                            setTime(tempStart, msInterval, false);
                            break;
                        }
                    }
                    html += '</tr>';
                }
                return html;
            },
            _addTimeSlotsCollections: function (groupCount, datesCount, tableRows, interval, isVerticallyGrouped) {
                var view = this._view;
                var rowCount = tableRows.length;
                if (isVerticallyGrouped) {
                    rowCount = rowCount / datesCount;
                }
                for (var dateIndex = 0; dateIndex < datesCount; dateIndex++) {
                    var rowMultiplier = 0;
                    var time;
                    if (isVerticallyGrouped) {
                        rowMultiplier = dateIndex;
                    }
                    var rowIndex = rowMultiplier * rowCount;
                    var cellMultiplier = 0;
                    var cells = tableRows[rowIndex].children;
                    var cellsPerGroup = isVerticallyGrouped ? rowCount : cells.length / (datesCount * groupCount);
                    var cellsPerDay = cells.length / datesCount;
                    var cellOffset;
                    time = getMilliseconds(new Date(+view.startTime()));
                    for (var cellIndex = 0; cellIndex < cellsPerGroup; cellIndex++) {
                        if (!isVerticallyGrouped) {
                            cellOffset = dateIndex * cellsPerDay + groupCount * cellIndex;
                            cellMultiplier++;
                        } else {
                            cellOffset = 0;
                            cells = tableRows[cellIndex + cellsPerGroup * dateIndex].children;
                        }
                        for (var groupIndex = 0; groupIndex < groupCount; groupIndex++) {
                            var group = view.groups[groupIndex];
                            view._addTimeSlotToCollection(group, cells, groupIndex, cellOffset, dateIndex, time, interval);
                        }
                        time += interval;
                    }
                }
            },
            _getVerticalGroupCount: function () {
                var view = this._view;
                return view.content.find('tr').length;
            },
            _getVerticalRowCount: function (eventGroups, groupIndex, maxRowCount) {
                return maxRowCount;
            },
            _renderEvent: function (eventGroup, event, adjustedEvent, group, range, container, startIndex, endIndex) {
                var view = this._view;
                var element;
                var eventObjects = [];
                for (var i = range.start.index; i <= range.end.index; i++) {
                    element = view._createEventElement(adjustedEvent.occurrence, event, i !== endIndex, i !== startIndex);
                    element.appendTo(container).css({
                        top: 0,
                        height: view.options.eventHeight
                    });
                    var currentSlot = group._timeSlotCollections[0]._slots[i];
                    var dateRange = group.timeSlotRanges(currentSlot.start, currentSlot.end, false)[0];
                    var eventObject = {
                        start: i === startIndex ? adjustedEvent.occurrence._startTime || adjustedEvent.occurrence.start : currentSlot.start,
                        end: i === endIndex ? adjustedEvent.occurrence._endTime || adjustedEvent.occurrence.end : currentSlot.end,
                        element: element,
                        uid: event.uid,
                        slotRange: dateRange,
                        rowIndex: 0,
                        offsetTop: 0
                    };
                    eventGroup.events[event.uid] = eventObject;
                    eventObjects.push(eventObject);
                    view.addContinuousEvent(group, dateRange, element, event.isAllDay);
                    view._arrangeRows(eventObject, dateRange, eventGroup);
                }
                eventGroup.events[event.uid] = eventObjects;
            },
            _verticalCountForLevel: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level);
            },
            _horizontalCountForLevel: function (level, columnLevel) {
                var view = this._view;
                return view._columnCountForLevel(columnLevel) / view._columnCountForLevel(2);
            },
            _updateCurrentVerticalTimeMarker: function (ranges, currentTime) {
                var view = this._view;
                var firstTimesCell = view.times.find('tr:first th:first');
                var lastTimesCell = view.times.find('tr:first th:last');
                var elementHtml = '<div class=\'' + CURRENT_TIME_MARKER_CLASS + '\'></div>';
                var timesTableMarker = $(elementHtml).prependTo(view.times);
                var markerTopPosition = Math.round(ranges[0].innerRect(currentTime, new Date(currentTime.getTime() + 1), false).top);
                var timesTableMarkerCss = {};
                if (this._isRtl) {
                    timesTableMarkerCss.right = firstTimesCell.position().left + outerHeight(firstTimesCell) - outerHeight(lastTimesCell);
                    timesTableMarker.addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-left');
                } else {
                    timesTableMarkerCss.left = lastTimesCell.position().left;
                    timesTableMarker.addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-right');
                }
                timesTableMarkerCss.top = markerTopPosition - outerWidth(timesTableMarker) * BORDER_SIZE_COEFF / 2;
                timesTableMarker.css(timesTableMarkerCss);
                $(elementHtml).prependTo(view.content).css({
                    top: markerTopPosition,
                    height: '1px',
                    right: '1px',
                    width: view.content[0].scrollWidth,
                    left: 0
                });
            },
            _changeGroup: function (selection, previous, slot) {
                var view = this._view;
                if (!slot) {
                    selection.groupIndex = previous ? view.groups.length - 1 : 0;
                }
            },
            _prevGroupSlot: function (slot) {
                return slot;
            },
            _nextGroupSlot: function (slot) {
                return slot;
            },
            _changeDate: function (selection, reverse, slot) {
                var view = this._view;
                var group = view.groups[selection.groupIndex];
                var collections, index;
                if (reverse) {
                    collections = group._getCollections(false);
                    index = slot.index - 1;
                    if (index >= 0) {
                        return collections[0]._slots[index];
                    }
                } else {
                    collections = group._getCollections(false);
                    index = slot.index + 1;
                    if (collections[0] && collections[0]._slots[index]) {
                        return collections[0]._slots[index];
                    }
                }
            },
            _verticalSlots: function (selection, reverse, slot) {
                return this._changeDate(selection, reverse, slot);
            },
            _verticalMethod: function (reverse, multiple) {
                if (multiple) {
                    return reverse ? 'upSlot' : 'downSlot';
                } else {
                    return reverse ? 'leftSlot' : 'rightSlot';
                }
            },
            _normalizeVerticalSelection: function (selection, ranges, reverse, multiple) {
                var view = this._view;
                if (!multiple) {
                    return view._normalizeVerticalSelection(selection, ranges, reverse);
                }
                return undefined;
            },
            _horizontalSlots: function (selection, group, method, startSlot, endSlot, multiple, reverse) {
                var view = this._view;
                var tempSlot = view._changeGroup(selection, reverse);
                var result = {};
                if (!tempSlot) {
                    if (!view._isVerticallyGrouped()) {
                        result.startSlot = group[method](startSlot);
                        result.endSlot = group[method](endSlot);
                    }
                } else {
                    result.startSlot = result.endSlot = tempSlot;
                }
                return result;
            },
            _changeVerticalViewPeriod: function (slots, shift, selection, reverse) {
                var view = this._view;
                if ((!slots.startSlot || !slots.endSlot) && !shift && view._changeViewPeriod(selection, reverse, view._isVerticallyGrouped())) {
                    return true;
                }
                return false;
            },
            _changeHorizontalViewPeriod: function (slots, shift, selection, reverse) {
                var view = this._view;
                if (view._isVerticallyGrouped()) {
                    return false;
                }
                if ((!slots.startSlot || !slots.endSlot) && !shift && view._changeViewPeriod(selection, reverse, false)) {
                    return true;
                }
                return false;
            },
            _updateDirection: function (selection, ranges, shift, reverse) {
                var view = this._view;
                view._updateDirection(selection, ranges, shift, reverse, !view._isVerticallyGrouped());
            },
            _createMoveHint: function (range, adjustedEvent) {
                var view = this._view;
                var startSlot = range.start;
                var startEnd = range.end;
                for (var slotIdx = startSlot.index; slotIdx <= startEnd.index; slotIdx++) {
                    var slot = range.collection._slots[slotIdx];
                    var hint = view._createEventElement(adjustedEvent.occurrence, adjustedEvent.occurrence, false, false);
                    hint.addClass('k-event-drag-hint');
                    var css = {
                        left: slot.offsetLeft + 2,
                        top: slot.offsetTop,
                        height: view.options.eventHeight,
                        width: slot.offsetWidth
                    };
                    hint.css(css);
                    if (adjustedEvent.occurrence.inverseColor) {
                        hint.addClass(INVERSE_COLOR_CLASS);
                    }
                    view._appendMoveHint(hint);
                }
            },
            _adjustLeftPosition: function (left) {
                var view = this._view;
                if (view._isRtl && !view._isVerticallyGrouped()) {
                    left -= view.content[0].scrollWidth - view.content[0].offsetWidth;
                }
                return left;
            }
        });
        kendo.ui.scheduler.TimelineGroupedView = TimelineGroupedView;
        kendo.ui.scheduler.TimelineGroupedByDateView = TimelineGroupedByDateView;
        var TimelineView = SchedulerView.extend({
            init: function (element, options) {
                var that = this;
                SchedulerView.fn.init.call(that, element, options);
                that._groupedView = that._getGroupedView();
                that.title = that.options.title || that.options.name;
                that._workDays = getWorkDays(that.options);
                that._templates();
                that._editable();
                that.calculateDateRange();
                that._groups();
                that._currentTime(true);
            },
            name: 'timeline',
            _getGroupedView: function () {
                if (this._isGroupedByDate()) {
                    return new kendo.ui.scheduler.TimelineGroupedByDateView(this);
                } else {
                    return new kendo.ui.scheduler.TimelineGroupedView(this);
                }
            },
            _getNextEventIndexBySlot: function (slot, sortedEvents, groupIndex) {
                if (this._isVerticallyGrouped()) {
                    return kendo.ui.SchedulerView.fn._getNextEventIndexBySlot.call(this, slot, sortedEvents, groupIndex);
                }
                var tempIndex = 0;
                for (var i = 0; i < sortedEvents.length; i++) {
                    if (slot.startDate() > sortedEvents[i].start.startDate()) {
                        tempIndex++;
                        continue;
                    }
                    if (slot.startDate().getTime() === sortedEvents[i].start.startDate().getTime() && groupIndex > sortedEvents[i].start.groupIndex) {
                        tempIndex++;
                        continue;
                    }
                    break;
                }
                return tempIndex;
            },
            _getSelectedSlot: function (slot, sortedEvents, event, idx, pad, prev) {
                if (this._isVerticallyGrouped()) {
                    return kendo.ui.SchedulerView.fn._getSelectedSlot.call(this, slot, sortedEvents, event, idx, pad, prev);
                }
                return slot;
            },
            _getSortedEvents: function (uniqueAllEvents) {
                if (this._isVerticallyGrouped()) {
                    return kendo.ui.SchedulerView.fn._getSortedEvents.call(this, uniqueAllEvents);
                }
                return uniqueAllEvents.sort(function (first, second) {
                    var result = first.start.startDate().getTime() - second.start.startDate().getTime();
                    if (result === 0) {
                        if (first.start.isDaySlot && !second.start.isDaySlot) {
                            result = -1;
                        }
                        if (!first.start.isDaySlot && second.start.isDaySlot) {
                            result = 1;
                        }
                    }
                    if (result === 0) {
                        result = first.start.groupIndex - second.start.groupIndex;
                    }
                    if (result === 0) {
                        result = $(first.element).index() - $(second.element).index();
                    }
                    return result;
                });
            },
            _currentTimeMarkerUpdater: function () {
                this._updateCurrentTimeMarker(new Date());
            },
            _updateCurrentTimeMarker: function (currentTime) {
                var options = this.options;
                this.datesHeader.find('.' + CURRENT_TIME_MARKER_CLASS).remove();
                this.times.find('.' + CURRENT_TIME_MARKER_CLASS).remove();
                this.content.find('.' + CURRENT_TIME_MARKER_CLASS).remove();
                if (!this._isInDateSlot({
                        start: currentTime,
                        end: currentTime
                    })) {
                    return;
                }
                if (options.currentTimeMarker.useLocalTimezone === false) {
                    var timezone = options.dataSource.options.schema.timezone;
                    if (options.dataSource && timezone) {
                        var timezoneOffset = kendo.timezone.offset(currentTime, timezone);
                        currentTime = kendo.timezone.convert(currentTime, currentTime.getTimezoneOffset(), timezoneOffset);
                    }
                }
                var groupsCount = !options.group || options.group.orientation == 'vertical' ? 1 : this.groups.length;
                for (var groupIndex = 0; groupIndex < groupsCount; groupIndex++) {
                    var currentGroup = this.groups[groupIndex];
                    if (!currentGroup) {
                        return;
                    }
                    var utcCurrentTime = kendo.date.toUtcTime(currentTime);
                    var ranges = currentGroup.timeSlotRanges(utcCurrentTime, utcCurrentTime + 1);
                    if (ranges.length === 0) {
                        return;
                    }
                    var collection = ranges[0].collection;
                    var slotElement = collection.slotByStartDate(currentTime);
                    if (slotElement) {
                        if (this._isVerticallyGrouped()) {
                            this._groupedView._updateCurrentVerticalTimeMarker(ranges, currentTime);
                        } else {
                            var elementHtml = '<div class=\'' + CURRENT_TIME_MARKER_CLASS + '\'></div>';
                            var headerWrap = this.datesHeader.find('.' + SCHEDULER_HEADER_WRAP_CLASS);
                            var left = Math.round(ranges[0].innerRect(currentTime, new Date(currentTime.getTime() + 1), false).left);
                            var timesTableMarker = $(elementHtml).prependTo(headerWrap).addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-down');
                            timesTableMarker.css({
                                left: this._adjustLeftPosition(left - outerWidth(timesTableMarker) * BORDER_SIZE_COEFF / 2),
                                top: headerWrap.find('tr:last').prev().position().top
                            });
                            $(elementHtml).prependTo(this.content).css({
                                left: this._adjustLeftPosition(left),
                                width: '1px',
                                height: this.content[0].scrollHeight - 1,
                                top: 0
                            });
                        }
                    }
                }
            },
            _adjustLeftPosition: function (left) {
                return this._groupedView._adjustLeftPosition(left);
            },
            _currentTime: function (setUpdateTimer) {
                var that = this;
                var markerOptions = that.options.currentTimeMarker;
                if (markerOptions !== false && markerOptions.updateInterval !== undefined) {
                    that._currentTimeMarkerUpdater();
                    if (setUpdateTimer) {
                        that._currentTimeUpdateTimer = setInterval(proxy(this._currentTimeMarkerUpdater, that), markerOptions.updateInterval);
                    }
                }
            },
            _editable: function () {
                if (this.options.editable) {
                    if (this._isMobile()) {
                        this._touchEditable();
                    } else {
                        this._mouseEditable();
                    }
                }
            },
            _mouseEditable: function () {
                var that = this;
                that.element.on('click' + NS, '.k-event a:has(.k-i-close)', function (e) {
                    that.trigger('remove', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                    e.preventDefault();
                });
                if (that.options.editable.create !== false) {
                    that.element.on('dblclick' + NS, '.k-scheduler-content td', function (e) {
                        var slot = that._slotByPosition(e.pageX, e.pageY);
                        if (slot) {
                            var resourceInfo = that._resourceBySlot(slot);
                            that.trigger('add', {
                                eventInfo: extend({
                                    start: slot.startDate(),
                                    end: slot.endDate()
                                }, resourceInfo)
                            });
                        }
                        e.preventDefault();
                    });
                }
                if (that.options.editable.update !== false) {
                    that.element.on('dblclick' + NS, '.k-event', function (e) {
                        that.trigger('edit', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                        e.preventDefault();
                    });
                }
            },
            _touchEditable: function () {
                var that = this;
                var threshold = 0;
                if (kendo.support.mobileOS.android) {
                    threshold = 5;
                }
                if (that.options.editable.create !== false) {
                    that._addUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        useClickAsTap: !kendo.support.browser.edge,
                        filter: '.k-scheduler-content td',
                        tap: function (e) {
                            if (that._scrolling) {
                                return;
                            }
                            var x = e.x.location !== undefined ? e.x.location : e.x;
                            var y = e.y.location !== undefined ? e.y.location : e.y;
                            var slot = that._slotByPosition(x, y);
                            if (slot) {
                                var resourceInfo = that._resourceBySlot(slot);
                                that.trigger('add', {
                                    eventInfo: extend({
                                        start: slot.startDate(),
                                        end: slot.endDate()
                                    }, resourceInfo)
                                });
                            }
                            e.preventDefault();
                        }
                    });
                }
                if (that.options.editable.update !== false) {
                    that._editUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        useClickAsTap: !kendo.support.browser.edge,
                        filter: '.k-event',
                        tap: function (e) {
                            if (that._scrolling) {
                                return;
                            }
                            var eventElement = $(e.target).closest('.k-event');
                            var touchElement = $(e.touch.initialTouch);
                            if (touchElement.hasClass('k-i-close')) {
                                that.trigger('remove', { uid: eventElement.attr(kendo.attr('uid')) });
                            } else if (!eventElement.hasClass('k-event-active')) {
                                that.trigger('edit', { uid: eventElement.attr(kendo.attr('uid')) });
                            }
                            e.preventDefault();
                        }
                    });
                }
            },
            _slotByPosition: function (x, y) {
                var slot;
                var content = this.content;
                var offset = content.offset();
                var groupIndex;
                x -= offset.left;
                y -= offset.top;
                if (this._isRtl) {
                    var browser = kendo.support.browser;
                    if (browser.mozilla) {
                        x += content[0].scrollWidth - content[0].offsetWidth;
                        x += content[0].scrollLeft;
                    } else if (browser.msie) {
                        x -= content.scrollLeft();
                        x += content[0].scrollWidth - content[0].offsetWidth;
                    } else if (browser.webkit) {
                        x += content[0].scrollLeft;
                    }
                } else {
                    x += content[0].scrollLeft;
                }
                y += content[0].scrollTop;
                x = Math.ceil(x);
                y = Math.ceil(y);
                for (groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                    slot = this._groupedView._getTimeSlotByPosition(x, y, groupIndex);
                    if (slot) {
                        return slot;
                    }
                }
                return null;
            },
            options: {
                name: 'TimelineView',
                title: 'Timeline',
                selectedDateFormat: '{0:D}',
                selectedShortDateFormat: '{0:d}',
                selectedMobileDateFormat: '{0:MMM dd}',
                date: kendo.date.today(),
                startTime: kendo.date.today(),
                endTime: kendo.date.today(),
                showWorkHours: false,
                minorTickCount: 2,
                editable: true,
                workDayStart: new Date(1980, 1, 1, 8, 0, 0),
                workDayEnd: new Date(1980, 1, 1, 17, 0, 0),
                workWeekStart: 1,
                workWeekEnd: 5,
                majorTick: 60,
                eventHeight: 25,
                eventMinWidth: 0,
                columnWidth: 100,
                groupHeaderTemplate: '#=text#',
                majorTimeHeaderTemplate: '#=kendo.toString(date, \'t\')#',
                slotTemplate: '&nbsp;',
                eventTemplate: EVENT_TEMPLATE,
                dateHeaderTemplate: DATA_HEADER_TEMPLATE,
                footer: { command: 'workDay' },
                currentTimeMarker: {
                    updateInterval: 10000,
                    useLocalTimezone: true
                },
                messages: {
                    defaultRowText: 'All events',
                    showFullDay: 'Show full day',
                    showWorkDay: 'Show business hours'
                }
            },
            events: [
                'remove',
                'add',
                'edit'
            ],
            _templates: function () {
                var options = this.options, settings = extend({}, kendo.Template, options.templateSettings);
                this.eventTemplate = this._eventTmpl(options.eventTemplate, EVENT_WRAPPER_STRING);
                this.majorTimeHeaderTemplate = kendo.template(options.majorTimeHeaderTemplate, settings);
                this.dateHeaderTemplate = kendo.template(options.dateHeaderTemplate, settings);
                this.slotTemplate = kendo.template(options.slotTemplate, settings);
                this.groupHeaderTemplate = kendo.template(options.groupHeaderTemplate, settings);
            },
            _render: function (dates) {
                var that = this;
                dates = dates || [];
                that._dates = dates;
                that._startDate = dates[0];
                that._endDate = dates[dates.length - 1 || 0];
                that._calculateSlotRanges();
                that.createLayout(that._layout(dates));
                that._content(dates);
                that._footer();
                that._setContentWidth();
                that.refreshLayout();
                that.datesHeader.on('click' + NS, '.k-nav-day', function (e) {
                    var th = $(e.currentTarget).closest('th');
                    var slot = that._slotByPosition(th.offset().left, that.content.offset().top);
                    that.trigger('navigate', {
                        view: 'timeline',
                        date: slot.startDate()
                    });
                });
                that._groupedView._hideHeaders();
            },
            _setContentWidth: function () {
                var content = this.content;
                var contentWidth = content.width();
                var contentTable = this.content.find('table');
                var columnCount = contentTable.find('tr:first').children().length;
                var minWidth = 100;
                var calculatedWidth = columnCount * this.options.columnWidth;
                if (contentWidth < calculatedWidth) {
                    minWidth = Math.ceil(calculatedWidth / contentWidth * 100);
                }
                contentTable.add(this.datesHeader.find('table')).css('width', minWidth + '%');
            },
            _calculateSlotRanges: function () {
                var dates = this._dates;
                var slotStartTime = this.startTime();
                var slotEndTime = this.endTime();
                slotEndTime = getMilliseconds(slotEndTime);
                slotStartTime = getMilliseconds(slotStartTime);
                if (slotEndTime === slotStartTime) {
                    slotEndTime += MS_PER_DAY - 1;
                } else if (slotEndTime < slotStartTime) {
                    slotEndTime += MS_PER_DAY;
                }
                var slotRanges = [];
                for (var i = 0; i < dates.length; i++) {
                    var rangeStart = getDate(dates[i]);
                    setTime(rangeStart, slotStartTime);
                    var rangeEnd = getDate(dates[i]);
                    setTime(rangeEnd, slotEndTime);
                    slotRanges.push({
                        start: kendo.date.toUtcTime(rangeStart),
                        end: kendo.date.toUtcTime(rangeEnd)
                    });
                }
                this._slotRanges = slotRanges;
            },
            _forTimeRange: function (min, max, action, verticalByDate, groupsCount) {
                min = toInvariantTime(min);
                max = toInvariantTime(max);
                var that = this, msMin = getMilliseconds(min), msMax = getMilliseconds(max), minorTickCount = that.options.minorTickCount, msMajorInterval = that.options.majorTick * MS_PER_MINUTE, msInterval = msMajorInterval / minorTickCount || 1, start = new Date(+min), idx = 0, length, html = '';
                length = MS_PER_DAY / msInterval;
                if (msMin != msMax) {
                    if (msMin > msMax) {
                        msMax += MS_PER_DAY;
                    }
                    length = (msMax - msMin) / msInterval;
                }
                length = verticalByDate ? 1 : Math.round(length);
                if (groupsCount) {
                    length = length * groupsCount;
                }
                for (; idx < length; idx++) {
                    var majorTickDivider = idx % (msMajorInterval / msInterval);
                    var isMajorTickColumn = majorTickDivider === 0;
                    var isMiddleColumn = majorTickDivider < minorTickCount - 1;
                    var isLastSlotColumn = majorTickDivider === minorTickCount - 1;
                    var minorTickColumns = minorTickCount;
                    if (length % minorTickCount !== 0) {
                        var isLastMajorSlot = length - (idx + 1) < minorTickCount;
                        if (isMajorTickColumn && isLastMajorSlot) {
                            minorTickColumns = length % minorTickCount;
                        }
                    }
                    html += action(start, isMajorTickColumn, isMiddleColumn, isLastSlotColumn, minorTickColumns, idx % groupsCount);
                    if (!verticalByDate) {
                        if (groupsCount) {
                            if (idx % groupsCount === groupsCount - 1) {
                                setTime(start, msInterval, false);
                            }
                        } else {
                            setTime(start, msInterval, false);
                        }
                    }
                }
                return html;
            },
            _layout: function (dates) {
                var timeColumns = [];
                var columns = [];
                var that = this;
                var rows = [{ text: that.options.messages.defaultRowText }];
                var groupedView = that._groupedView;
                var minorTickSlots = [];
                for (var minorTickIndex = 0; minorTickIndex < that.options.minorTickCount; minorTickIndex++) {
                    minorTickSlots.push({
                        text: '&#8203;',
                        className: 'k-last',
                        minorTicks: true
                    });
                }
                this._forTimeRange(that.startTime(), that.endTime(), function (date, majorTick, middleColumn, lastSlotColumn, minorSlotsCount) {
                    var template = that.majorTimeHeaderTemplate;
                    if (majorTick) {
                        var timeColumn = {
                            text: template({ date: date }),
                            className: lastSlotColumn ? 'k-slot-cell' : '',
                            columns: minorTickSlots.slice(0, minorSlotsCount)
                        };
                        groupedView._setColspan(timeColumn);
                        timeColumns.push(timeColumn);
                    }
                });
                for (var idx = 0; idx < dates.length; idx++) {
                    columns.push({
                        text: that.dateHeaderTemplate({ date: dates[idx] }),
                        className: 'k-slot-cell',
                        columns: timeColumns.slice(0)
                    });
                }
                var resources = this.groupedResources;
                if (resources.length) {
                    if (this._groupOrientation() === 'vertical') {
                        rows = groupedView._createRowsLayout(resources, null, this.groupHeaderTemplate, columns);
                        columns = groupedView._createVerticalColumnsLayout(resources, null, this.groupHeaderTemplate, columns);
                    } else {
                        columns = groupedView._createColumnsLayout(resources, columns, this.groupHeaderTemplate, columns);
                    }
                }
                return {
                    columns: columns,
                    rows: rows
                };
            },
            _footer: function () {
                var options = this.options;
                if (options.footer !== false) {
                    var html = '<div class="k-header k-scheduler-footer">';
                    var command = options.footer.command;
                    if (this._isMobile()) {
                        html += '<span class="k-state-default k-scheduler-today"><a href="#" class="k-link">';
                        html += options.messages.today + '</a></span>';
                    }
                    if (command && command === 'workDay') {
                        if (this._isMobile()) {
                            html += '<span class="k-state-default k-scheduler-fullday"><a href="#" class="k-link">';
                            html += (options.showWorkHours ? options.messages.showFullDay : options.messages.showWorkDay) + '</a></span>';
                        } else {
                            html += '<ul class="k-reset k-header">';
                            html += '<li class="k-state-default k-scheduler-fullday"><a href="#" class="k-link"><span class="k-icon k-i-clock"></span>';
                            html += (options.showWorkHours ? options.messages.showFullDay : options.messages.showWorkDay) + '</a></li>';
                            html += '</ul>';
                        }
                    } else {
                        html += '&nbsp;';
                    }
                    html += '</div>';
                    this.footer = $(html).appendTo(this.element);
                    var that = this;
                    this.footer.on('click' + NS, '.k-scheduler-fullday', function (e) {
                        e.preventDefault();
                        that.trigger('navigate', {
                            view: that.name || options.name,
                            date: that.startDate(),
                            isWorkDay: !options.showWorkHours
                        });
                    });
                    this.footer.on('click' + NS, '.k-scheduler-today', function (e) {
                        e.preventDefault();
                        var timezone = that.options.timezone;
                        var action = 'today';
                        var currentDate = new Date();
                        var date;
                        if (timezone) {
                            var timezoneOffset = kendo.timezone.offset(currentDate, timezone);
                            date = kendo.timezone.convert(currentDate, currentDate.getTimezoneOffset(), timezoneOffset);
                        } else {
                            date = currentDate;
                        }
                        that.trigger('navigate', {
                            view: that.name || options.name,
                            action: action,
                            date: date
                        });
                    });
                }
            },
            _columnCountForLevel: function (level) {
                var columnLevel = this.columnLevels[level];
                return columnLevel ? columnLevel.length : 0;
            },
            _rowCountForLevel: function (level) {
                var rowLevel = this.rowLevels[level];
                return rowLevel ? rowLevel.length : 0;
            },
            _isWorkDay: function (date) {
                var day = date.getDay();
                var workDays = this._workDays;
                for (var i = 0; i < workDays.length; i++) {
                    if (workDays[i] === day) {
                        return true;
                    }
                }
                return false;
            },
            _content: function (dates) {
                var that = this;
                var start = that.startTime();
                var end = this.endTime();
                var groupsCount = 1;
                var rowCount = 1;
                var columnCount = dates.length;
                var html = '';
                var resources = this.groupedResources;
                var slotTemplate = this.slotTemplate;
                var isVerticalGrouped = false;
                if (resources.length) {
                    isVerticalGrouped = that._groupOrientation() === 'vertical';
                    if (isVerticalGrouped) {
                        rowCount = that._groupedView._getRowCount(this.rowLevels.length - 1);
                        groupsCount = that._groupedView._getGroupsCount();
                    } else {
                        groupsCount = that._groupCount();
                    }
                }
                html += '<tbody>';
                html += that._groupedView._addContent(dates, columnCount, groupsCount, rowCount, start, end, slotTemplate, isVerticalGrouped);
                html += '</tbody>';
                this.content.find('table').append(html);
            },
            _groups: function () {
                var groupCount = this._groupCount();
                var dates = this._dates;
                var columnCount = dates.length;
                this.groups = [];
                for (var idx = 0; idx < groupCount; idx++) {
                    var view = this._addResourceView(idx);
                    var start = dates[0];
                    var end = dates[dates.length - 1 || 0];
                    var startTime = getMilliseconds(this.startTime());
                    var endTime = getMilliseconds(this.endTime());
                    if (startTime !== 0 && endTime <= startTime) {
                        start = getDate(start);
                        setTime(start, startTime);
                        end = getDate(end);
                        setTime(end, endTime);
                    }
                    view.addTimeSlotCollection(start, kendo.date.addDays(end, 1));
                }
                this._timeSlotGroups(groupCount, columnCount);
            },
            _isHorizontallyGrouped: function () {
                return this.groupedResources.length && this._groupOrientation() === 'horizontal';
            },
            _timeSlotGroups: function (groupCount, datesCount) {
                var interval = this._timeSlotInterval();
                var isVerticallyGrouped = this._isVerticallyGrouped();
                var tableRows = this.content.find('tr');
                tableRows.attr('role', 'row');
                this._groupedView._addTimeSlotsCollections(groupCount, datesCount, tableRows, interval, isVerticallyGrouped);
            },
            _addTimeSlotToCollection: function (group, cells, cellIndex, cellOffset, dateIndex, time, interval) {
                var cell = cells[cellIndex + cellOffset];
                var collection = group.getTimeSlotCollection(0);
                var currentDate = this._dates[dateIndex];
                var currentTime = Date.UTC(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate());
                var start = currentTime + time;
                var end = start + interval;
                cell.setAttribute('role', 'gridcell');
                cell.setAttribute('aria-selected', false);
                collection.addTimeSlot(cell, start, end, true);
            },
            startDate: function () {
                return this._startDate;
            },
            endDate: function () {
                return this._endDate;
            },
            visibleEndDate: function () {
                var startTime = getMilliseconds(this.startTime());
                var endTime = getMilliseconds(this.endTime());
                var endDate = this.endDate();
                if (startTime !== 0 && endTime <= startTime) {
                    endDate = kendo.date.addDays(endDate, 1);
                }
                return endDate;
            },
            startTime: function () {
                var options = this.options;
                return options.showWorkHours ? options.workDayStart : options.startTime;
            },
            endTime: function () {
                var options = this.options;
                return options.showWorkHours ? options.workDayEnd : options.endTime;
            },
            _timeSlotInterval: function () {
                var options = this.options;
                return options.majorTick / options.minorTickCount * MS_PER_MINUTE;
            },
            nextDate: function () {
                return kendo.date.nextDay(this.endDate());
            },
            previousDate: function () {
                return kendo.date.previousDay(this.startDate());
            },
            calculateDateRange: function () {
                this._render([this.options.date]);
            },
            render: function (events) {
                this._headerColumnCount = 0;
                this._groups();
                this.element.find('.k-event').remove();
                events = new kendo.data.Query(events).sort([
                    {
                        field: 'start',
                        dir: 'asc'
                    },
                    {
                        field: 'end',
                        dir: 'desc'
                    }
                ]).toArray();
                var eventsByResource = [];
                this._eventsByResource(events, this.groupedResources, eventsByResource);
                var eventGroups = [];
                var maxRowCount = 0;
                for (var groupIndex = 0; groupIndex < eventsByResource.length; groupIndex++) {
                    var eventGroup = {
                        groupIndex: groupIndex,
                        maxRowCount: 0,
                        events: {}
                    };
                    eventGroups.push(eventGroup);
                    this._renderEvents(eventsByResource[groupIndex], groupIndex, eventGroup);
                    if (maxRowCount < eventGroup.maxRowCount) {
                        maxRowCount = eventGroup.maxRowCount;
                    }
                }
                this._setRowsHeight(eventGroups, eventsByResource.length, maxRowCount);
                this._positionEvents(eventGroups, eventsByResource.length);
                this._currentTime(false);
                this.trigger('activate');
            },
            _positionEvents: function (eventGroups, groupsCount) {
                for (var groupIndex = 0; groupIndex < groupsCount; groupIndex++) {
                    var eventsForGroup = eventGroups[groupIndex].events;
                    for (var eventUid in eventsForGroup) {
                        var eventObject = eventsForGroup[eventUid];
                        if ($.isArray(eventObject)) {
                            for (var eventIndex = 0; eventIndex < eventObject.length; eventIndex++) {
                                this._positionEvent(eventObject[eventIndex]);
                            }
                        } else {
                            this._positionEvent(eventObject);
                        }
                    }
                }
            },
            _setRowsHeight: function (eventGroups, groupsCount, maxRowCount) {
                var eventHeight = this.options.eventHeight + 2;
                var eventBottomOffset = this._getBottomRowOffset();
                var groupedView = this._groupedView;
                var verticalGroupCount = groupedView._getVerticalGroupCount(groupsCount);
                groupsCount = this._isVerticallyGrouped() ? verticalGroupCount : 1;
                for (var groupIndex = 0; groupIndex < groupsCount; groupIndex++) {
                    var rowsCount = groupedView._getVerticalRowCount(eventGroups, groupIndex, maxRowCount);
                    rowsCount = rowsCount ? rowsCount : 1;
                    var rowHeight = (eventHeight + 2) * rowsCount + eventBottomOffset;
                    var timesRow = $(this.times.find('tr')[groupIndex]);
                    var row = $(this.content.find('tr')[groupIndex]);
                    timesRow.height(rowHeight);
                    row.height(rowHeight);
                }
                this._setContentWidth();
                this.refreshLayout();
                this._refreshSlots();
            },
            _getBottomRowOffset: function () {
                var eventBottomOffset = this.options.eventHeight * 0.5;
                var isMobile = this._isMobile();
                var minOffset;
                var maxOffset;
                if (isMobile) {
                    minOffset = 30;
                    maxOffset = 60;
                } else {
                    minOffset = 15;
                    maxOffset = 30;
                }
                if (eventBottomOffset > maxOffset) {
                    eventBottomOffset = maxOffset;
                } else if (eventBottomOffset < minOffset) {
                    eventBottomOffset = minOffset;
                }
                return eventBottomOffset;
            },
            _positionEvent: function (eventObject) {
                var eventHeight = this.options.eventHeight + 2;
                var rect = eventObject.slotRange.innerRect(eventObject.start, eventObject.end, false);
                var left = this._adjustLeftPosition(rect.left);
                var width = rect.right - rect.left - 2;
                if (width < 0) {
                    width = 0;
                }
                if (width < this.options.eventMinWidth) {
                    var slotsCollection = eventObject.slotRange.collection;
                    var lastSlot = slotsCollection._slots[slotsCollection._slots.length - 1];
                    var offsetRight = lastSlot.offsetLeft + lastSlot.offsetWidth;
                    width = this.options.eventMinWidth;
                    if (offsetRight < left + width) {
                        width = offsetRight - rect.left - 2;
                    }
                }
                eventObject.element.css({
                    top: eventObject.slotRange.start.offsetTop + eventObject.rowIndex * (eventHeight + 2) + 'px',
                    left: left,
                    width: width
                });
            },
            _refreshSlots: function () {
                for (var groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                    this.groups[groupIndex].refresh();
                }
            },
            _eventsByResource: function (events, resources, result) {
                var resource = resources[0];
                if (resource) {
                    var view = resource.dataSource.view();
                    for (var itemIdx = 0; itemIdx < view.length; itemIdx++) {
                        var value = this._resourceValue(resource, view[itemIdx]);
                        var eventsFilteredByResource = new kendo.data.Query(events).filter({
                            field: resource.field,
                            operator: SchedulerView.groupEqFilter(value)
                        }).toArray();
                        if (resources.length > 1) {
                            this._eventsByResource(eventsFilteredByResource, resources.slice(1), result);
                        } else {
                            result.push(eventsFilteredByResource);
                        }
                    }
                } else {
                    result.push(events);
                }
            },
            _isInDateSlot: function (event) {
                var startTime = event.start;
                var endTime = event.end;
                var rangeStart = getDate(this._startDate);
                var rangeEnd = kendo.date.addDays(getDate(this.visibleEndDate()), 1);
                if (startTime < rangeEnd && rangeStart <= endTime) {
                    return true;
                }
                return false;
            },
            _isInTimeSlot: function (event) {
                var startTime = event._startTime || kendo.date.toUtcTime(event.start);
                var endTime = event._endTime || kendo.date.toUtcTime(event.end);
                var slotRanges = this._slotRanges;
                if (startTime === endTime) {
                    endTime = endTime + 1;
                }
                for (var slotIndex = 0; slotIndex < slotRanges.length; slotIndex++) {
                    if (startTime < slotRanges[slotIndex].end && slotRanges[slotIndex].start < endTime) {
                        return true;
                    }
                }
                return false;
            },
            _adjustEvent: function (event) {
                var start = event.start;
                var end = event.end;
                var eventStartTime = event._time('start');
                var eventEndTime = event._time('end');
                var startTime = getMilliseconds(this.startTime());
                var endTime = getMilliseconds(this.endTime());
                var adjustedStartDate = null;
                var adjustedEndDate = null;
                var occurrence;
                var head = false;
                var tail = false;
                if (event.isAllDay) {
                    start = getDate(start);
                    eventStartTime = 0;
                    end = getDate(end);
                    eventEndTime = MS_PER_DAY;
                    adjustedEndDate = kendo.date.addDays(end, 1);
                }
                if (endTime === 0) {
                    endTime = MS_PER_DAY;
                }
                if (endTime <= startTime) {
                    if (eventStartTime < startTime && eventStartTime >= endTime) {
                        adjustedStartDate = getDate(start);
                        setTime(adjustedStartDate, startTime);
                        tail = true;
                    }
                    if (eventEndTime > endTime && eventEndTime <= startTime) {
                        adjustedEndDate = getDate(end);
                        setTime(adjustedEndDate, endTime);
                        head = true;
                    }
                } else {
                    if (startTime > eventStartTime) {
                        adjustedStartDate = getDate(start);
                        setTime(adjustedStartDate, startTime);
                        tail = true;
                    } else if (endTime <= eventStartTime) {
                        adjustedStartDate = getDate(start);
                        adjustedStartDate = kendo.date.addDays(adjustedStartDate, 1);
                        setTime(adjustedStartDate, startTime);
                        tail = true;
                    }
                    if (endTime < eventEndTime) {
                        adjustedEndDate = getDate(end);
                        setTime(adjustedEndDate, endTime);
                        head = true;
                    } else if (startTime > eventEndTime) {
                        adjustedEndDate = getDate(end);
                        adjustedEndDate = kendo.date.addDays(adjustedEndDate, -1);
                        setTime(adjustedEndDate, endTime);
                        head = true;
                    }
                }
                occurrence = event.clone({
                    start: adjustedStartDate ? adjustedStartDate : start,
                    end: adjustedEndDate ? adjustedEndDate : end,
                    _startTime: adjustedStartDate ? kendo.date.toUtcTime(adjustedStartDate) : event._startTime,
                    _endTime: adjustedEndDate ? kendo.date.toUtcTime(adjustedEndDate) : event._endTime,
                    isAllDay: false
                });
                return {
                    occurrence: occurrence,
                    head: head,
                    tail: tail
                };
            },
            _renderEvents: function (events, groupIndex, eventGroup) {
                var event;
                var idx;
                var length;
                for (idx = 0, length = events.length; idx < length; idx++) {
                    event = events[idx];
                    if (this._isInDateSlot(event)) {
                        var isMultiDayEvent = event.isAllDay || event.duration() >= MS_PER_DAY;
                        var container = this.content;
                        if (isMultiDayEvent || this._isInTimeSlot(event)) {
                            var adjustedEvent = this._adjustEvent(event);
                            var group = this.groups[groupIndex];
                            if (!group._continuousEvents) {
                                group._continuousEvents = [];
                            }
                            if (this._isInTimeSlot(adjustedEvent.occurrence)) {
                                var ranges = group.slotRanges(adjustedEvent.occurrence, false);
                                var range = ranges[0];
                                var startIndex = range.start.index;
                                var endIndex = range.end.index;
                                this._groupedView._renderEvent(eventGroup, event, adjustedEvent, group, range, container, startIndex, endIndex);
                            }
                        }
                    }
                }
            },
            addContinuousEvent: function (group, range, element, isAllDay) {
                var events = group._continuousEvents;
                events.push({
                    element: element,
                    isAllDay: isAllDay,
                    uid: element.attr(kendo.attr('uid')),
                    start: range.start,
                    end: range.end
                });
            },
            _createEventElement: function (occurrence, event, head, tail) {
                var template = this.eventTemplate;
                var editable = this.options.editable;
                var isMobile = this._isMobile();
                var showDelete = editable && editable.destroy !== false && !isMobile;
                var resizable = editable && editable.resize !== false;
                var eventStartTime = event._time('start');
                var eventEndTime = event._time('end');
                var eventStartDate = event.start;
                var eventEndDate = event.end;
                var resources = this.eventResources(event);
                if (event._startTime && eventStartTime !== kendo.date.getMilliseconds(event.start)) {
                    eventStartDate = new Date(eventStartTime);
                    eventStartDate = kendo.timezone.apply(eventStartDate, 'Etc/UTC');
                }
                if (event._endTime && eventEndTime !== kendo.date.getMilliseconds(event.end)) {
                    eventEndDate = new Date(eventEndTime);
                    eventEndDate = kendo.timezone.apply(eventEndDate, 'Etc/UTC');
                }
                var data = extend({}, {
                    ns: kendo.ns,
                    resizable: resizable,
                    showDelete: showDelete,
                    head: head,
                    tail: tail,
                    singleDay: this._dates.length == 1,
                    resources: resources,
                    inverseColor: false,
                    messages: this.options.messages
                }, event, {
                    start: eventStartDate,
                    end: eventEndDate
                });
                var element = $(template(data));
                this.angular('compile', function () {
                    return {
                        elements: element,
                        data: [{ dataItem: data }]
                    };
                });
                return element;
            },
            _arrangeRows: function (eventObject, slotRange, eventGroup) {
                var startIndex = slotRange.start.index;
                var endIndex = slotRange.end.index;
                var rect = eventObject.slotRange.innerRect(eventObject.start, eventObject.end, false);
                var rectRight = rect.right + this.options.eventMinWidth;
                var events = collidingEvents(slotRange.events(), rect.left, rectRight);
                slotRange.addEvent({
                    slotIndex: startIndex,
                    start: startIndex,
                    end: endIndex,
                    rectLeft: rect.left,
                    rectRight: rectRight,
                    element: eventObject.element,
                    uid: eventObject.uid
                });
                events.push({
                    start: startIndex,
                    end: endIndex,
                    uid: eventObject.uid
                });
                var rows = SchedulerView.createRows(events);
                if (eventGroup.maxRowCount < rows.length) {
                    eventGroup.maxRowCount = rows.length;
                }
                for (var idx = 0, length = rows.length; idx < length; idx++) {
                    var rowEvents = rows[idx].events;
                    for (var j = 0, eventLength = rowEvents.length; j < eventLength; j++) {
                        eventGroup.events[rowEvents[j].uid].rowIndex = idx;
                    }
                }
            },
            _groupCount: function () {
                var resources = this.groupedResources;
                var groupedView = this._groupedView;
                if (resources.length) {
                    if (this._groupOrientation() === 'vertical') {
                        return groupedView._verticalCountForLevel(resources.length - 1);
                    } else {
                        return groupedView._horizontalCountForLevel(resources.length - 1, this.columnLevels.length - 1);
                    }
                }
                return 1;
            },
            _updateEventForSelection: function (event) {
                var adjustedEvent = this._adjustEvent(event.clone());
                return adjustedEvent.occurrence;
            },
            _eventOptionsForMove: function (event) {
                if (event.isAllDay) {
                    return { isAllDay: false };
                }
                return {};
            },
            _updateEventForResize: function (event) {
                if (event.isAllDay) {
                    event.set('isAllDay', false);
                }
            },
            _updateMoveHint: function (event, groupIndex, distance) {
                var group = this.groups[groupIndex];
                var clonedEvent = event.clone({
                    start: event.start,
                    end: event.end
                });
                var eventDuraton = clonedEvent.duration();
                clonedEvent.start = new Date(clonedEvent.start.getTime() + distance);
                clonedEvent.end = new Date(+clonedEvent.start + eventDuraton);
                this._removeMoveHint(event.uid);
                if (this._isInDateSlot(clonedEvent)) {
                    if (clonedEvent.isAllDay || clonedEvent.duration() >= MS_PER_DAY || this._isInTimeSlot(clonedEvent)) {
                        var adjustedEvent = this._adjustEvent(clonedEvent);
                        var ranges = group.slotRanges(adjustedEvent.occurrence, false);
                        for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                            this._groupedView._createMoveHint(ranges[rangeIndex], adjustedEvent);
                        }
                    }
                }
            },
            _appendMoveHint: function (hint) {
                hint.appendTo(this.content);
                this._moveHint = this._moveHint.add(hint);
            },
            _updateResizeHint: function (event, groupIndex, startTime, endTime) {
                var group = this.groups[groupIndex];
                var ranges = group.ranges(startTime, endTime, false, false);
                this._removeResizeHint();
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    var range = ranges[rangeIndex];
                    var start = range.startSlot();
                    var startRect = range.innerRect(startTime, endTime, false);
                    startRect.top = start.offsetTop;
                    var width = startRect.right - startRect.left;
                    if (width < 0) {
                        for (var i = 0; i < range.events().length; i++) {
                            if (range.events()[i].uid === event.uid) {
                                width = range.events()[i].rectRight - startRect.left;
                                break;
                            }
                        }
                    }
                    var height = range.endSlot().offsetTop + start.offsetHeight - startRect.top;
                    var left = this._adjustLeftPosition(startRect.left);
                    var hint = SchedulerView.fn._createResizeHint.call(this, left, startRect.top, width, height);
                    this._resizeHint = this._resizeHint.add(hint);
                }
                var format = 't';
                var container = this.content;
                this._resizeHint.appendTo(container);
                this._resizeHint.find('.k-label-top,.k-label-bottom').text('');
                this._resizeHint.first().addClass('k-first').find('.k-label-top').text(kendo.toString(kendo.timezone.toLocalDate(startTime), format));
                this._resizeHint.last().addClass('k-last').find('.k-label-bottom').text(kendo.toString(kendo.timezone.toLocalDate(endTime), format));
            },
            selectionByElement: function (cell) {
                var offset = cell.offset();
                return this._slotByPosition(offset.left, offset.top);
            },
            _updateDirection: function (selection, ranges, multiple, reverse, vertical) {
                var startSlot = ranges[0].start;
                var endSlot = ranges[ranges.length - 1].end;
                if (multiple && !vertical) {
                    if (startSlot.index === endSlot.index && startSlot.collectionIndex === endSlot.collectionIndex) {
                        selection.backward = reverse;
                    }
                }
            },
            _changeGroup: function (selection, previous) {
                var method = previous ? 'prevGroupSlot' : 'nextGroupSlot';
                var slot = this[method](selection.start, selection.groupIndex, false);
                if (slot) {
                    selection.groupIndex += previous ? -1 : 1;
                }
                this._groupedView._changeGroup(selection, previous, slot);
                return slot;
            },
            prevGroupSlot: function (date, groupIndex, isDay) {
                var group = this.groups[groupIndex];
                var slot = group.ranges(date, date, isDay, false)[0].start;
                if (groupIndex <= 0) {
                    return;
                }
                return this._groupedView._prevGroupSlot(slot, group, isDay);
            },
            nextGroupSlot: function (date, groupIndex, isDay) {
                var group = this.groups[groupIndex];
                var slot = group.ranges(date, date, isDay, false)[0].start;
                if (groupIndex >= this.groups.length - 1) {
                    return;
                }
                return this._groupedView._nextGroupSlot(slot, group, isDay);
            },
            _verticalSlots: function (selection, ranges, multiple, reverse) {
                var groupedView = this._groupedView;
                var method = groupedView._verticalMethod(reverse, multiple);
                var startSlot = ranges[0].start;
                var endSlot = ranges[ranges.length - 1].end;
                var group = this.groups[selection.groupIndex];
                var slot = groupedView._normalizeVerticalSelection(selection, ranges, reverse, multiple);
                if (slot) {
                    startSlot = endSlot = slot;
                }
                startSlot = group[method](startSlot);
                endSlot = group[method](endSlot);
                if (!multiple && this._isVerticallyGrouped() && (!startSlot || !endSlot)) {
                    startSlot = endSlot = groupedView._verticalSlots(selection, reverse, slot);
                }
                return {
                    startSlot: startSlot,
                    endSlot: endSlot
                };
            },
            _horizontalSlots: function (selection, ranges, multiple, reverse) {
                var method = reverse ? 'upSlot' : 'downSlot';
                var startSlot = ranges[0].start;
                var endSlot = ranges[ranges.length - 1].end;
                var group = this.groups[selection.groupIndex];
                var result = {};
                if (!multiple) {
                    result = this._groupedView._horizontalSlots(selection, group, method, startSlot, endSlot, multiple, reverse);
                } else {
                    result.startSlot = group[method](startSlot);
                    result.endSlot = group[method](endSlot);
                    if (!multiple && this._isHorizontallyGrouped() && (!startSlot || !endSlot)) {
                        result.startSlot = result.endSlot = this._changeGroup(selection, reverse);
                    }
                }
                return result;
            },
            _changeViewPeriod: function (selection, reverse) {
                var date = reverse ? this.previousDate() : this.nextDate();
                var start = selection.start;
                var end = selection.end;
                var newStart, newEnd;
                newStart = new Date(date);
                newEnd = new Date(date);
                if (this._isInRange(newStart, newEnd)) {
                    return false;
                }
                selection.start = newStart;
                selection.end = newEnd;
                if (this._isHorizontallyGrouped()) {
                    selection.groupIndex = reverse ? this.groups.length - 1 : 0;
                }
                var duration = end - start;
                if (reverse) {
                    end = getMilliseconds(this.endTime());
                    end = end === 0 ? MS_PER_DAY : end;
                    setTime(selection.start, end - duration);
                    setTime(selection.end, end);
                } else {
                    start = getMilliseconds(this.startTime());
                    setTime(selection.start, start);
                    setTime(selection.end, start + duration);
                }
                selection.events = [];
                return true;
            },
            move: function (selection, key, shift) {
                var handled = false;
                var group = this.groups[selection.groupIndex];
                var keys = kendo.keys;
                var groupedView = this._groupedView;
                var ranges = group.ranges(selection.start, selection.end, false, false);
                var startSlot, endSlot, reverse, slots;
                if (key === keys.DOWN || key === keys.UP) {
                    handled = true;
                    reverse = key === keys.UP;
                    groupedView._updateDirection(selection, ranges, shift, reverse);
                    slots = this._verticalSlots(selection, ranges, shift, reverse);
                    if (groupedView._changeVerticalViewPeriod(slots, shift, selection, reverse)) {
                        return handled;
                    }
                } else if (key === keys.LEFT || key === keys.RIGHT) {
                    handled = true;
                    reverse = key === keys.LEFT;
                    this._updateDirection(selection, ranges, shift, reverse, false);
                    slots = this._horizontalSlots(selection, ranges, shift, reverse);
                    if (groupedView._changeHorizontalViewPeriod(slots, shift, selection, reverse)) {
                        return handled;
                    }
                }
                if (handled) {
                    startSlot = slots.startSlot;
                    endSlot = slots.endSlot;
                    if (shift) {
                        var backward = selection.backward;
                        if (backward && startSlot) {
                            selection.start = startSlot.startDate();
                        } else if (!backward && endSlot) {
                            selection.end = endSlot.endDate();
                        }
                    } else if (startSlot && endSlot) {
                        selection.start = startSlot.startDate();
                        selection.end = endSlot.endDate();
                    }
                    selection.events = [];
                }
                return handled;
            },
            destroy: function () {
                var that = this;
                if (that.element) {
                    that.element.off(NS);
                }
                if (that.footer) {
                    that.footer.remove();
                }
                if (that._currentTimeUpdateTimer) {
                    clearInterval(that._currentTimeUpdateTimer);
                }
                SchedulerView.fn.destroy.call(this);
                if (this._isMobile() && that.options.editable) {
                    if (that.options.editable.create !== false) {
                        that._addUserEvents.destroy();
                    }
                    if (that.options.editable.update !== false) {
                        that._editUserEvents.destroy();
                    }
                }
            }
        });
        extend(true, ui, {
            TimelineView: TimelineView,
            TimelineWeekView: TimelineView.extend({
                options: {
                    name: 'TimelineWeekView',
                    title: 'Timeline Week',
                    selectedDateFormat: '{0:D} - {1:D}',
                    selectedShortDateFormat: '{0:d} - {1:d}',
                    selectedMobileDateFormat: '{0:MMM dd} - {1:dd}',
                    majorTick: 120
                },
                name: 'timelineWeek',
                calculateDateRange: function () {
                    var selectedDate = this.options.date, start = kendo.date.dayOfWeek(selectedDate, this.calendarInfo().firstDay, -1), idx, length, dates = [];
                    for (idx = 0, length = 7; idx < length; idx++) {
                        dates.push(start);
                        start = kendo.date.nextDay(start);
                    }
                    this._render(dates);
                }
            }),
            TimelineWorkWeekView: TimelineView.extend({
                options: {
                    name: 'TimelineWorkWeekView',
                    title: 'Timeline Work Week',
                    selectedDateFormat: '{0:D} - {1:D}',
                    selectedShortDateFormat: '{0:d} - {1:d}',
                    selectedMobileDateFormat: '{0:MMM dd} - {1:dd}',
                    majorTick: 120
                },
                name: 'timelineWorkWeek',
                nextDate: function () {
                    var weekStart = kendo.date.dayOfWeek(kendo.date.nextDay(this.endDate()), this.calendarInfo().firstDay, 1);
                    return kendo.date.addDays(weekStart, this._workDays[0]);
                },
                previousDate: function () {
                    var weekStart = kendo.date.dayOfWeek(this.startDate(), this.calendarInfo().firstDay, -1);
                    var workDays = this._workDays;
                    return kendo.date.addDays(weekStart, workDays[workDays.length - 1] - 7);
                },
                calculateDateRange: function () {
                    var selectedDate = this.options.date, start = kendo.date.dayOfWeek(selectedDate, this.options.workWeekStart, -1), end = kendo.date.dayOfWeek(start, this.options.workWeekEnd, 1), dates = [];
                    while (start <= end) {
                        dates.push(start);
                        start = kendo.date.nextDay(start);
                    }
                    this._render(dates);
                }
            }),
            TimelineMonthView: TimelineView.extend({
                options: {
                    name: 'TimelineMonthView',
                    title: 'Timeline Month',
                    selectedDateFormat: '{0:D} - {1:D}',
                    selectedShortDateFormat: '{0:d} - {1:d}',
                    workDayStart: new Date(1980, 1, 1, 0, 0, 0),
                    workDayEnd: new Date(1980, 1, 1, 23, 59, 59),
                    footer: false,
                    majorTick: 1440,
                    minorTickCount: 1
                },
                name: 'timelineMonth',
                calculateDateRange: function () {
                    var selectedDate = this.options.date, start = kendo.date.firstDayOfMonth(selectedDate), end = kendo.date.lastDayOfMonth(selectedDate), idx, length, dates = [];
                    for (idx = 0, length = end.getDate(); idx < length; idx++) {
                        dates.push(start);
                        start = kendo.date.nextDay(start);
                    }
                    this._render(dates);
                }
            })
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler', [
        'kendo.dropdownlist',
        'kendo.editable',
        'kendo.multiselect',
        'kendo.window',
        'kendo.datetimepicker',
        'kendo.scheduler.recurrence',
        'kendo.scheduler.view',
        'kendo.scheduler.dayview',
        'kendo.scheduler.agendaview',
        'kendo.scheduler.monthview',
        'kendo.scheduler.timelineview',
        'kendo.dialog',
        'kendo.pane',
        'kendo.pdf',
        'kendo.switch'
    ], f);
}(function () {
    var __meta__ = {
        id: 'scheduler',
        name: 'Scheduler',
        category: 'web',
        description: 'The Scheduler is an event calendar.',
        depends: [
            'dropdownlist',
            'editable',
            'multiselect',
            'window',
            'datepicker',
            'datetimepicker',
            'scheduler.recurrence',
            'scheduler.view'
        ],
        features: [
            {
                id: 'scheduler-dayview',
                name: 'Scheduler Day View',
                description: 'Scheduler Day View',
                depends: ['scheduler.dayview']
            },
            {
                id: 'scheduler-agendaview',
                name: 'Scheduler Agenda View',
                description: 'Scheduler Agenda View',
                depends: ['scheduler.agendaview']
            },
            {
                id: 'scheduler-monthview',
                name: 'Scheduler Month View',
                description: 'Scheduler Month View',
                depends: ['scheduler.monthview']
            },
            {
                id: 'scheduler-timelineview',
                name: 'Scheduler Timeline View',
                description: 'Scheduler Timeline View',
                depends: ['scheduler.timelineview']
            },
            {
                id: 'scheduler-mobile',
                name: 'Scheduler adaptive rendering',
                description: 'Support for adaptive rendering',
                depends: [
                    'dialog',
                    'pane',
                    'switch'
                ]
            },
            {
                id: 'scheduler-pdf-export',
                name: 'PDF export',
                description: 'Export the scheduler events as PDF',
                depends: [
                    'pdf',
                    'drawing'
                ]
            },
            {
                id: 'scheduler-timezones',
                name: 'Timezones',
                description: 'Allow selecting timezones different than Etc/UTC',
                depends: ['timezones']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, date = kendo.date, MS_PER_DAY = date.MS_PER_DAY, getDate = date.getDate, getMilliseconds = kendo.date.getMilliseconds, recurrence = kendo.recurrence, keys = $.extend({ F10: 121 }, kendo.keys), ui = kendo.ui, Widget = ui.Widget, DataBoundWidget = ui.DataBoundWidget, STRING = 'string', Popup = ui.Popup, Calendar = ui.Calendar, DataSource = kendo.data.DataSource, isPlainObject = $.isPlainObject, extend = $.extend, proxy = $.proxy, toString = Object.prototype.toString, isArray = $.isArray, NS = '.kendoScheduler', CLICK = 'click', MOUSEDOWN = 'mousedown', TOUCHSTART = kendo.support.pointers ? 'pointerdown' : 'touchstart', TOUCHMOVE = kendo.support.pointers ? 'pointermove' : 'touchmove', TOUCHEND = kendo.support.pointers ? 'pointerup' : 'touchend', MOUSEMOVE = kendo.support.mousemove, CHANGE = 'change', PROGRESS = 'progress', ERROR = 'error', CANCEL = 'cancel', REMOVE = 'remove', RESET = 'resetSeries', SAVE = 'save', ADD = 'add', EDIT = 'edit', FOCUSEDSTATE = 'k-state-focused', EXPANDEDSTATE = 'k-state-expanded', VIEWSSELECTOR = '.k-scheduler-views', INVERSECOLORCLASS = 'k-event-inverse', valueStartEndBoundRegex = /(?:value:start|value:end)(?:,|$)/, TODAY = getDate(new Date()), EXCEPTION_SEPARATOR = ',', OLD_EXCEPTION_SEPARATOR_REGEXP = /\;/g, RECURRENCE_EXCEPTION = 'recurrenceException', DELETECONFIRM = 'Are you sure you want to delete this event?', DELETERECURRING = 'Do you want to delete only this event occurrence or the whole series?', EDITRECURRING = 'Do you want to edit only this event occurrence or the whole series?', DELETERECURRINGCONFIRM = 'Are you sure you want to delete this event occurrence?', RESETSERIESCONFIRM = 'Are you sure you want to reset the whole series?', DELETESERIESCONFIRM = 'Are you sure you want to delete the whole series?', COMMANDBUTTONTMPL = '<a class="k-button #=className#" #=attr# href="\\#">#=text#</a>', VIEWBUTTONTEMPLATE = kendo.template('<li class="k-current-view" data-#=ns#name="#=view#"><a role="button" href="\\#" class="k-link">${views[view].title}</a></li>'), TOOLBARTEMPLATE = kendo.template('<div class="k-floatwrap k-header k-scheduler-toolbar">' + '# if (pdf) { #' + '<ul class="k-reset k-scheduler-tools">' + '<li><a role="button" href="\\#" class="k-button k-pdf"><span class="k-icon k-i-file-pdf"></span>${messages.pdf}</a></li>' + '</ul>' + '# } #' + '<ul class="k-reset k-scheduler-navigation">' + '<li class="k-state-default k-header k-nav-today"><a role="button" href="\\#" class="k-link" title="${messages.today}">${messages.today}</a></li>' + '<li class="k-state-default k-header k-nav-prev"><a role="button" href="\\#" class="k-link" title="${messages.previous}" aria-label="${messages.previous}"><span class="k-icon k-i-arrow-60-left" style="pointer-events: none"></span></a></li>' + '<li class="k-state-default k-header k-nav-next"><a role="button" href="\\#" class="k-link" title="${messages.next}" aria-label="${messages.next}"><span class="k-icon k-i-arrow-60-right" style="pointer-events: none"></span></a></li>' + '<li class="k-state-default k-nav-current">' + '<a role="button" href="\\#" class="k-link">' + '<span class="k-icon k-i-calendar"></span>' + '<span class="k-sm-date-format" data-#=ns#bind="text: formattedShortDate"></span>' + '<span class="k-lg-date-format" data-#=ns#bind="text: formattedDate"></span>' + '</a>' + '</li>' + '</ul>' + '#if(viewsCount === 1){#' + '<a role="button" data-#=ns#name="#=view#" href="\\#" class="k-link k-scheduler-refresh">' + '<span class="k-icon k-i-reload"></span>' + '</a>' + '#}else{#' + '<ul class="k-reset k-header k-scheduler-views">' + '#for(var view in views){#' + '<li class="k-state-default k-view-#= view.toLowerCase() #" data-#=ns#name="#=view#"><a role="button" href="\\#" class="k-link">${views[view].title}</a></li>' + '#}#' + '</ul>' + '#}#' + '</div>'), MOBILETOOLBARTEMPLATE = kendo.template('<div class="k-header k-scheduler-toolbar">' + '<ul class="k-reset k-scheduler-tools">' + '# if (pdf) { #' + '<li><a role="button" href="\\#" class="k-button k-pdf"><span class="k-icon k-i-file-pdf"></span></a></li>' + '# } #' + '<li><a role="button" href="\\#" class="k-button k-nav-calendar"><span class="k-icon k-i-calendar"></span></a></li>' + '# if (editable) { #' + '<li><a role="button" href="\\#" class="k-button k-create-event"><span class="k-icon k-i-plus"></span></a></li>' + '# } #' + '</ul>' + '#if(viewsCount === 1){#' + '<a role="button" data-#=ns#name="#=view#" href="\\#" class="k-link k-scheduler-refresh">' + '<span class="k-icon k-i-reload"></span>' + '</a>' + '#}else{#' + '<select class="k-scheduler-mobile-views">' + '#for(var view in views){#' + '<option class="k-state-default k-view-#= view.toLowerCase() #" value="#=view#">${views[view].title}</option>' + '#}#' + '</select>' + '#}#' + '</div>' + '<div class="k-header k-scheduler-toolbar">' + '<ul class="k-reset k-header k-scheduler-navigation">' + '<li class="k-state-default k-nav-prev"><a role="button" href="\\#" class="k-link"><span class="k-icon k-i-arrow-chevron-left"></span></a></li>' + '<li class="k-state-default k-nav-current">' + '<span class="k-m-date-format" data-#=ns#bind="text: formattedMobileDate"></span>' + '<span class="k-y-date-format" data-#=ns#bind="text: formattedYear"></span>' + '</li>' + '<li class="k-state-default k-nav-next"><a role="button" href="\\#" class="k-link"><span class="k-icon k-i-arrow-chevron-right"></span></a></li>' + '</ul>' + '</div>'), MOBILEDATERANGEEDITOR = function (container, options) {
                var attr = {
                    name: options.field,
                    title: options.title
                };
                var isAllDay = options.model.isAllDay;
                var dateTimeValidate = kendo.attr('validate') + '=\'' + !isAllDay + '\'';
                var dateValidate = kendo.attr('validate') + '=\'' + isAllDay + '\'';
                appendTimezoneAttr(attr, options);
                appendValidDateValidator(attr, options);
                appendDateCompareValidator(attr, options);
                $('<input type="datetime-local" required ' + kendo.attr('type') + '="datetime-local" ' + kendo.attr('bind') + '="value:' + options.field + ', invisible:isAllDay" ' + dateTimeValidate + '/>').attr(attr).appendTo(container);
                $('<input type="date" required ' + kendo.attr('type') + '="date" ' + kendo.attr('bind') + '="value:' + options.field + ',visible:isAllDay" ' + dateValidate + '/>').attr(attr).appendTo(container);
                $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
            }, DATERANGEEDITOR = function (container, options) {
                var attr = {
                        name: options.field,
                        title: options.title
                    }, isAllDay = options.model.isAllDay, dateTimeValidate = kendo.attr('validate') + '=\'' + !isAllDay + '\' ', dateValidate = kendo.attr('validate') + '=\'' + isAllDay + '\' ';
                appendTimezoneAttr(attr, options);
                appendValidDateValidator(attr, options);
                appendDateCompareValidator(attr, options);
                $('<input type="text" required ' + kendo.attr('type') + '="date"' + ' ' + kendo.attr('role') + '="datetimepicker" ' + kendo.attr('bind') + '="value:' + options.field + ',invisible:isAllDay" ' + dateTimeValidate + '/>').attr(attr).appendTo(container);
                $('<input type="text" required ' + kendo.attr('type') + '="date"' + ' ' + kendo.attr('role') + '="datepicker" ' + kendo.attr('bind') + '="value:' + options.field + ',visible:isAllDay" ' + dateValidate + '/>').attr(attr).appendTo(container);
                $('<span ' + kendo.attr('bind') + '="text: ' + options.field + 'Timezone"></span>').appendTo(container);
                if (options.field === 'end') {
                    $('<span ' + kendo.attr('bind') + '="text: startTimezone, invisible: endTimezone"></span>').appendTo(container);
                }
                $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
            }, RECURRENCEEDITOR = function (container, options) {
                $('<div ' + kendo.attr('bind') + '="value:' + options.field + '" />').attr({ name: options.field }).appendTo(container).kendoRecurrenceEditor({
                    start: options.model.start,
                    timezone: options.timezone,
                    messages: options.messages
                });
            }, MOBILERECURRENCEEDITOR = function (container, options) {
                $('<div ' + kendo.attr('bind') + '="value:' + options.field + '" />').attr({ name: options.field }).appendTo(container).kendoMobileRecurrenceEditor({
                    start: options.model.start,
                    timezone: options.timezone,
                    messages: options.messages,
                    pane: options.pane,
                    value: options.model[options.field]
                });
            }, MOBILEISALLDAYEDITOR = function (container, options) {
                $('<input type="checkbox" data-role="switch"' + kendo.attr('bind') + '="value:' + options.field + '" />').appendTo(container);
            }, MOBILETIMEZONEPOPUP = function (container, options) {
                var text = timezoneButtonText(options.model, options.messages.noTimezone);
                $('<span class="k-timezone-label"></span>').text(text).appendTo(container);
                $('<span class="k-icon k-i-arrow-chevron-right"></span>').appendTo(container);
                container.closest('li.k-item label').click(options.click);
            }, TIMEZONEPOPUP = function (container, options) {
                $('<a href="#" class="k-button" data-bind="invisible:isAllDay">' + options.messages.timezoneEditorButton + '</a>').click(options.click).appendTo(container);
            }, MOBILETIMEZONEEDITOR = function (container, options) {
                $('<div class="k-mobiletimezoneeditor" ' + kendo.attr('bind') + '="value:' + options.field + '" />').attr({ name: options.field }).appendTo(container).kendoMobileTimezoneEditor({ optionLabel: options.noTimezone });
            }, TIMEZONEEDITOR = function (container, options) {
                var visible = options.visible || options.visible === undefined;
                $('<div ' + kendo.attr('bind') + '="value:' + options.field + '" />').attr({ name: options.field }).toggle(visible).appendTo(container).kendoTimezoneEditor({
                    optionLabel: options.noTimezone,
                    title: options.title
                });
            };
        function timezoneButtonText(model, message) {
            message = message || '';
            if (model.startTimezone) {
                message = model.startTimezone;
                if (model.endTimezone) {
                    message += ' | ' + model.endTimezone;
                }
            }
            return message;
        }
        function appendTimezoneAttr(attrs, options) {
            var timezone = options.timezone;
            if (timezone) {
                attrs[kendo.attr('timezone')] = timezone;
            }
        }
        function appendValidDateValidator(attrs, options) {
            var validationRules = options.model.fields[options.field].validation;
            if (validationRules) {
                var validDateRule = validationRules.validDateValidator;
                if (validDateRule && isPlainObject(validDateRule) && validDateRule.message) {
                    attrs[kendo.attr('validDate-msg')] = validDateRule.message;
                }
            }
        }
        function appendDateCompareValidator(attrs, options) {
            var validationRules = options.model.fields[options.field].validation;
            if (validationRules) {
                var dateCompareRule = validationRules.dateCompare;
                if (dateCompareRule && isPlainObject(dateCompareRule) && dateCompareRule.message) {
                    attrs[kendo.attr('dateCompare-msg')] = dateCompareRule.message;
                }
            }
        }
        function wrapDataAccess(originalFunction, timezone) {
            return function (data) {
                data = originalFunction(data);
                convertData(data, 'apply', timezone);
                return data || [];
            };
        }
        function wrapDataSerialization(originalFunction, timezone) {
            return function (data) {
                if (data) {
                    if (toString.call(data) !== '[object Array]' && !(data instanceof kendo.data.ObservableArray)) {
                        data = [data];
                    }
                }
                convertData(data, 'remove', timezone, true);
                data = originalFunction(data);
                return data || [];
            };
        }
        function convertData(data, method, timezone, removeUid) {
            var event, idx, length;
            data = data || [];
            for (idx = 0, length = data.length; idx < length; idx++) {
                event = data[idx];
                if (removeUid) {
                    if (event.startTimezone || event.endTimezone) {
                        if (timezone) {
                            event.start = kendo.timezone.convert(event.start, event.startTimezone || event.endTimezone, timezone);
                            event.end = kendo.timezone.convert(event.end, event.endTimezone || event.startTimezone, timezone);
                            event.start = kendo.timezone[method](event.start, timezone);
                            event.end = kendo.timezone[method](event.end, timezone);
                        } else {
                            event.start = kendo.timezone[method](event.start, event.startTimezone || event.endTimezone);
                            event.end = kendo.timezone[method](event.end, event.endTimezone || event.startTimezone);
                        }
                    } else if (timezone) {
                        event.start = kendo.timezone[method](event.start, timezone);
                        event.end = kendo.timezone[method](event.end, timezone);
                    }
                } else {
                    if (event.startTimezone || event.endTimezone) {
                        event.start = kendo.timezone[method](event.start, event.startTimezone || event.endTimezone);
                        event.end = kendo.timezone[method](event.end, event.endTimezone || event.startTimezone);
                        if (timezone) {
                            event.start = kendo.timezone.convert(event.start, event.startTimezone || event.endTimezone, timezone);
                            event.end = kendo.timezone.convert(event.end, event.endTimezone || event.startTimezone, timezone);
                        }
                    } else if (timezone) {
                        event.start = kendo.timezone[method](event.start, timezone);
                        event.end = kendo.timezone[method](event.end, timezone);
                    }
                }
                if (removeUid) {
                    delete event.uid;
                }
            }
            return data;
        }
        function getOccurrenceByUid(data, uid) {
            var length = data.length, idx = 0, event;
            for (; idx < length; idx++) {
                event = data[idx];
                if (event.uid === uid) {
                    return event;
                }
            }
        }
        var SchedulerDataReader = kendo.Class.extend({
            init: function (schema, reader) {
                var timezone = schema.timezone;
                this.reader = reader;
                if (reader.model) {
                    this.model = reader.model;
                }
                this.timezone = timezone;
                this.data = wrapDataAccess($.proxy(this.data, this), timezone);
                this.serialize = wrapDataSerialization($.proxy(this.serialize, this), timezone);
            },
            errors: function (data) {
                return this.reader.errors(data);
            },
            parse: function (data) {
                return this.reader.parse(data);
            },
            data: function (data) {
                return this.reader.data(data);
            },
            total: function (data) {
                return this.reader.total(data);
            },
            groups: function (data) {
                return this.reader.groups(data);
            },
            aggregates: function (data) {
                return this.reader.aggregates(data);
            },
            serialize: function (data) {
                return this.reader.serialize(data);
            }
        });
        function applyZone(date, fromZone, toZone) {
            if (toZone) {
                date = kendo.timezone.convert(date, fromZone, toZone);
            } else {
                date = kendo.timezone.remove(date, fromZone);
            }
            return date;
        }
        function validDateValidator(input) {
            if (input.filter('[name=start]').length && input.filter('[title=Start]').length || input.filter('[name=end]').length && input.filter('[title=End]').length) {
                var date;
                var picker = kendo.widgetInstance(input, kendo.ui);
                if (picker) {
                    date = kendo.parseDate(input.val(), picker.options.format);
                    return !!date && picker.value();
                } else {
                    date = kendo.parseDate(input.val());
                    return !!date;
                }
            }
            return true;
        }
        function dateCompareValidator(input) {
            if (input.filter('[name=end]').length) {
                var container = input.closest('.k-scheduler-edit-form');
                var startInput = container.find('[name=start]:visible');
                var endInput = container.find('[name=end]:visible');
                if (endInput[0] && startInput[0]) {
                    var start, end;
                    var startPicker = kendo.widgetInstance(startInput, kendo.ui);
                    var endPicker = kendo.widgetInstance(endInput, kendo.ui);
                    var editable = container.data('kendoEditable');
                    var model = editable ? editable.options.model : null;
                    if (startPicker && endPicker) {
                        start = startPicker.value();
                        end = endPicker.value();
                    } else {
                        start = kendo.parseDate(startInput.val());
                        end = kendo.parseDate(endInput.val());
                    }
                    if (start && end) {
                        if (model) {
                            var timezone = startInput.attr(kendo.attr('timezone'));
                            var startTimezone = model.startTimezone;
                            var endTimezone = model.endTimezone;
                            startTimezone = startTimezone || endTimezone;
                            endTimezone = endTimezone || startTimezone;
                            if (startTimezone) {
                                start = applyZone(start, startTimezone, timezone);
                                end = applyZone(end, endTimezone, timezone);
                            }
                        }
                        return start <= end;
                    }
                }
            }
            return true;
        }
        var SchedulerEvent = kendo.data.Model.define({
            init: function (value) {
                var that = this;
                kendo.data.Model.fn.init.call(that, value);
                that._defaultId = that.defaults[that.idField];
            },
            _time: function (field) {
                var date = this[field];
                var fieldTime = '_' + field + 'Time';
                if (this[fieldTime]) {
                    return this[fieldTime] - kendo.date.toUtcTime(kendo.date.getDate(date));
                }
                return getMilliseconds(date);
            },
            _date: function (field) {
                var fieldTime = '_' + field + 'Time';
                if (this[fieldTime]) {
                    return this[fieldTime] - this._time(field);
                }
                return kendo.date.getDate(this[field]);
            },
            clone: function (options, updateUid) {
                var uid = this.uid, event = new this.constructor($.extend({}, this.toJSON(), options));
                if (!updateUid) {
                    event.uid = uid;
                }
                return event;
            },
            duration: function () {
                var end = this.end;
                var start = this.start;
                var offset = (end.getTimezoneOffset() - start.getTimezoneOffset()) * kendo.date.MS_PER_MINUTE;
                return end - start - offset;
            },
            expand: function (start, end, zone) {
                return recurrence ? recurrence.expand(this, start, end, zone) : [this];
            },
            update: function (eventInfo) {
                for (var field in eventInfo) {
                    this.set(field, eventInfo[field]);
                }
                if (this._startTime) {
                    this.set('_startTime', kendo.date.toUtcTime(this.start));
                }
                if (this._endTime) {
                    this.set('_endTime', kendo.date.toUtcTime(this.end));
                }
            },
            isMultiDay: function () {
                return this.isAllDay || this.duration() >= kendo.date.MS_PER_DAY;
            },
            isException: function () {
                return !this.isNew() && this.recurrenceId;
            },
            isOccurrence: function () {
                return this.isNew() && this.recurrenceId;
            },
            isRecurring: function () {
                return !!(this.recurrenceRule || this.recurrenceId);
            },
            isRecurrenceHead: function () {
                return !!(this.id && this.recurrenceRule);
            },
            toOccurrence: function (options) {
                options = $.extend(options, {
                    recurrenceException: null,
                    recurrenceRule: null,
                    recurrenceId: this.id || this.recurrenceId
                });
                options[this.idField] = this.defaults[this.idField];
                return this.clone(options, true);
            },
            toJSON: function () {
                var obj = kendo.data.Model.fn.toJSON.call(this);
                obj.uid = this.uid;
                delete obj._startTime;
                delete obj._endTime;
                return obj;
            },
            shouldSerialize: function (field) {
                return kendo.data.Model.fn.shouldSerialize.call(this, field) && field !== '_defaultId';
            },
            set: function (key, value) {
                var isAllDay = this.isAllDay || false;
                kendo.data.Model.fn.set.call(this, key, value);
                if (key == 'isAllDay' && value != isAllDay) {
                    var start = kendo.date.getDate(this.start);
                    var end = new Date(this.end);
                    var milliseconds = kendo.date.getMilliseconds(end);
                    if (milliseconds === 0 && value) {
                        milliseconds = MS_PER_DAY;
                    }
                    this.set('start', start);
                    if (value === true) {
                        kendo.date.setTime(end, -milliseconds);
                        if (end < start) {
                            end = start;
                        }
                    } else {
                        kendo.date.setTime(end, MS_PER_DAY - milliseconds);
                    }
                    this.set('end', end);
                }
            },
            id: 'id',
            fields: {
                id: { type: 'number' },
                title: {
                    defaultValue: '',
                    type: 'string'
                },
                start: {
                    type: 'date',
                    validation: {
                        required: true,
                        validDate: { value: validDateValidator }
                    }
                },
                startTimezone: { type: 'string' },
                end: {
                    type: 'date',
                    validation: {
                        required: true,
                        validDate: { value: validDateValidator },
                        dateCompare: { value: dateCompareValidator }
                    }
                },
                endTimezone: { type: 'string' },
                recurrenceRule: {
                    defaultValue: '',
                    type: 'string'
                },
                recurrenceException: {
                    defaultValue: '',
                    type: 'string'
                },
                isAllDay: {
                    type: 'boolean',
                    defaultValue: false
                },
                description: { type: 'string' }
            }
        });
        var SchedulerDataSource = DataSource.extend({
            init: function (options) {
                DataSource.fn.init.call(this, extend(true, {}, {
                    schema: {
                        modelBase: SchedulerEvent,
                        model: SchedulerEvent
                    }
                }, options));
                this.reader = new SchedulerDataReader(this.options.schema, this.reader);
            },
            expand: function (start, end) {
                var data = this.view(), filter = {}, endOffset;
                if (start && end) {
                    endOffset = end.getTimezoneOffset();
                    end = new Date(end.getTime() + MS_PER_DAY - 1);
                    if (end.getTimezoneOffset() !== endOffset) {
                        end = kendo.timezone.apply(end, endOffset);
                    }
                    filter = {
                        logic: 'or',
                        filters: [
                            {
                                logic: 'and',
                                filters: [
                                    {
                                        field: 'start',
                                        operator: 'gte',
                                        value: start
                                    },
                                    {
                                        field: 'end',
                                        operator: 'gte',
                                        value: start
                                    },
                                    {
                                        field: 'start',
                                        operator: 'lte',
                                        value: end
                                    }
                                ]
                            },
                            {
                                logic: 'and',
                                filters: [
                                    {
                                        field: 'start',
                                        operator: 'lte',
                                        value: new Date(start.getTime() + MS_PER_DAY - 1)
                                    },
                                    {
                                        field: 'end',
                                        operator: 'gte',
                                        value: start
                                    }
                                ]
                            }
                        ]
                    };
                    data = new kendo.data.Query(expandAll(data, start, end, this.reader.timezone)).filter(filter).toArray();
                }
                return data;
            },
            cancelChanges: function (model) {
                if (model && model.isOccurrence()) {
                    this._removeExceptionDate(model);
                }
                DataSource.fn.cancelChanges.call(this, model);
            },
            insert: function (index, model) {
                if (!model) {
                    return;
                }
                if (!(model instanceof SchedulerEvent)) {
                    var eventInfo = model;
                    model = this._createNewModel();
                    model.accept(eventInfo);
                }
                if (!this._pushCreated && model.isRecurrenceHead() || model.recurrenceId) {
                    model = model.recurrenceId ? model : model.toOccurrence();
                    this._addExceptionDate(model);
                }
                return DataSource.fn.insert.call(this, index, model);
            },
            pushCreate: function (items) {
                this._pushCreated = true;
                DataSource.fn.pushCreate.call(this, items);
                this._pushCreated = false;
            },
            remove: function (model) {
                if (model.isRecurrenceHead()) {
                    this._removeExceptions(model);
                } else if (model.isRecurring()) {
                    this._addExceptionDate(model);
                }
                return DataSource.fn.remove.call(this, model);
            },
            _removeExceptions: function (model) {
                var data = this.data().slice(0), item = data.shift(), id = model.id;
                while (item) {
                    if (item.recurrenceId === id) {
                        DataSource.fn.remove.call(this, item);
                    }
                    item = data.shift();
                }
                model.set(RECURRENCE_EXCEPTION, '');
            },
            _removeExceptionDate: function (model) {
                if (model.recurrenceId) {
                    var head = this.get(model.recurrenceId);
                    if (head) {
                        var start = model.defaults.start;
                        var replaceRegExp = new RegExp('(\\' + EXCEPTION_SEPARATOR + '?)' + recurrence.toExceptionString(start, this.reader.timezone));
                        var recurrenceException = (head.recurrenceException || '').replace(OLD_EXCEPTION_SEPARATOR_REGEXP, EXCEPTION_SEPARATOR).replace(/\,$/, '');
                        if (replaceRegExp.test(recurrenceException)) {
                            head.set(RECURRENCE_EXCEPTION, recurrenceException.replace(replaceRegExp, ''));
                        } else {
                            start = model.start;
                            replaceRegExp = new RegExp('(\\' + EXCEPTION_SEPARATOR + '?)' + recurrence.toExceptionString(start, this.reader.timezone));
                            head.set(RECURRENCE_EXCEPTION, recurrenceException.replace(replaceRegExp, ''));
                        }
                    }
                }
            },
            _addExceptionDate: function (model) {
                var start = model.start;
                var zone = this.reader.timezone;
                var head = this.get(model.recurrenceId);
                var recurrenceException = (head.recurrenceException || '').replace(OLD_EXCEPTION_SEPARATOR_REGEXP, EXCEPTION_SEPARATOR).replace(/\,$/, '');
                if (!recurrence.isException(recurrenceException, start, zone)) {
                    var newException = recurrence.toExceptionString(start, zone);
                    model.defaults.start = start;
                    head.set(RECURRENCE_EXCEPTION, recurrenceException + (recurrenceException && newException ? EXCEPTION_SEPARATOR : '') + newException);
                }
            }
        });
        function expandAll(events, start, end, zone) {
            var length = events.length, data = [], idx = 0;
            for (; idx < length; idx++) {
                data = data.concat(events[idx].expand(start, end, zone));
            }
            return data;
        }
        SchedulerDataSource.create = function (options) {
            if (isArray(options) || options instanceof kendo.data.ObservableArray) {
                options = { data: options };
            }
            var dataSource = options || {}, data = dataSource.data;
            dataSource.data = data;
            if (!(dataSource instanceof SchedulerDataSource) && dataSource instanceof kendo.data.DataSource) {
                throw new Error('Incorrect DataSource type. Only SchedulerDataSource instances are supported');
            }
            return dataSource instanceof SchedulerDataSource ? dataSource : new SchedulerDataSource(dataSource);
        };
        extend(true, kendo.data, {
            SchedulerDataSource: SchedulerDataSource,
            SchedulerDataReader: SchedulerDataReader,
            SchedulerEvent: SchedulerEvent
        });
        var defaultCommands = {
            update: {
                text: 'Save',
                className: 'k-primary k-scheduler-update'
            },
            canceledit: {
                text: 'Cancel',
                className: 'k-scheduler-cancel'
            },
            destroy: {
                text: 'Delete',
                imageClass: 'k-i-close',
                className: 'k-primary k-scheduler-delete',
                iconClass: 'k-icon'
            }
        };
        function trimOptions(options) {
            delete options.name;
            delete options.prefix;
            delete options.remove;
            delete options.edit;
            delete options.add;
            delete options.navigate;
            return options;
        }
        function createValidationAttributes(model, field) {
            var modelField = (model.fields || model)[field];
            var specialRules = [
                'url',
                'email',
                'number',
                'date',
                'boolean'
            ];
            var validation = modelField ? modelField.validation : {};
            var datatype = kendo.attr('type');
            var inArray = $.inArray;
            var ruleName;
            var rule;
            var attr = {};
            for (ruleName in validation) {
                rule = validation[ruleName];
                if (inArray(ruleName, specialRules) >= 0) {
                    attr[datatype] = ruleName;
                } else if (!kendo.isFunction(rule)) {
                    attr[ruleName] = isPlainObject(rule) ? rule.value || ruleName : rule;
                }
                attr[kendo.attr(ruleName + '-msg')] = rule.message;
            }
            return attr;
        }
        function dropDownResourceEditor(resource, model) {
            var attr = createValidationAttributes(model, resource.field);
            return function (container) {
                $(kendo.format('<select data-{0}bind="value:{1}" title="' + model.title + '">', kendo.ns, resource.field)).appendTo(container).attr(attr).kendoDropDownList({
                    dataTextField: resource.dataTextField,
                    dataValueField: resource.dataValueField,
                    dataSource: resource.dataSource,
                    valuePrimitive: resource.valuePrimitive,
                    optionLabel: 'None',
                    template: kendo.format('<span class="k-scheduler-mark" style="background-color:#= data.{0}?{0}:"none" #"></span>#={1}#', resource.dataColorField, resource.dataTextField)
                });
            };
        }
        function dropDownResourceEditorMobile(resource, model) {
            var attr = createValidationAttributes(model, resource.field);
            return function (container) {
                var options = '';
                var view = resource.dataSource.view();
                for (var idx = 0, length = view.length; idx < length; idx++) {
                    options += kendo.format('<option value="{0}">{1}</option>', kendo.getter(resource.dataValueField)(view[idx]), kendo.getter(resource.dataTextField)(view[idx]));
                }
                $(kendo.format('<select data-{0}bind="value:{1}">{2}</select>', kendo.ns, resource.field, options, resource.valuePrimitive)).appendTo(container).attr(attr);
            };
        }
        function descriptionEditor(options) {
            var attr = createValidationAttributes(options.model, options.field);
            return function (container, model) {
                $('<textarea name="description" class="k-textbox" title="' + model.title + '"/>').attr(attr).appendTo(container);
            };
        }
        function multiSelectResourceEditor(resource, model) {
            var attr = createValidationAttributes(model, resource.field);
            return function (container) {
                $(kendo.format('<select data-{0}bind="value:{1}">', kendo.ns, resource.field)).appendTo(container).attr(attr).kendoMultiSelect({
                    dataTextField: resource.dataTextField,
                    dataValueField: resource.dataValueField,
                    dataSource: resource.dataSource,
                    valuePrimitive: resource.valuePrimitive,
                    itemTemplate: kendo.format('<span class="k-scheduler-mark" style="background-color:#= data.{0}?{0}:"none" #"></span>#={1}#', resource.dataColorField, resource.dataTextField),
                    tagTemplate: kendo.format('<span class="k-scheduler-mark" style="background-color:#= data.{0}?{0}:"none" #"></span>#={1}#', resource.dataColorField, resource.dataTextField)
                });
            };
        }
        function multiSelectResourceEditorMobile(resource, model) {
            var attr = createValidationAttributes(model, resource.field);
            return function (container) {
                var options = '';
                var view = resource.dataSource.view();
                for (var idx = 0, length = view.length; idx < length; idx++) {
                    options += kendo.format('<option value="{0}">{1}</option>', kendo.getter(resource.dataValueField)(view[idx]), kendo.getter(resource.dataTextField)(view[idx]));
                }
                $(kendo.format('<select data-{0}bind="value:{1}" multiple="multiple" data-{0}value-primitive="{3}">{2}</select>', kendo.ns, resource.field, options, resource.valuePrimitive)).appendTo(container).attr(attr);
            };
        }
        function moveEventRange(event, distance) {
            var duration = event.end.getTime() - event.start.getTime();
            var start = new Date(event.start.getTime());
            kendo.date.setTime(start, distance);
            var end = new Date(start.getTime());
            kendo.date.setTime(end, duration, true);
            return {
                start: start,
                end: end
            };
        }
        var editors = {
            mobile: {
                dateRange: MOBILEDATERANGEEDITOR,
                timezonePopUp: MOBILETIMEZONEPOPUP,
                timezone: MOBILETIMEZONEEDITOR,
                recurrence: MOBILERECURRENCEEDITOR,
                description: descriptionEditor,
                multipleResources: multiSelectResourceEditorMobile,
                resources: dropDownResourceEditorMobile,
                isAllDay: MOBILEISALLDAYEDITOR
            },
            desktop: {
                dateRange: DATERANGEEDITOR,
                timezonePopUp: TIMEZONEPOPUP,
                timezone: TIMEZONEEDITOR,
                recurrence: RECURRENCEEDITOR,
                description: descriptionEditor,
                multipleResources: multiSelectResourceEditor,
                resources: dropDownResourceEditor
            }
        };
        var Editor = kendo.Observable.extend({
            init: function (element, options) {
                kendo.Observable.fn.init.call(this);
                this.element = element;
                this.options = extend(true, {}, this.options, options);
                this.createButton = this.options.createButton;
                this.toggleDateValidationHandler = proxy(this._toggleDateValidation, this);
            },
            _toggleDateValidation: function (e) {
                if (e.field == 'isAllDay') {
                    var container = this.container, isAllDay = this.editable.options.model.isAllDay, bindAttribute = kendo.attr('bind'), element, isDateTimeInput, shouldValidate;
                    container.find('[' + bindAttribute + '*=end],[' + bindAttribute + '*=start]').each(function () {
                        element = $(this);
                        if (valueStartEndBoundRegex.test(element.attr(bindAttribute))) {
                            isDateTimeInput = element.is('[' + kendo.attr('role') + '=datetimepicker],[type*=datetime]');
                            shouldValidate = isAllDay !== isDateTimeInput;
                            element.attr(kendo.attr('validate'), shouldValidate);
                        }
                    });
                }
            },
            fields: function (editors, model) {
                var that = this;
                var messages = that.options.messages;
                var timezone = that.options.timezone;
                var click = function (e) {
                    e.preventDefault();
                    that._initTimezoneEditor(model, this);
                };
                var fields = [
                    {
                        field: 'title',
                        title: messages.editor.title
                    },
                    {
                        field: 'start',
                        title: messages.editor.start,
                        editor: editors.dateRange,
                        timezone: timezone
                    },
                    {
                        field: 'end',
                        title: messages.editor.end,
                        editor: editors.dateRange,
                        timezone: timezone
                    },
                    {
                        field: 'isAllDay',
                        title: messages.editor.allDayEvent,
                        editor: editors.isAllDay
                    }
                ];
                if (kendo.timezone.windows_zones) {
                    fields.push({
                        field: 'timezone',
                        title: messages.editor.timezone,
                        editor: editors.timezonePopUp,
                        click: click,
                        messages: messages.editor,
                        model: model
                    });
                    fields.push({
                        field: 'startTimezone',
                        title: messages.editor.startTimezone,
                        editor: editors.timezone,
                        noTimezone: messages.editor.noTimezone
                    });
                    fields.push({
                        field: 'endTimezone',
                        title: messages.editor.endTimezone,
                        editor: editors.timezone,
                        noTimezone: messages.editor.noTimezone
                    });
                }
                if (!model.recurrenceId) {
                    fields.push({
                        field: 'recurrenceRule',
                        title: messages.editor.repeat,
                        editor: editors.recurrence,
                        timezone: timezone,
                        messages: messages.recurrenceEditor,
                        pane: this.pane
                    });
                }
                if ('description' in model) {
                    fields.push({
                        field: 'description',
                        title: messages.editor.description,
                        editor: editors.description({
                            model: model,
                            field: 'description'
                        })
                    });
                }
                for (var resourceIndex = 0; resourceIndex < this.options.resources.length; resourceIndex++) {
                    var resource = this.options.resources[resourceIndex];
                    fields.push({
                        field: resource.field,
                        title: resource.title,
                        editor: resource.multiple ? editors.multipleResources(resource, model) : editors.resources(resource, model)
                    });
                }
                return fields;
            },
            end: function () {
                return this.editable.end();
            },
            _buildDesktopEditTemplate: function (model, fields, editableFields) {
                var messages = this.options.messages;
                var settings = extend({}, kendo.Template, this.options.templateSettings);
                var paramName = settings.paramName;
                var html = '';
                for (var idx = 0, length = fields.length; idx < length; idx++) {
                    var field = fields[idx];
                    if (field.field === 'startTimezone') {
                        html += '<div class="k-popup-edit-form k-scheduler-edit-form k-scheduler-timezones" style="display:none">';
                        html += '<div class="k-edit-form-container">';
                        html += '<div class="k-edit-label"></div>';
                        html += '<div class="k-edit-field"><label class="k-check"><input class="k-timezone-toggle" type="checkbox" />' + messages.editor.separateTimezones + '</label></div>';
                    }
                    html += '<div class="k-edit-label"><label for="' + field.field + '">' + (field.title || field.field || '') + '</label></div>';
                    if (!model.editable || model.editable(field.field)) {
                        editableFields.push(field);
                        html += '<div ' + kendo.attr('container-for') + '="' + field.field + '" class="k-edit-field"></div>';
                    } else {
                        var tmpl = '#:';
                        if (field.field) {
                            field = kendo.expr(field.field, paramName);
                            tmpl += field + '==null?\'\':' + field;
                        } else {
                            tmpl += '\'\'';
                        }
                        tmpl += '#';
                        tmpl = kendo.template(tmpl, settings);
                        html += '<div class="k-edit-field">' + tmpl(model) + '</div>';
                    }
                    if (field.field === 'endTimezone') {
                        html += this._createEndTimezoneButton();
                    }
                }
                return html;
            },
            _buildMobileEditTemplate: function (model, fields, editableFields) {
                var messages = this.options.messages;
                var settings = extend({}, kendo.Template, this.options.templateSettings);
                var paramName = settings.paramName;
                var html = '';
                html += '<ul>';
                for (var idx = 0, length = fields.length; idx < length; idx++) {
                    var field = fields[idx];
                    if (field.field === 'timezone' || field.field === 'recurrenceRule') {
                        html += '</ul><ul>';
                    }
                    if (field.field === 'startTimezone') {
                        html += '<div class="k-popup-edit-form k-scheduler-edit-form k-scheduler-timezones" style="display:none">';
                        html += '<ul><li class="k-item"><label class="k-label">';
                        html += '<span class="k-item-title">' + messages.editor.separateTimezones + '</span>';
                        html += '<input class="k-timezone-toggle" data-role="switch" type="checkbox">';
                        html += '</label></li>';
                    }
                    if (!model.editable || model.editable(field.field)) {
                        html += '<li class="k-item">';
                        if (field.field === 'timezone') {
                            html += '<label class="k-label" data-bind="css: { k-state-disabled: isAllDay }">';
                        } else {
                            html += '<label class="k-label">';
                        }
                        html += '<span class="k-item-title">' + (field.title || field.field || '') + '</span>';
                        editableFields.push(field);
                        html += '<div ' + kendo.attr('container-for') + '="' + field.field + '"></div>';
                    } else {
                        var tmpl = '#:';
                        html += '<li class="k-item">';
                        html += '<label class="k-label k-no-click">';
                        html += '<span class="k-item-title">' + (field.title || field.field || '') + '</span>';
                        if (field.field) {
                            field = kendo.expr(field.field, paramName);
                            tmpl += field + '==null?\'\':' + field;
                        } else {
                            tmpl += '\'\'';
                        }
                        tmpl += '#';
                        tmpl = kendo.template(tmpl, settings);
                        html += '<span class="k-no-editor">' + tmpl(model) + '</span>';
                    }
                    html += '</label></li>';
                    if (field.field === 'recurrenceRule') {
                        html += '</ul><ul>';
                    }
                    if (field.field === 'endTimezone') {
                        html += this._createEndTimezoneButton();
                    }
                }
                html += '</ul>';
                return html;
            },
            _buildEditTemplate: function (model, fields, editableFields, isMobile) {
                var settings = extend({}, kendo.Template, this.options.templateSettings);
                var template = this.options.editable.template;
                var html = '';
                if (template) {
                    if (typeof template === STRING) {
                        template = window.unescape(template);
                    }
                    html += kendo.template(template, settings)(model);
                } else if (isMobile) {
                    html += '<div data-role="content">' + this._buildMobileEditTemplate(model, fields, editableFields) + '</div>';
                } else {
                    html += this._buildDesktopEditTemplate(model, fields, editableFields);
                }
                return html;
            },
            _createEndTimezoneButton: function () {
                return '</ul></div>';
            },
            _revertTimezones: function (model) {
                model.set('startTimezone', this._startTimezone);
                model.set('endTimezone', this._endTimezone);
                delete this._startTimezone;
                delete this._endTimezone;
            }
        });
        var MobileEditor = Editor.extend({
            init: function () {
                Editor.fn.init.apply(this, arguments);
                this.pane = kendo.Pane.wrap(this.element, {
                    viewEngine: {
                        viewOptions: {
                            renderOnInit: true,
                            wrap: false,
                            wrapInSections: true,
                            detachOnHide: false,
                            detachOnDestroy: false
                        }
                    }
                });
                this.pane.element.parent().css('height', this.options.height);
                this.view = this.pane.view();
            },
            options: {
                animations: {
                    left: 'slide',
                    right: 'slide:right'
                }
            },
            destroy: function () {
                this.close();
                this.unbind();
                this.pane.destroy();
            },
            _initTimezoneEditor: function (model) {
                var that = this;
                var pane = that.pane;
                var messages = that.options.messages;
                var timezoneView = that.timezoneView;
                var container = timezoneView ? timezoneView.content.find('.k-scheduler-timezones') : that.container.find('.k-scheduler-timezones');
                var kSwitch = container.find('input.k-timezone-toggle').data('kendoSwitch');
                var endTimezoneRow = container.find('li.k-item:not(.k-zonepicker):last');
                var startTimezoneChange = function (e) {
                    if (e.field === 'startTimezone') {
                        var value = model.startTimezone;
                        kSwitch.enable(value);
                        if (!value) {
                            endTimezoneRow.hide();
                            model.set('endTimezone', '');
                            kSwitch.value(false);
                        }
                    }
                };
                that._startTimezone = model.startTimezone || '';
                that._endTimezone = model.endTimezone || '';
                if (!timezoneView) {
                    var html = '<div data-role="view" class="k-popup-edit-form k-scheduler-edit-form k-mobile-list">' + '<div data-role="header" class="k-header">' + '<a href="\\#" class="k-header-cancel k-scheduler-cancel k-link" title="' + messages.cancel + '"' + 'aria-label="' + messages.cancel + '"><span class="k-icon k-i-arrow-chevron-left"></span></a>' + messages.editor.timezoneTitle + '<a href="\\#" class="k-header-done k-scheduler-update k-link" title="' + messages.save + '" ' + 'aria-label="' + messages.save + '"><span class="k-icon k-i-check"></span></a>' + '</div><div data-role="content"></div>';
                    this.timezoneView = timezoneView = pane.append(html);
                    timezoneView.contentElement.append(container.show());
                    timezoneView.element.on(CLICK + NS, '.k-scheduler-cancel, .k-scheduler-update', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        if ($(this).hasClass('k-scheduler-cancel')) {
                            that._revertTimezones(model);
                        }
                        model.unbind('change', startTimezoneChange);
                        var editView = that._editPane;
                        var text = timezoneButtonText(model, messages.editor.noTimezone);
                        editView.content.find('.k-timezone-label').text(text);
                        pane.navigate(editView, that.options.animations.right);
                    });
                    kSwitch.bind('change', function (ev) {
                        endTimezoneRow.toggle(ev.checked);
                        model.set('endTimezone', '');
                    });
                    model.bind('change', startTimezoneChange);
                }
                kSwitch.value(!!model.endTimezone);
                kSwitch.enable(!!model.startTimezone);
                if (model.endTimezone) {
                    endTimezoneRow.show();
                } else {
                    endTimezoneRow.hide();
                }
                pane.navigate(timezoneView, that.options.animations.left);
            },
            showDialog: function (options) {
                var actions = options.buttons.map(function (button) {
                    return {
                        text: button.text,
                        action: button.click
                    };
                });
                actions.push({
                    text: this.options.messages.cancel,
                    primary: true
                });
                $('<div />').appendTo(document.body).kendoDialog({
                    close: function () {
                        this.destroy();
                    },
                    modal: { preventScroll: true },
                    closable: false,
                    title: false,
                    content: options.text,
                    actions: actions
                });
            },
            editEvent: function (model) {
                var pane = this.pane;
                var html = '';
                var messages = this.options.messages;
                var updateText = messages.save;
                var removeText = messages.destroy;
                var cancelText = messages.cancel;
                var titleText = messages.editor.editorTitle;
                var resetSeries = messages.resetSeries;
                html += '<div data-role="view" class="k-popup-edit-form k-scheduler-edit-form k-mobile-list"' + kendo.attr('uid') + '="' + model.uid + '">' + '<div data-role="header" class="k-header">' + '<a href="\\#" class="k-header-cancel k-scheduler-cancel k-link" title="' + cancelText + '"' + 'aria-label="' + cancelText + '"><span class="k-icon k-i-arrow-chevron-left"></span></a>' + titleText + '<a href="\\#" class="k-header-done k-scheduler-update k-link" title="' + updateText + '" ' + 'aria-label="' + updateText + '"><span class="k-icon k-i-check"></span></a>' + '</div>';
                var fields = this.fields(editors.mobile, model);
                var that = this;
                var editableFields = [];
                html += this._buildEditTemplate(model, fields, editableFields, true);
                html += '</div>';
                var view = pane.append(html);
                if (!model.isNew() && this.options.editable && this.options.editable.destroy !== false && model.isRecurrenceHead() && model.recurrenceException) {
                    var resetSeriesBtn = '<ul class="k-edit-buttons"><li class="k-item"><span href="#" class="k-scheduler-resetSeries k-label" aria-label="' + resetSeries + '">' + resetSeries + '</span></li></ul>';
                    view.contentElement.append(resetSeriesBtn);
                }
                if (!model.isNew() && this.options.editable && this.options.editable.destroy !== false) {
                    var deleteBtn = '<ul class="k-edit-buttons"><li class="k-item"><span href="#" class="k-scheduler-delete k-label" aria-label="' + removeText + '">' + removeText + '</span></li></ul>';
                    view.contentElement.append(deleteBtn);
                }
                this._editPane = view;
                var container = this.container = view.element;
                this.editable = container.kendoEditable({
                    fields: editableFields,
                    model: model,
                    clearContainer: false,
                    target: that.options.target,
                    validateOnBlur: true
                }).data('kendoEditable');
                if (!this.trigger('edit', {
                        container: container,
                        model: model
                    })) {
                    container.on(CLICK + NS, 'a.k-scheduler-edit, a.k-scheduler-cancel, a.k-scheduler-update, span.k-scheduler-delete, span.k-scheduler-resetSeries', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        var button = $(this);
                        if (!button.hasClass('k-scheduler-edit')) {
                            var name = 'cancel';
                            if (button.hasClass('k-scheduler-update')) {
                                name = 'save';
                            } else if (button.hasClass('k-scheduler-delete')) {
                                name = 'remove';
                            } else if (button.hasClass('k-scheduler-resetSeries')) {
                                name = RESET;
                            }
                            that.trigger(name, {
                                container: container,
                                model: model
                            });
                        } else {
                            pane.navigate(this._editPane, that.options.animations.right);
                        }
                    });
                    pane.navigate(view, that.options.animations.left);
                    model.bind('change', that.toggleDateValidationHandler);
                } else {
                    this.trigger('cancel', {
                        container: container,
                        model: model
                    });
                }
                return this.editable;
            },
            _views: function () {
                return this.pane.element.find(kendo.roleSelector('view')).not(this.view.element);
            },
            close: function () {
                if (this.container) {
                    this.pane.navigate('', this.options.animations.right);
                    var views = this._views();
                    var view;
                    for (var idx = 0, length = views.length; idx < length; idx++) {
                        view = views.eq(idx).data('kendoView');
                        if (view) {
                            view.purge();
                        }
                    }
                    views.remove();
                    this.container = null;
                    if (this.editable) {
                        this.editable.options.model.unbind('change', this.toggleDateValidationHandler);
                        this.editable.destroy();
                        this.editable = null;
                    }
                    this.timezoneView = null;
                }
            }
        });
        var PopupEditor = Editor.extend({
            destroy: function () {
                this.close();
                this.unbind();
            },
            editEvent: function (model) {
                var that = this;
                var editable = that.options.editable;
                var html = '<div ' + kendo.attr('uid') + '="' + model.uid + '" class="k-popup-edit-form k-scheduler-edit-form"><div class="k-edit-form-container">';
                var messages = that.options.messages;
                var updateText = messages.save;
                var cancelText = messages.cancel;
                var deleteText = messages.destroy;
                var resetSeries = messages.resetSeries;
                var fields = this.fields(editors.desktop, model);
                var editableFields = [];
                html += this._buildEditTemplate(model, fields, editableFields, false);
                var attr;
                var options = isPlainObject(editable) ? editable.window : {};
                html += '<div class="k-edit-buttons k-state-default">';
                html += this.createButton({
                    name: 'update',
                    text: updateText,
                    attr: attr
                }) + this.createButton({
                    name: 'canceledit',
                    text: cancelText,
                    attr: attr
                });
                if (!model.isNew() && editable.destroy !== false && model.isRecurrenceHead() && model.recurrenceException) {
                    html += this.createButton({
                        name: 'resetSeries',
                        text: resetSeries,
                        attr: attr
                    });
                }
                if (!model.isNew() && editable.destroy !== false) {
                    html += this.createButton({
                        name: 'delete',
                        text: deleteText,
                        attr: attr
                    });
                }
                html += '</div></div></div>';
                var container = this.container = $(html).appendTo(that.element).eq(0).kendoWindow(extend({
                    modal: true,
                    resizable: false,
                    draggable: true,
                    title: messages.editor.editorTitle,
                    visible: false,
                    close: function (e) {
                        if (e.userTriggered) {
                            if (that.trigger(CANCEL, {
                                    container: container,
                                    model: model
                                })) {
                                e.preventDefault();
                            }
                        }
                    }
                }, options));
                that.editable = container.kendoEditable({
                    fields: editableFields,
                    model: model,
                    clearContainer: false,
                    validateOnBlur: true,
                    target: that.options.target
                }).data('kendoEditable');
                if (!that.trigger(EDIT, {
                        container: container,
                        model: model
                    })) {
                    container.data('kendoWindow').center().open();
                    container.on(CLICK + NS, 'a.k-scheduler-cancel', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        that.trigger(CANCEL, {
                            container: container,
                            model: model
                        });
                    });
                    container.on(CLICK + NS, 'a.k-scheduler-update', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        that.trigger('save', {
                            container: container,
                            model: model
                        });
                    });
                    container.on(CLICK + NS, 'a.k-scheduler-delete', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        that.trigger(REMOVE, {
                            container: container,
                            model: model
                        });
                    });
                    container.on(CLICK + NS, 'a.k-scheduler-resetSeries', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        that.trigger(RESET, {
                            container: container,
                            model: model
                        });
                    });
                    kendo.cycleForm(container);
                    model.bind('change', that.toggleDateValidationHandler);
                } else {
                    that.trigger(CANCEL, {
                        container: container,
                        model: model
                    });
                }
                return that.editable;
            },
            close: function () {
                var that = this;
                var destroy = function () {
                    if (that.editable) {
                        that.editable.options.model.unbind('change', that.toggleDateValidationHandler);
                        that.editable.destroy();
                        that.editable = null;
                        that.container = null;
                    }
                    if (that.popup) {
                        that.popup.destroy();
                        that.popup = null;
                    }
                };
                if (that.editable) {
                    if (that._timezonePopup && that._timezonePopup.data('kendoWindow')) {
                        that._timezonePopup.data('kendoWindow').destroy();
                        that._timezonePopup = null;
                    }
                    if (that.container.is(':visible')) {
                        that.container.data('kendoWindow').bind('deactivate', destroy).close();
                    } else {
                        destroy();
                    }
                } else {
                    destroy();
                }
            },
            _createEndTimezoneButton: function () {
                var messages = this.options.messages;
                var html = '';
                html += '<div class="k-edit-buttons k-state-default">';
                html += this.createButton({
                    name: 'savetimezone',
                    text: messages.save
                }) + this.createButton({
                    name: 'canceltimezone',
                    text: messages.cancel
                });
                html += '</div></div></div>';
                return html;
            },
            showDialog: function (options) {
                var html = kendo.format('<div class=\'k-popup-edit-form\'><div class=\'k-edit-form-container\'><p class=\'k-popup-message\'>{0}</p>', options.text);
                html += '<div class="k-edit-buttons k-state-default">';
                for (var buttonIndex = 0; buttonIndex < options.buttons.length; buttonIndex++) {
                    html += this.createButton(options.buttons[buttonIndex]);
                }
                html += '</div></div></div>';
                var wrapper = this.element;
                if (this.popup) {
                    this.popup.destroy();
                }
                var popup = this.popup = $(html).appendTo(wrapper).eq(0).on(CLICK, '.k-button', function (e) {
                    e.preventDefault();
                    popup.close();
                    var buttonIndex = $(e.currentTarget).index();
                    options.buttons[buttonIndex].click();
                }).kendoWindow({
                    modal: true,
                    resizable: false,
                    draggable: false,
                    title: options.title,
                    visible: false,
                    close: function () {
                        this.destroy();
                        wrapper.focus();
                    }
                }).getKendoWindow();
                popup.center().open();
            },
            _initTimezoneEditor: function (model, activator) {
                var that = this;
                var container = that.container.find('.k-scheduler-timezones');
                var checkbox = container.find('input.k-timezone-toggle');
                var endTimezoneRow = container.find('.k-edit-label:last').add(container.find('.k-edit-field:last'));
                var saveButton = container.find('.k-scheduler-savetimezone');
                var cancelButton = container.find('.k-scheduler-canceltimezone');
                var timezonePopup = that._timezonePopup;
                var startTimezoneChange = function (e) {
                    if (e.field === 'startTimezone') {
                        var value = model.startTimezone;
                        checkbox.prop('disabled', !value);
                        if (!value) {
                            endTimezoneRow.hide();
                            model.set('endTimezone', '');
                            checkbox.prop('checked', false);
                        }
                    }
                };
                var wnd;
                that._startTimezone = model.startTimezone;
                that._endTimezone = model.endTimezone;
                if (!timezonePopup) {
                    that._timezonePopup = timezonePopup = container.kendoWindow({
                        modal: true,
                        resizable: false,
                        draggable: true,
                        title: that.options.messages.editor.timezoneEditorTitle,
                        visible: false,
                        close: function (e) {
                            model.unbind('change', startTimezoneChange);
                            if (e.userTriggered) {
                                that._revertTimezones(model);
                            }
                            if (activator) {
                                activator.focus();
                            }
                        }
                    });
                    checkbox.click(function () {
                        endTimezoneRow.toggle(checkbox.prop('checked'));
                        model.set('endTimezone', '');
                    });
                    saveButton.click(function (e) {
                        e.preventDefault();
                        wnd.close();
                    });
                    cancelButton.click(function (e) {
                        e.preventDefault();
                        that._revertTimezones(model);
                        wnd.close();
                    });
                    model.bind('change', startTimezoneChange);
                }
                checkbox.prop('checked', model.endTimezone).prop('disabled', !model.startTimezone);
                if (model.endTimezone) {
                    endTimezoneRow.show();
                } else {
                    endTimezoneRow.hide();
                }
                wnd = timezonePopup.data('kendoWindow');
                wnd.center().open();
            }
        });
        var Scheduler = DataBoundWidget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                if (!that.options.views || !that.options.views.length) {
                    that.options.views = [
                        'day',
                        'week'
                    ];
                }
                that.resources = [];
                that._initModel();
                that._wrapper();
                that._views();
                that._toolbar();
                that._dataSource();
                that._resources();
                that._resizeHandler = function () {
                    that.resize();
                };
                that.wrapper.on(MOUSEDOWN + NS + ' selectstart' + NS, function (e) {
                    if (!$(e.target).is(':kendoFocusable')) {
                        e.preventDefault();
                    }
                });
                if (that.options.editable && that.options.editable.resize !== false) {
                    that._resizable();
                }
                that._movable();
                that._bindResize();
                if (that.options.messages && that.options.messages.recurrence) {
                    recurrence.options = that.options.messages.recurrence;
                }
                that._selectable();
                that._touchHandlers();
                that._ariaId = kendo.guid();
                that._createEditor();
            },
            _bindResize: function () {
                $(window).on('resize' + NS, this._resizeHandler);
            },
            _unbindResize: function () {
                $(window).off('resize' + NS, this._resizeHandler);
            },
            dataItems: function () {
                var that = this;
                var items = that.items();
                var events = that._data;
                var eventsUids = $.map(items, function (item) {
                    return $(item).attr('data-uid');
                });
                var i;
                var key;
                var dict = {};
                var eventsUidsLength = eventsUids.length;
                for (i = 0; i < eventsUidsLength; i++) {
                    dict[eventsUids[i]] = null;
                }
                var eventsCount = events.length;
                for (i = 0; i < eventsCount; i++) {
                    var event = events[i];
                    if (dict[event.uid] !== undefined) {
                        dict[event.uid] = event;
                    }
                }
                var sortedData = [];
                for (key in dict) {
                    sortedData.push(dict[key]);
                }
                return sortedData;
            },
            _isMobile: function () {
                var options = this.options;
                return options.mobile === true && kendo.support.mobileOS || options.mobile === 'phone' || options.mobile === 'tablet';
            },
            _isTouch: function (event) {
                return /touch/.test(event.type) || event.originalEvent && /touch/.test(event.originalEvent.pointerType);
            },
            _isInverseColor: function (eventElement) {
                return eventElement.hasClass(INVERSECOLORCLASS);
            },
            _groupsByResource: function (resources, groupIndex, groupsArray, parentFieldValue, parentField) {
                if (!groupsArray) {
                    groupsArray = [];
                }
                var resource = resources[0];
                if (resource) {
                    var group;
                    var data = resource.dataSource.view();
                    var prevIndex = 0;
                    for (var dataIndex = 0; dataIndex < data.length; dataIndex++) {
                        var fieldValue = kendo.getter(resource.dataValueField)(data[dataIndex]);
                        var currentGroupIndex = groupIndex + prevIndex + dataIndex;
                        group = this._groupsByResource(resources.slice(1), currentGroupIndex, groupsArray, fieldValue, resource.field);
                        group[resource.field] = fieldValue;
                        prevIndex = group.groupIndex;
                        if (parentField && parentFieldValue) {
                            group[parentField] = parentFieldValue;
                        }
                        if (resources.length === 1) {
                            group.groupIndex = groupIndex + dataIndex;
                            groupsArray.push(group);
                        }
                    }
                    return group;
                } else {
                    return {};
                }
            },
            data: function () {
                return this._data;
            },
            select: function (options) {
                var that = this;
                var view = that.view();
                var selection = that._selection;
                var groups = view.groups;
                var selectedGroups;
                if (options === undefined) {
                    var selectedEvents;
                    var slots = view._selectedSlots;
                    if (!selection) {
                        return [];
                    }
                    if (selection && selection.events) {
                        selectedEvents = that._selectedEvents();
                    }
                    return {
                        start: selection.start,
                        end: selection.end,
                        events: selectedEvents,
                        slots: slots,
                        resources: view._resourceBySlot(selection)
                    };
                }
                if (!options) {
                    that._selection = null;
                    that._old = null;
                    view.clearSelection();
                    return;
                }
                if ($.isArray(options)) {
                    options = { events: options.splice(0) };
                }
                if (options.resources) {
                    var fieldName;
                    var filters = [];
                    var groupsByResource = [];
                    if (view.groupedResources) {
                        that._groupsByResource(view.groupedResources, 0, groupsByResource);
                    }
                    for (fieldName in options.resources) {
                        filters.push({
                            field: fieldName,
                            operator: 'eq',
                            value: options.resources[fieldName]
                        });
                    }
                    selectedGroups = new kendo.data.Query(groupsByResource).filter(filters).toArray();
                }
                if (options.events && options.events.length) {
                    that._selectEvents(options.events, selectedGroups);
                    that._select();
                    return;
                }
                if (groups && (options.start && options.end)) {
                    var rangeStart = getDate(view._startDate);
                    var rangeEnd = kendo.date.addDays(getDate(view._endDate), 1);
                    var group;
                    var ranges;
                    if (options.start < rangeEnd && rangeStart <= options.end) {
                        if (selectedGroups && selectedGroups.length) {
                            group = groups[selectedGroups[0].groupIndex];
                        } else {
                            group = groups[0];
                        }
                        if (!group.timeSlotCollectionCount()) {
                            options.isAllDay = true;
                        }
                        ranges = group.ranges(options.start, options.end, options.isAllDay, false);
                        if (ranges.length) {
                            that._selection = {
                                start: kendo.timezone.toLocalDate(ranges[0].start.start),
                                end: kendo.timezone.toLocalDate(ranges[ranges.length - 1].end.end),
                                groupIndex: ranges[0].start.groupIndex,
                                index: ranges[0].start.index,
                                isAllDay: ranges[0].start.isDaySlot,
                                events: []
                            };
                            that._select();
                        }
                    }
                }
            },
            _selectEvents: function (eventsUids, selectedGroups) {
                var that = this;
                var idx;
                var view = that.view();
                var groups = view.groups;
                var eventsLength = eventsUids.length;
                var isGrouped = selectedGroups && selectedGroups.length;
                for (idx = 0; idx < eventsLength; idx++) {
                    if (groups && isGrouped) {
                        var currentGroup = groups[selectedGroups[0].groupIndex];
                        var events = [];
                        var timeSlotCollectionCount = currentGroup.timeSlotCollectionCount();
                        var daySlotCollectionCount = currentGroup.daySlotCollectionCount();
                        for (var collIdx = 0; collIdx < timeSlotCollectionCount; collIdx++) {
                            events = events.concat(currentGroup.getTimeSlotCollection(collIdx).events());
                        }
                        for (var dayCollIdx = 0; dayCollIdx < daySlotCollectionCount; dayCollIdx++) {
                            events = events.concat(currentGroup.getDaySlotCollection(dayCollIdx).events());
                        }
                        events = new kendo.data.Query(events).filter({
                            field: 'element[0].getAttribute(\'data-uid\')',
                            operator: 'eq',
                            value: eventsUids[idx]
                        }).toArray();
                        if (events[0]) {
                            that._createSelection(events[0].element);
                        }
                    } else {
                        var element = view.element.find(kendo.format('.k-event[data-uid={0}], .k-task[data-uid={0}]', eventsUids[idx]));
                        if (element.length) {
                            that._createSelection(element[0]);
                        }
                    }
                }
            },
            _touchHandlers: function () {
                var that = this;
                var startX;
                var startY;
                var endX;
                var endY;
                var timeStamp;
                var wrapper = that.wrapper;
                var touchMoveHandler = $.proxy(that._touchMove, that);
                wrapper.on(TOUCHSTART + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td, .k-event', function (e) {
                    var content = that.wrapper.find('.k-scheduler-content');
                    if (!that._isTouch(e)) {
                        return;
                    }
                    content.stop(true, false);
                    that._touchPosX = startX = that._tapPosition(e, 'X');
                    that._touchPosY = startY = that._tapPosition(e, 'Y');
                    that._userTouched = true;
                    that.view()._scrolling = false;
                    timeStamp = Date.now();
                    wrapper.on(TOUCHMOVE + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td, .k-event', touchMoveHandler);
                });
                wrapper.on(TOUCHEND + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td, .k-event', function (e) {
                    if (!that._isTouch(e)) {
                        return;
                    }
                    var delta = Date.now() - timeStamp;
                    var content = that.wrapper.find('.k-scheduler-content');
                    var amplitude = -that._amplitude * (3000 / delta);
                    endX = that._tapPosition(e, 'X');
                    endY = that._tapPosition(e, 'Y');
                    if (that._dragging) {
                        return;
                    }
                    if (that.options.selectable && (Math.abs(endX - startX) <= 10 || Math.abs(endY - startY) <= 10)) {
                        that._mouseDownSelection(e);
                    }
                    if (!kendo.support.kineticScrollNeeded && delta < 200 && Math.abs(endX - startX) > 10) {
                        content.animate({ scrollTop: content[0].scrollTop + amplitude });
                    }
                    wrapper.off(TOUCHMOVE + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td', touchMoveHandler);
                });
            },
            _selectable: function () {
                var that = this;
                var wrapper = that.wrapper;
                if (!that.options.selectable) {
                    return;
                }
                that._tabindex();
                wrapper.on(MOUSEDOWN + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td, .k-event', function (e) {
                    if (that._isTouch(e)) {
                        return;
                    }
                    that._mouseDownSelection(e);
                });
                var mouseMoveHandler = $.proxy(that._mouseMove, that);
                wrapper.on(MOUSEDOWN + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td', function (e) {
                    var which = e.which;
                    var button = e.button;
                    var isRight = which && which === 3 || button && button == 2;
                    if (that._isTouch(e)) {
                        return;
                    }
                    if (!isRight) {
                        wrapper.on(MOUSEMOVE + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td', mouseMoveHandler);
                    }
                });
                wrapper.on('mouseup' + NS + ' mousecancel' + NS, function () {
                    wrapper.off(MOUSEMOVE + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td', mouseMoveHandler);
                });
                wrapper.on('focus' + NS, function () {
                    if (!that._selection && !that._userTouched) {
                        that._selectFirstSlot();
                    }
                    that._select();
                });
                wrapper.on('focusout' + NS, function (e) {
                    that._ctrlKey = that._shiftKey = false;
                    that.toolbar.find('ul > li').removeClass(FOCUSEDSTATE);
                    if (!$(e.relatedTarget).closest(VIEWSSELECTOR).length) {
                        that.toolbar.find(VIEWSSELECTOR).removeClass(EXPANDEDSTATE);
                    }
                });
                wrapper.on('keydown' + NS, proxy(that._keydown, that));
                wrapper.on('keyup' + NS, function (e) {
                    that._ctrlKey = e.ctrlKey;
                    that._shiftKey = e.shiftKey;
                });
            },
            _mouseDownSelection: function (e) {
                var which = e.which;
                var button = e.button;
                var isRight = which && which === 3 || button && button == 2;
                if (!isRight) {
                    if (e.ctrlKey) {
                        this._ctrlKey = e.ctrlKey;
                    }
                    if (e.shiftKey) {
                        this._shiftKey = e.shiftKey;
                    }
                    this._createSelection(e.currentTarget);
                }
                if (kendo._activeElement() !== this.wrapper.get(0)) {
                    kendo.focusElement(this.wrapper);
                } else {
                    this._select();
                }
                this.toolbar.find('ul > li').removeClass(FOCUSEDSTATE);
            },
            _selectFirstSlot: function () {
                this._createSelection(this.wrapper.find('.k-scheduler-content').find('td:first'));
            },
            _select: function () {
                var that = this;
                var view = that.view();
                var wrapper = that.wrapper;
                var current = view.current();
                var selection = that._selection;
                var oldSelection = that._old ? that._old.selection : null;
                var oldEventsLength = that._old ? that._old.eventsLength : null;
                if (!selection) {
                    return;
                }
                if (current) {
                    current.removeAttribute('id');
                    current.removeAttribute('aria-label');
                    wrapper.removeAttr('aria-activedescendant');
                }
                view.select(selection);
                current = view.current();
                if (current && (oldSelection !== current || selection.events && oldEventsLength !== selection.events.length)) {
                    var currentUid = $(current).data('uid');
                    if (that._old && currentUid && currentUid === $(that._old.selection).data('uid') && (selection.events && that._old.eventsLength === selection.events.length)) {
                        return;
                    }
                    var labelFormat;
                    var data = selection;
                    var events = that._selectedEvents();
                    var slots = view._selectedSlots;
                    if (events[0]) {
                        data = events[0] || selection;
                        labelFormat = kendo.format(that.options.messages.ariaEventLabel, data.title, data.start, data.start);
                    } else {
                        labelFormat = kendo.format(that.options.messages.ariaSlotLabel, data.start, data.end);
                    }
                    current.setAttribute('id', that._ariaId);
                    current.setAttribute('aria-label', labelFormat);
                    wrapper.attr('aria-activedescendant', that._ariaId);
                    that._old = {
                        selection: current,
                        eventsLength: events.length
                    };
                    that.trigger('change', {
                        start: selection.start,
                        end: selection.end,
                        events: events,
                        slots: slots,
                        resources: view._resourceBySlot(selection)
                    });
                }
            },
            _selectedEvents: function () {
                var uids = this._selection.events;
                var length = uids.length;
                var idx = 0;
                var event;
                var events = [];
                for (; idx < length; idx++) {
                    event = this.occurrenceByUid(uids[idx]);
                    if (event) {
                        events.push(event);
                    }
                }
                return events;
            },
            _tapPosition: function (event, coordinate) {
                return /touch/.test(event.type) ? (event.originalEvent || event).changedTouches[0]['page' + coordinate] : event['page' + coordinate];
            },
            _touchMove: function (e) {
                var that = this;
                var content = that.wrapper.find('.k-scheduler-content');
                var verticalScroll = content[0].scrollHeight > content[0].clientHeight;
                var horizontalScroll = content[0].scrollWidth > content[0].clientWidth;
                var endY = that._tapPosition(e, 'Y');
                var endX = that._tapPosition(e, 'X');
                var scrollTop = content[0].scrollTop - Math.round(endY - that._touchPosY);
                var scrollLeft = content[0].scrollLeft - Math.round(endX - that._touchPosX);
                var applyVerticalScroll = verticalScroll && Math.abs(endY - that._touchPosY) > 10;
                var applyhorizontalScroll = horizontalScroll && Math.abs(endY - that._touchPosY) > 10;
                if (that._dragging || kendo.support.kineticScrollNeeded || !that._isTouch(e)) {
                    return;
                }
                if (applyVerticalScroll || applyhorizontalScroll) {
                    that._amplitude = Math.round(endY - that._touchPosY);
                    that._touchPosY = endY;
                    that._touchPosX = endX;
                    content.animate({
                        scrollTop: scrollTop,
                        scrollLeft: scrollLeft
                    }, 0);
                    that.view()._scrolling = true;
                }
            },
            _mouseMove: function (e) {
                var that = this;
                clearTimeout(that._moveTimer);
                if (that._isTouch(e)) {
                    return;
                }
                that._moveTimer = setTimeout(function () {
                    var view = that.view();
                    var selection = that._selection;
                    if (selection) {
                        var slot = view.selectionByElement($(e.currentTarget));
                        if (slot && selection.groupIndex === slot.groupIndex) {
                            var startDate = slot.startDate();
                            var endDate = slot.endDate();
                            if (startDate >= selection.end) {
                                selection.backward = false;
                            } else if (endDate <= selection.start) {
                                selection.backward = true;
                            }
                            if (selection.backward) {
                                selection.start = startDate;
                            } else {
                                selection.end = endDate;
                            }
                            that._select();
                        }
                    }
                }, 5);
            },
            _viewByIndex: function (index) {
                var view, views = this.views;
                for (view in views) {
                    if (!index) {
                        return view;
                    }
                    index--;
                }
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, view = that.view(), editable = view.options.editable, selection = that._selection, prevSelection = $.extend(selection), isModifier = key === 16 || key === 18 || key === 17 || key === 91 || key === 92, focusableToolBarSelector = '.k-scheduler-tools > li,' + '.k-scheduler-navigation > li,' + '.k-scheduler-views > li.k-state-selected:visible, ' + '.k-scheduler-views > li.k-current-view:visible', focusableItems = that.toolbar.find(focusableToolBarSelector), viewsWrapper = that.toolbar.find(VIEWSSELECTOR), shouldNavigate = $(e.target).closest(VIEWSSELECTOR).length || that.toolbar.find('.k-scheduler-views .k-state-focused').length, focusedViewIndex = viewsWrapper.children().index(that.toolbar.find('.' + FOCUSEDSTATE)), selectedIndex, isRtl = kendo.support.isRtl(that.element), direction = isRtl ? -1 : 1;
                if (focusedViewIndex == -1) {
                    focusedViewIndex = viewsWrapper.children().index(that.toolbar.find('.k-state-selected'));
                }
                that._ctrlKey = e.ctrlKey;
                that._shiftKey = e.shiftKey;
                if (key === keys.F10) {
                    that.toolbar.find('ul > li:first').focus().addClass(FOCUSEDSTATE);
                    e.preventDefault();
                    return;
                } else if (key === keys.TAB) {
                    if (that.toolbar.find('.' + FOCUSEDSTATE).length) {
                        var idx = focusableItems.index(that.toolbar.find('.' + FOCUSEDSTATE));
                        if (idx === -1 && that._focusedView) {
                            idx = focusableItems.index(that.toolbar.find('.k-scheduler-views > .k-state-selected'));
                        }
                        var itemToFocus = e.shiftKey ? focusableItems[idx - 1] : focusableItems[idx + 1];
                        that.toolbar.find('.' + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
                        if (itemToFocus) {
                            $(itemToFocus).addClass(FOCUSEDSTATE).focus();
                            that._focusedView = null;
                            e.preventDefault();
                            return;
                        } else {
                            that.element.focus();
                            e.preventDefault();
                            return;
                        }
                    }
                } else if (key === keys.ENTER || key === keys.SPACEBAR) {
                    if (shouldNavigate && that._focusedView && !that._focusedView.hasClass('k-state-selected')) {
                        var focusedViewName = that._focusedView.data().name;
                        if (!that.trigger('navigate', {
                                view: focusedViewName,
                                action: 'changeView',
                                date: that.date()
                            })) {
                            that.view(focusedViewName);
                            viewsWrapper.removeClass(EXPANDEDSTATE);
                            if (that.toolbar.find('.k-current-view:visible').length) {
                                $(document.activeElement).blur();
                                that.toolbar.find('.k-current-view:visible').addClass(FOCUSEDSTATE).find('.k-link').focus();
                            }
                        }
                        e.preventDefault();
                        return;
                    }
                    if (that.toolbar.find('.' + FOCUSEDSTATE + ':visible').length) {
                        that.toolbar.find('.' + FOCUSEDSTATE + ':visible').click();
                        e.preventDefault();
                        return;
                    }
                } else if (e.altKey && key === keys.DOWN) {
                    if (that.toolbar.find('.' + FOCUSEDSTATE + ':visible').length) {
                        that.toolbar.find('.' + FOCUSEDSTATE + ':visible').click();
                        e.preventDefault();
                        return;
                    }
                } else if (key === keys.RIGHT && shouldNavigate) {
                    $(that.toolbar.find('.' + FOCUSEDSTATE)).removeClass(FOCUSEDSTATE);
                    if (isRtl) {
                        that._focusedView = focusedViewIndex - 1 === 0 ? $(viewsWrapper.children(':not(.k-current-view):last')) : $(viewsWrapper.children()[focusedViewIndex + 1 * direction]);
                    } else {
                        that._focusedView = focusedViewIndex + 1 === viewsWrapper.children().length ? $(viewsWrapper.children(':not(.k-current-view):first')) : $(viewsWrapper.children()[focusedViewIndex + 1 * direction]);
                    }
                    that._focusedView.focus().addClass(FOCUSEDSTATE);
                    e.preventDefault();
                    return;
                } else if (key === keys.LEFT && shouldNavigate) {
                    $(that.toolbar.find('.' + FOCUSEDSTATE)).removeClass(FOCUSEDSTATE);
                    if (isRtl) {
                        that._focusedView = focusedViewIndex + 1 === viewsWrapper.children().length ? $(viewsWrapper.children(':not(.k-current-view):first')) : $(viewsWrapper.children()[focusedViewIndex - 1 * direction]);
                    } else {
                        that._focusedView = focusedViewIndex - 1 === 0 ? $(viewsWrapper.children(':not(.k-current-view):last')) : $(viewsWrapper.children()[focusedViewIndex - 1 * direction]);
                    }
                    that._focusedView.focus().addClass(FOCUSEDSTATE);
                    e.preventDefault();
                    return;
                } else if (key === keys.DOWN && that.toolbar.find(VIEWSSELECTOR).hasClass(EXPANDEDSTATE)) {
                    that.toolbar.find('.' + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
                    if (that._focusedView) {
                        selectedIndex = viewsWrapper.find(that._focusedView).index();
                    } else {
                        selectedIndex = viewsWrapper.children('.k-scheduler-views > .k-state-selected').index();
                    }
                    that._focusedView = selectedIndex + 1 === viewsWrapper.children().length ? $(viewsWrapper.children(':not(.k-current-view):first')) : $(viewsWrapper.children()[selectedIndex + 1 * direction]);
                    that._focusedView.focus().addClass(FOCUSEDSTATE);
                    e.preventDefault();
                    return;
                } else if (key === keys.UP && that.toolbar.find(VIEWSSELECTOR).hasClass(EXPANDEDSTATE)) {
                    that.toolbar.find('.' + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
                    if (that._focusedView) {
                        selectedIndex = viewsWrapper.find(that._focusedView).index();
                    } else {
                        selectedIndex = viewsWrapper.children('.k-scheduler-views > .k-state-selected').index();
                    }
                    that._focusedView = selectedIndex - 1 === 0 ? $(viewsWrapper.children(':not(.k-current-view):last')) : $(viewsWrapper.children()[selectedIndex - 1 * direction]);
                    that._focusedView.focus().addClass(FOCUSEDSTATE);
                    e.preventDefault();
                    return;
                } else if (e.altKey && key === keys.DOWN && that.toolbar.find('.k-nav-current').hasClass(FOCUSEDSTATE)) {
                    that._showCalendar();
                    e.preventDefault();
                    return;
                } else if (key === keys.ESC && that.popup && that.popup.visible()) {
                    that.popup.close();
                    e.preventDefault();
                    return;
                } else if (key === keys.ESC && that.toolbar.find(VIEWSSELECTOR).hasClass(EXPANDEDSTATE)) {
                    that.toolbar.find(VIEWSSELECTOR).removeClass(EXPANDEDSTATE);
                    that.toolbar.find(VIEWSSELECTOR).children().removeClass(FOCUSEDSTATE);
                    that._focusedView = null;
                    that.toolbar.find('.k-current-view').focus().addClass(FOCUSEDSTATE);
                    e.preventDefault();
                    return;
                }
                if (isModifier) {
                    return;
                }
                if (!selection) {
                    that._selectFirstSlot();
                    that._select();
                    that.element.focus();
                    return;
                }
                if (key === keys.TAB) {
                    if (view.moveToEvent(selection, e.shiftKey)) {
                        that._select();
                        that.element.focus();
                        e.preventDefault();
                    }
                } else if (key === keys.ENTER || key === keys.SPACEBAR) {
                    if (selection.events.length && editable) {
                        if (editable.update !== false) {
                            that.editEvent(selection.events[0]);
                        }
                    } else if (editable && editable.create !== false) {
                        if (selection.isAllDay) {
                            selection = $.extend({}, selection, { end: kendo.date.addDays(selection.end, -1) });
                        }
                        e.preventDefault();
                        that.addEvent(extend({}, selection, view._resourceBySlot(selection)));
                    }
                } else if (key === keys.DELETE && editable !== false && editable.destroy !== false) {
                    that.removeEvent(selection.events[0]);
                } else if (key >= 49 && key <= 57) {
                    var viewByIndex = that._viewByIndex(key - 49);
                    if (viewByIndex && !that.trigger('navigate', {
                            view: viewByIndex,
                            action: 'changeView',
                            date: that.date()
                        })) {
                        that.view(viewByIndex);
                    }
                } else if (view.move(selection, key, e.shiftKey)) {
                    if (view.inRange(selection)) {
                        that._select();
                    } else {
                        var action = that.date().getTime() > selection.start.getTime() ? 'previous' : 'next';
                        if (!that.trigger('navigate', {
                                view: that._selectedViewName,
                                action: action,
                                date: selection.start
                            })) {
                            that.date(selection.start);
                        } else {
                            selection.start = prevSelection.start;
                            selection.end = prevSelection.end;
                        }
                    }
                    that.toolbar.find('ul > li').removeClass(FOCUSEDSTATE);
                    e.preventDefault();
                }
                that._adjustSelectedDate();
            },
            _createSelection: function (item) {
                var selection = this._selection;
                var uid;
                var slot;
                item = $(item);
                if (item.is('.k-event')) {
                    uid = item.attr(kendo.attr('uid'));
                    if (selection && selection.events.indexOf(uid) !== -1 && !this._ctrlKey) {
                        return;
                    }
                }
                if (!selection || !this._ctrlKey && !this._shiftKey) {
                    selection = this._selection = {
                        events: [],
                        groupIndex: 0
                    };
                }
                slot = this.view().selectionByElement(item);
                if (slot) {
                    selection.groupIndex = slot.groupIndex || 0;
                }
                if (uid) {
                    slot = getOccurrenceByUid(this._data, uid);
                }
                if (slot && slot.uid) {
                    uid = [slot.uid];
                }
                this._updateSelection(slot, uid);
                this._adjustSelectedDate();
            },
            _updateSelection: function (dataItem, events, groupIndex) {
                var selection = this._selection;
                if (dataItem && selection) {
                    var view = this.view();
                    if (dataItem.uid) {
                        dataItem = view._updateEventForSelection(dataItem);
                    }
                    if (this._shiftKey && selection.start && selection.end) {
                        var backward = dataItem.end < selection.end;
                        selection.end = dataItem.endDate ? dataItem.endDate() : dataItem.end;
                        if (backward && view._timeSlotInterval) {
                            kendo.date.setTime(selection.end, -view._timeSlotInterval());
                        }
                    } else {
                        selection.start = dataItem.startDate ? dataItem.startDate() : dataItem.start;
                        selection.end = dataItem.endDate ? dataItem.endDate() : dataItem.end;
                    }
                    if ('isDaySlot' in dataItem) {
                        selection.isAllDay = dataItem.isDaySlot;
                    } else {
                        selection.isAllDay = dataItem.isAllDay;
                    }
                    if (groupIndex !== null && groupIndex !== undefined) {
                        selection.groupIndex = groupIndex;
                    }
                    selection.index = dataItem.index;
                    if (this._ctrlKey) {
                        var indexOfEvent = events && events.length ? selection.events.indexOf(events[0]) : -1;
                        if (indexOfEvent > -1) {
                            selection.events.splice(indexOfEvent, 1);
                        } else {
                            selection.events = selection.events.concat(events || []);
                        }
                    } else {
                        selection.events = events || [];
                    }
                }
            },
            options: {
                name: 'Scheduler',
                date: TODAY,
                editable: true,
                autoBind: true,
                snap: true,
                mobile: false,
                timezone: '',
                allDaySlot: true,
                min: new Date(1900, 0, 1),
                max: new Date(2099, 11, 31),
                toolbar: null,
                workWeekStart: 1,
                workWeekEnd: 5,
                showWorkHours: false,
                startTime: TODAY,
                endTime: TODAY,
                currentTimeMarker: {
                    updateInterval: 10000,
                    useLocalTimezone: true
                },
                footer: {},
                messages: {
                    today: 'Today',
                    pdf: 'Export to PDF',
                    save: 'Save',
                    cancel: 'Cancel',
                    destroy: 'Delete',
                    resetSeries: 'Reset Series',
                    deleteWindowTitle: 'Delete event',
                    next: 'Next',
                    previous: 'Previous',
                    ariaSlotLabel: 'Selected from {0:t} to {1:t}',
                    ariaEventLabel: '{0} on {1:D} at {2:t}',
                    views: {
                        day: 'Day',
                        week: 'Week',
                        workWeek: 'Work Week',
                        agenda: 'Agenda',
                        month: 'Month',
                        timeline: 'Timeline',
                        timelineWeek: 'Timeline Week',
                        timelineWorkWeek: 'Timeline Work Week',
                        timelineMonth: 'Timeline Month'
                    },
                    recurrenceMessages: {
                        deleteWindowTitle: 'Delete Recurring Item',
                        resetSeriesWindowTitle: 'Reset Series',
                        deleteWindowOccurrence: 'Delete current occurrence',
                        deleteWindowSeries: 'Delete the series',
                        editWindowTitle: 'Edit Recurring Item',
                        editWindowOccurrence: 'Edit current occurrence',
                        editWindowSeries: 'Edit the series'
                    },
                    editable: { confirmation: DELETECONFIRM },
                    editor: {
                        title: 'Title',
                        start: 'Start',
                        end: 'End',
                        allDayEvent: 'All day event',
                        description: 'Description',
                        repeat: 'Repeat',
                        timezone: 'Timezone',
                        startTimezone: 'Start timezone',
                        endTimezone: 'End timezone',
                        separateTimezones: 'Use separate start and end time zones',
                        timezoneEditorTitle: 'Timezones',
                        timezoneEditorButton: 'Time zone',
                        timezoneTitle: 'Time zones',
                        noTimezone: 'No timezone',
                        editorTitle: 'Event'
                    }
                },
                height: null,
                width: null,
                resources: [],
                group: {
                    resources: [],
                    orientation: 'horizontal'
                },
                views: [],
                selectable: false
            },
            events: [
                REMOVE,
                EDIT,
                CANCEL,
                SAVE,
                'add',
                'dataBinding',
                'dataBound',
                'moveStart',
                'move',
                'moveEnd',
                'resizeStart',
                'resize',
                'resizeEnd',
                'navigate',
                'change'
            ],
            destroy: function () {
                var that = this, element;
                Widget.fn.destroy.call(that);
                if (that.dataSource) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                    that.dataSource.unbind(PROGRESS, that._progressHandler);
                    that.dataSource.unbind(ERROR, that._errorHandler);
                }
                if (that._resourceRefreshHandler) {
                    for (var idx = 0; idx < that.resources.length; idx++) {
                        var resourceDS = that.resources[idx].dataSource;
                        resourceDS.unbind(CHANGE, that._resourceRefreshHandler);
                        resourceDS.unbind(PROGRESS, that._resourceProgressHandler);
                        resourceDS.unbind(ERROR, that._resourceErrorHandler);
                    }
                }
                if (that.calendar) {
                    that.calendar.destroy();
                    that.popup.destroy();
                }
                if (that.view()) {
                    that.view().destroy();
                }
                if (that._editor) {
                    that._editor.destroy();
                }
                if (this._moveDraggable) {
                    this._moveDraggable.destroy();
                }
                if (this._resizeDraggable) {
                    this._resizeDraggable.destroy();
                }
                element = that.element.add(that.wrapper).add(that.toolbar).add(that.popup);
                element.off(NS);
                clearTimeout(that._moveTimer);
                that._model = null;
                that.toolbar = null;
                that.element = null;
                $(window).off('resize' + NS, that._resizeHandler);
                kendo.destroy(that.wrapper);
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                if (this.options.autoBind && dataSource.fetch) {
                    dataSource.fetch();
                } else if (isArray(dataSource)) {
                    this.view(this._selectedView);
                }
            },
            items: function () {
                var content = this.wrapper.find('.k-scheduler-content');
                var view = this.view();
                if (view && view.options.name === 'agenda') {
                    return content.find('.k-task');
                } else {
                    return content.find('.k-event').add(this.wrapper.find('.k-scheduler-header-wrap').find('.k-scheduler-header-all-day').siblings());
                }
            },
            _movable: function () {
                var startSlot;
                var endSlot;
                var startResources;
                var startTime;
                var endTime;
                var event;
                var clonedEvent;
                var that = this;
                var originSlot;
                var originStartTime;
                var originalEvent;
                var distance = 0;
                var clonedEvents = [];
                var cachedEvents = [];
                var isMobile = that._isMobile();
                var movable = that.options.editable && that.options.editable.move !== false;
                var resizable = that.options.editable && that.options.editable.resize !== false;
                if (movable || resizable && isMobile) {
                    that._dragging = false;
                    if (isMobile && kendo.support.mobileOS.android) {
                        distance = 5;
                    }
                    that._moveDraggable = new kendo.ui.Draggable(that.element, {
                        distance: distance,
                        filter: '.k-event',
                        ignore: '.k-resize-handle',
                        holdToDrag: isMobile,
                        autoScroll: true
                    });
                    if (movable) {
                        that._moveDraggable.bind('dragstart', function (e) {
                            var view = that.view();
                            var eventElement = e.currentTarget;
                            var isTouch = that._isTouch(e);
                            that._dragging = true;
                            if (!view.options.editable || view.options.editable.move === false) {
                                that._dragging = false;
                                e.preventDefault();
                                return;
                            }
                            if (isTouch && !eventElement.hasClass('k-event-active')) {
                                that._dragging = false;
                                that.element.find('.k-event-active').removeClass('k-event-active');
                                e.preventDefault();
                                return;
                            }
                            event = that.occurrenceByUid(eventElement.attr(kendo.attr('uid')));
                            clonedEvent = event.clone();
                            originalEvent = event.clone();
                            clonedEvent.update(view._eventOptionsForMove(clonedEvent));
                            clonedEvent.inverseColor = that._isInverseColor(eventElement);
                            clonedEvents = [];
                            if (that._selection) {
                                var events = that._selection.events;
                                for (var i = 0; i < events.length; i++) {
                                    var evtClone = that.occurrenceByUid(events[i]).clone();
                                    var evtCloneElement = this.element.find('div.k-event[data-uid="' + evtClone.uid + '"]').eq(0);
                                    evtClone.update(view._eventOptionsForMove(evtClone));
                                    if (evtCloneElement.length) {
                                        evtClone.inverseColor = that._isInverseColor(evtCloneElement);
                                    }
                                    clonedEvents.push(evtClone);
                                }
                            } else {
                                clonedEvents.push(clonedEvent);
                            }
                            startSlot = view._slotByPosition(e.x.startLocation, e.y.startLocation);
                            startResources = view._resourceBySlot(startSlot);
                            originStartTime = startTime = startSlot.startOffset(e.x.startLocation, e.y.startLocation, that.options.snap);
                            endSlot = startSlot;
                            originSlot = startSlot;
                            if (!startSlot || that.trigger('moveStart', { event: event })) {
                                e.preventDefault();
                            }
                        }).bind('drag', function (e) {
                            var view = that.view();
                            var slot = view._slotByPosition(e.x.location, e.y.location);
                            var distance;
                            var range;
                            var i;
                            if (!slot) {
                                return;
                            }
                            endTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                            if (slot.isDaySlot !== startSlot.isDaySlot) {
                                if (slot.isDaySlot !== originSlot.isDaySlot) {
                                    var slotIndex = $(startSlot.element).index();
                                    var targetSlotElement = $(slot.element).parent().children().eq(slotIndex);
                                    startSlot = view._slotByPosition(targetSlotElement.offset().left, targetSlotElement.offset().top);
                                    startTime = startSlot.startOffset(e.x.location, e.y.location, true);
                                    cachedEvents = clonedEvents.map(function (event) {
                                        return event.clone();
                                    });
                                    for (i = 0; i < clonedEvents.length; i++) {
                                        if (clonedEvents[i].isAllDay != slot.isDaySlot) {
                                            clonedEvents[i].isAllDay = slot.isDaySlot;
                                            clonedEvents[i].end = kendo.date.getDate(clonedEvents[i].start);
                                            clonedEvents[i].start = kendo.date.getDate(clonedEvents[i].start);
                                            if (!slot.isDaySlot) {
                                                kendo.date.setTime(clonedEvents[i].start, kendo.date.getMilliseconds(view.startTime()));
                                                kendo.date.setTime(clonedEvents[i].end, kendo.date.getMilliseconds(view.startTime()) + view._timeSlotInterval());
                                            }
                                        }
                                    }
                                } else {
                                    startSlot = $.extend(true, {}, originSlot);
                                    startTime = originStartTime;
                                    clonedEvents = cachedEvents;
                                }
                            }
                            distance = endTime - startTime;
                            for (i = 0; i < clonedEvents.length; i++) {
                                view._updateMoveHint(clonedEvents[i], slot.groupIndex, distance);
                            }
                            range = moveEventRange(clonedEvent, distance);
                            if (!that.trigger('move', {
                                    event: event,
                                    slot: {
                                        element: slot.element,
                                        start: slot.startDate(),
                                        end: slot.endDate(),
                                        isDaySlot: slot.isDaySlot
                                    },
                                    resources: view._resourceBySlot(slot),
                                    start: range.start,
                                    end: range.end
                                })) {
                                endSlot = slot;
                            } else {
                                for (i = 0; i < clonedEvents.length; i++) {
                                    view._updateMoveHint(clonedEvents[i], slot.groupIndex, distance);
                                }
                            }
                        }).bind('dragend', function (e) {
                            that.view()._removeMoveHint();
                            var distance = endTime - startTime;
                            var range = moveEventRange(clonedEvent, distance);
                            var start = range.start;
                            var end = range.end;
                            that._dragging = false;
                            var endResources = that.view()._resourceBySlot(endSlot);
                            var prevented = that.trigger('moveEnd', {
                                event: event,
                                slot: {
                                    element: endSlot.element,
                                    start: endSlot.startDate(),
                                    end: endSlot.endDate()
                                },
                                start: start,
                                end: end,
                                resources: endResources
                            });
                            if (!prevented && (event.start.getTime() !== start.getTime() || event.end.getTime() !== end.getTime() || originSlot.isDaySlot !== endSlot.isDaySlot || kendo.stringify(endResources) !== kendo.stringify(startResources))) {
                                that._isMultiDrag = clonedEvents.length > 1;
                                for (var i = 0; i < clonedEvents.length; i++) {
                                    var evt = clonedEvents[i];
                                    range = moveEventRange(evt, distance);
                                    var updatedEventOptions = that.view()._eventOptionsForMove(evt);
                                    var eventOptions = $.extend({
                                        isAllDay: evt.isAllDay,
                                        start: range.start,
                                        end: range.end
                                    }, updatedEventOptions, endResources);
                                    that._updateEvent(null, evt, eventOptions);
                                }
                                if (that._isMultiDrag) {
                                    that.dataSource.sync();
                                    that._isMultiDrag = false;
                                }
                            }
                            e.currentTarget.removeClass('k-event-active');
                            this.cancelHold();
                            clonedEvents = [];
                            cachedEvents = [];
                        }).bind('dragcancel', function () {
                            that.view()._removeMoveHint();
                            this.cancelHold();
                            clonedEvents = [];
                            cachedEvents = [];
                        });
                    }
                    that._moveDraggable.bind('hold', function (e) {
                        if (that._isTouch(e)) {
                            that.element.find('.k-event-active').removeClass('k-event-active');
                            if (that.options.selectable) {
                                that._createSelection(e.currentTarget);
                            }
                            e.currentTarget.addClass('k-event-active');
                        }
                    });
                }
            },
            _resizable: function () {
                var startTime;
                var endTime;
                var event;
                var clonedEvent;
                var slot;
                var that = this;
                var distance = 0;
                function direction(handle) {
                    var directions = {
                        'k-resize-e': 'east',
                        'k-resize-w': 'west',
                        'k-resize-n': 'north',
                        'k-resize-s': 'south'
                    };
                    for (var key in directions) {
                        if (handle.hasClass(key)) {
                            return directions[key];
                        }
                    }
                }
                if (that._isMobile() && kendo.support.mobileOS.android) {
                    distance = 5;
                }
                that._resizeDraggable = new kendo.ui.Draggable(that.element, {
                    distance: distance,
                    filter: '.k-resize-handle',
                    autoScroll: true,
                    dragstart: function (e) {
                        var dragHandle = $(e.currentTarget);
                        var eventElement = dragHandle.closest('.k-event');
                        var uid = eventElement.attr(kendo.attr('uid'));
                        var view = that.view();
                        that._dragging = true;
                        event = that.occurrenceByUid(uid);
                        clonedEvent = event.clone();
                        view._updateEventForResize(clonedEvent);
                        slot = view._slotByPosition(e.x.startLocation, e.y.startLocation);
                        if (that.trigger('resizeStart', { event: event })) {
                            e.preventDefault();
                        }
                        startTime = kendo.date.toUtcTime(clonedEvent.start);
                        endTime = kendo.date.toUtcTime(clonedEvent.end);
                    },
                    drag: function (e) {
                        if (!slot) {
                            return;
                        }
                        var dragHandle = $(e.currentTarget);
                        var dir = direction(dragHandle);
                        var view = that.view();
                        var currentSlot = view._slotByPosition(e.x.location, e.y.location);
                        if (!currentSlot || slot.groupIndex != currentSlot.groupIndex) {
                            return;
                        }
                        slot = currentSlot;
                        var originalStart = startTime;
                        var originalEnd = endTime;
                        if (dir == 'south') {
                            if (!slot.isDaySlot && slot.end - kendo.date.toUtcTime(clonedEvent.start) >= view._timeSlotInterval()) {
                                if (clonedEvent.isAllDay) {
                                    endTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                                } else {
                                    endTime = slot.endOffset(e.x.location, e.y.location, that.options.snap);
                                }
                            }
                        } else if (dir == 'north') {
                            if (!slot.isDaySlot && kendo.date.toUtcTime(clonedEvent.end) - slot.start >= view._timeSlotInterval()) {
                                startTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                            }
                        } else if (dir == 'east') {
                            if (slot.isDaySlot && kendo.date.toUtcTime(kendo.date.getDate(slot.endDate())) >= kendo.date.toUtcTime(kendo.date.getDate(clonedEvent.start))) {
                                if (clonedEvent.isAllDay) {
                                    endTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                                } else {
                                    endTime = slot.endOffset(e.x.location, e.y.location, that.options.snap);
                                }
                            } else if (!slot.isDaySlot && slot.end - kendo.date.toUtcTime(clonedEvent.start) >= view._timeSlotInterval()) {
                                endTime = slot.endOffset(e.x.location, e.y.location, that.options.snap);
                            }
                        } else if (dir == 'west') {
                            if (slot.isDaySlot && kendo.date.toUtcTime(kendo.date.getDate(clonedEvent.end)) >= kendo.date.toUtcTime(kendo.date.getDate(slot.startDate()))) {
                                startTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                            } else if (!slot.isDaySlot && kendo.date.toUtcTime(clonedEvent.end) - slot.start >= view._timeSlotInterval()) {
                                startTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                            }
                        }
                        if (!that.trigger('resize', {
                                event: event,
                                slot: {
                                    element: slot.element,
                                    start: slot.startDate(),
                                    end: slot.endDate()
                                },
                                start: kendo.timezone.toLocalDate(startTime),
                                end: kendo.timezone.toLocalDate(endTime),
                                resources: view._resourceBySlot(slot)
                            })) {
                            view._updateResizeHint(clonedEvent, slot.groupIndex, startTime, endTime);
                        } else {
                            startTime = originalStart;
                            endTime = originalEnd;
                        }
                    },
                    dragend: function (e) {
                        var dragHandle = $(e.currentTarget);
                        var start = new Date(clonedEvent.start.getTime());
                        var end = new Date(clonedEvent.end.getTime());
                        var dir = direction(dragHandle);
                        that._dragging = false;
                        that.view()._removeResizeHint();
                        if (dir == 'south') {
                            end = kendo.timezone.toLocalDate(endTime);
                        } else if (dir == 'north') {
                            start = kendo.timezone.toLocalDate(startTime);
                        } else if (dir == 'east') {
                            if (slot.isDaySlot) {
                                end = kendo.date.getDate(kendo.timezone.toLocalDate(endTime));
                            } else {
                                end = kendo.timezone.toLocalDate(endTime);
                            }
                        } else if (dir == 'west') {
                            if (slot.isDaySlot) {
                                start = new Date(kendo.timezone.toLocalDate(startTime));
                                start.setHours(0);
                                start.setMinutes(0);
                            } else {
                                start = kendo.timezone.toLocalDate(startTime);
                            }
                        }
                        var prevented = that.trigger('resizeEnd', {
                            event: event,
                            slot: {
                                element: slot.element,
                                start: slot.startDate(),
                                end: slot.endDate()
                            },
                            start: start,
                            end: end,
                            resources: that.view()._resourceBySlot(slot)
                        });
                        if (!prevented && end.getTime() >= start.getTime()) {
                            if (clonedEvent.start.getTime() != start.getTime() || clonedEvent.end.getTime() != end.getTime()) {
                                that.view()._updateEventForResize(event);
                                that._updateEvent(dir, event, {
                                    start: start,
                                    end: end
                                });
                            }
                        }
                        slot = null;
                        event = null;
                    },
                    dragcancel: function () {
                        that._dragging = false;
                        that.view()._removeResizeHint();
                        slot = null;
                        event = null;
                    }
                });
            },
            _updateEvent: function (dir, event, eventInfo) {
                var that = this;
                var updateEvent = function (event, callback) {
                    try {
                        that._preventRefresh = true;
                        event.update(eventInfo);
                        that._convertDates(event);
                    } finally {
                        that._preventRefresh = false;
                    }
                    if (!that.trigger(SAVE, { event: event })) {
                        if (callback) {
                            callback();
                        }
                        if (!that._isMultiDrag) {
                            that.dataSource.sync();
                        }
                    }
                };
                var recurrenceHead = function (event) {
                    if (event.recurrenceRule) {
                        return that.dataSource.getByUid(event.uid);
                    } else {
                        return that.dataSource.get(event.recurrenceId);
                    }
                };
                var updateSeries = function () {
                    var head = recurrenceHead(event);
                    if (dir == 'south' || dir == 'north') {
                        if (eventInfo.start) {
                            var start = kendo.date.getDate(head.start);
                            kendo.date.setTime(start, getMilliseconds(eventInfo.start));
                            eventInfo.start = start;
                        }
                        if (eventInfo.end) {
                            var end = kendo.date.getDate(head.end);
                            kendo.date.setTime(end, getMilliseconds(eventInfo.end));
                            eventInfo.end = end;
                        }
                    }
                    that.dataSource._removeExceptions(head);
                    updateEvent(head);
                };
                var updateOccurrence = function () {
                    var head = recurrenceHead(event);
                    var eventUid;
                    var callback = function () {
                        that._convertDates(head);
                        if (that._selection) {
                            that._selection.events.push(eventUid);
                        }
                    };
                    var exception = head.toOccurrence({
                        start: event.start,
                        end: event.end
                    });
                    eventUid = exception.uid;
                    updateEvent(that.dataSource.add(exception), callback);
                };
                if (event.recurrenceRule || event.isOccurrence()) {
                    var recurrenceMessages = that.options.messages.recurrenceMessages;
                    that._showRecurringDialog(event, updateOccurrence, updateSeries, {
                        title: recurrenceMessages.editWindowTitle,
                        text: recurrenceMessages.editRecurring ? recurrenceMessages.editRecurring : EDITRECURRING,
                        occurrenceText: recurrenceMessages.editWindowOccurrence,
                        seriesText: recurrenceMessages.editWindowSeries
                    });
                } else {
                    updateEvent(that.dataSource.getByUid(event.uid));
                }
            },
            _modelForContainer: function (container) {
                container = $(container).closest('[' + kendo.attr('uid') + ']');
                return this.dataSource.getByUid(container.attr(kendo.attr('uid')));
            },
            showDialog: function (options) {
                this._editor.showDialog(options);
            },
            focus: function () {
                this.wrapper.focus();
            },
            _confirmation: function (callback, model, isResetSeries) {
                var editable = this.options.editable;
                if (editable === true || editable.confirmation !== false) {
                    var messages = this.options.messages;
                    var title = messages.deleteWindowTitle;
                    var text = typeof editable.confirmation === STRING ? editable.confirmation : messages.editable.confirmation;
                    if (this._isEditorOpened() && model.isRecurring()) {
                        var recurrenceMessages = this.options.messages.recurrenceMessages;
                        title = recurrenceMessages.deleteWindowTitle;
                        if (model.isException()) {
                            text = recurrenceMessages.deleteRecurringConfirmation ? recurrenceMessages.deleteRecurringConfirmation : DELETERECURRINGCONFIRM;
                        } else {
                            text = recurrenceMessages.deleteSeriesConfirmation ? recurrenceMessages.deleteSeriesConfirmation : DELETESERIESCONFIRM;
                        }
                        if (isResetSeries) {
                            title = recurrenceMessages.resetSeriesWindowTitle;
                            text = recurrenceMessages.resetSeriesConfirmation ? recurrenceMessages.resetSeriesConfirmation : RESETSERIESCONFIRM;
                        }
                    }
                    var buttons = [{
                            name: 'destroy',
                            text: isResetSeries ? messages.resetSeries : messages.destroy,
                            click: function () {
                                callback();
                            }
                        }];
                    if (!(this._isMobile() && kendo.Pane)) {
                        buttons.push({
                            name: 'canceledit',
                            text: messages.cancel,
                            click: function () {
                                callback(true);
                            }
                        });
                    }
                    this._unbindResize();
                    this.showDialog({
                        model: model,
                        text: text,
                        title: title,
                        buttons: buttons
                    });
                    this._bindResize();
                } else {
                    callback();
                }
            },
            addEvent: function (eventInfo) {
                var editable = this._editor.editable;
                var dataSource = this.dataSource;
                var event;
                eventInfo = eventInfo || {};
                var prevented = this.trigger('add', { event: eventInfo });
                if (!prevented && (editable && editable.end() || !editable)) {
                    this.cancelEvent();
                    if (eventInfo && eventInfo.toJSON) {
                        eventInfo = eventInfo.toJSON();
                    }
                    event = dataSource.add(eventInfo);
                    if (event) {
                        this.cancelEvent();
                        this._editEvent(event);
                    }
                }
            },
            saveEvent: function () {
                var editor = this._editor;
                if (!editor) {
                    return;
                }
                var editable = editor.editable;
                var container = editor.container;
                var model = this._modelForContainer(container);
                if (container && editable && editable.end() && !this.trigger(SAVE, {
                        container: container,
                        event: model
                    })) {
                    if (!model.dirty && !model.isOccurrence()) {
                        this._convertDates(model, 'remove');
                    }
                    this.dataSource.sync();
                }
            },
            cancelEvent: function () {
                var editor = this._editor;
                var container = editor.container;
                var model;
                if (container) {
                    model = this._modelForContainer(container);
                    if (model && model.isOccurrence()) {
                        this._convertDates(model, 'remove');
                        this._convertDates(this.dataSource.get(model.recurrenceId), 'remove');
                    }
                    this.dataSource.cancelChanges(model);
                    editor.close();
                }
            },
            editEvent: function (uid) {
                var model = typeof uid == 'string' ? this.occurrenceByUid(uid) : uid;
                if (!model) {
                    return;
                }
                this.cancelEvent();
                if (model.isRecurring()) {
                    this._editRecurringDialog(model);
                } else {
                    this._editEvent(model);
                }
            },
            _editEvent: function (model) {
                this._preventRefresh = true;
                this._unbindResize();
                this._createPopupEditor(model);
                this._bindResize();
            },
            _editRecurringDialog: function (model) {
                var that = this;
                var editOccurrence = function () {
                    if (model.isException()) {
                        that._editEvent(model);
                    } else {
                        that.addEvent(model);
                    }
                };
                var editSeries = function () {
                    if (model.recurrenceId) {
                        model = that.dataSource.get(model.recurrenceId);
                    }
                    that._editEvent(model);
                };
                var recurrenceMessages = that.options.messages.recurrenceMessages;
                that._showRecurringDialog(model, editOccurrence, editSeries, {
                    title: recurrenceMessages.editWindowTitle,
                    text: recurrenceMessages.editRecurring ? recurrenceMessages.editRecurring : EDITRECURRING,
                    occurrenceText: recurrenceMessages.editWindowOccurrence,
                    seriesText: recurrenceMessages.editWindowSeries
                });
            },
            _showRecurringDialog: function (model, editOccurrence, editSeries, messages) {
                var editable = this.options.editable;
                var editRecurringMode = isPlainObject(editable) ? editable.editRecurringMode : 'dialog';
                if (editRecurringMode === 'occurrence' || this._isMultiDrag) {
                    editOccurrence();
                } else if (editRecurringMode === 'series') {
                    editSeries();
                } else {
                    this._unbindResize();
                    this.showDialog({
                        model: model,
                        title: messages.title,
                        text: messages.text,
                        buttons: [
                            {
                                text: messages.occurrenceText,
                                click: editOccurrence
                            },
                            {
                                text: messages.seriesText,
                                click: editSeries
                            }
                        ]
                    });
                    this._bindResize();
                }
            },
            _createButton: function (command) {
                var template = command.template || COMMANDBUTTONTMPL, commandName = typeof command === STRING ? command : command.name || command.text, options = {
                        className: 'k-scheduler-' + (commandName || '').replace(/\s/g, ''),
                        text: commandName,
                        attr: ''
                    };
                if (!commandName && !(isPlainObject(command) && command.template)) {
                    throw new Error('Custom commands should have name specified');
                }
                if (isPlainObject(command)) {
                    if (command.className) {
                        command.className += ' ' + options.className;
                    }
                    if (commandName === 'edit' && isPlainObject(command.text)) {
                        command = extend(true, {}, command);
                        command.text = command.text.edit;
                    }
                    options = extend(true, options, defaultCommands[commandName], command);
                } else {
                    options = extend(true, options, defaultCommands[commandName]);
                }
                return kendo.template(template)(options);
            },
            _convertDates: function (model, method) {
                var timezone = this.dataSource.reader.timezone;
                var startTimezone = model.startTimezone;
                var endTimezone = model.endTimezone;
                var start = model.start;
                var end = model.start;
                method = method || 'apply';
                startTimezone = startTimezone || endTimezone;
                endTimezone = endTimezone || startTimezone;
                if (startTimezone) {
                    if (timezone) {
                        if (method === 'apply') {
                            start = kendo.timezone.convert(model.start, timezone, startTimezone);
                            end = kendo.timezone.convert(model.end, timezone, endTimezone);
                        } else {
                            start = kendo.timezone.convert(model.start, startTimezone, timezone);
                            end = kendo.timezone.convert(model.end, endTimezone, timezone);
                        }
                    } else {
                        start = kendo.timezone[method](model.start, startTimezone);
                        end = kendo.timezone[method](model.end, endTimezone);
                    }
                    model._set('start', start);
                    model._set('end', end);
                }
            },
            _createEditor: function () {
                var that = this;
                var editor;
                if (this._isMobile() && kendo.Pane) {
                    editor = that._editor = new MobileEditor(this.wrapper, extend({}, this.options, {
                        target: this,
                        timezone: that.dataSource.reader.timezone,
                        resources: that.resources,
                        createButton: proxy(this._createButton, this)
                    }));
                } else {
                    editor = that._editor = new PopupEditor(this.wrapper, extend({}, this.options, {
                        target: this,
                        createButton: proxy(this._createButton, this),
                        timezone: that.dataSource.reader.timezone,
                        resources: that.resources
                    }));
                }
                editor.bind('cancel', function (e) {
                    if (that.trigger('cancel', {
                            container: e.container,
                            event: e.model
                        })) {
                        e.preventDefault();
                        return;
                    }
                    that._preventRefresh = false;
                    that.cancelEvent();
                    if (that._attemptRefresh) {
                        that.refresh();
                    }
                    that.focus();
                });
                editor.bind('edit', function (e) {
                    if (that.trigger(EDIT, {
                            container: e.container,
                            event: e.model
                        })) {
                        e.preventDefault();
                    }
                });
                editor.bind('save', function () {
                    that._preventRefresh = false;
                    that.saveEvent();
                });
                editor.bind('remove', function (e) {
                    that._preventRefresh = false;
                    that.removeEvent(e.model);
                });
                editor.bind('resetSeries', function (e) {
                    that._confirmation(function (cancel) {
                        that._preventRefresh = false;
                        if (!cancel) {
                            that.dataSource._removeExceptions(e.model);
                            that.saveEvent();
                        }
                    }, e.model, true);
                });
            },
            _createPopupEditor: function (model) {
                var editor = this._editor;
                if (!model.isNew() || model.isOccurrence()) {
                    if (model.isOccurrence()) {
                        this._convertDates(model.recurrenceId ? this.dataSource.get(model.recurrenceId) : model);
                    }
                    this._convertDates(model);
                }
                this.editable = editor.editEvent(model);
            },
            removeEvent: function (uid) {
                var that = this, model = typeof uid == 'string' ? that.occurrenceByUid(uid) : uid;
                if (!model) {
                    return;
                }
                if (model.isRecurring()) {
                    that._deleteRecurringDialog(model);
                } else {
                    that._confirmation(function (cancel) {
                        if (!cancel) {
                            that._removeEvent(model);
                        }
                    }, model);
                }
            },
            occurrenceByUid: function (uid) {
                var occurrence = this.dataSource.getByUid(uid);
                if (!occurrence) {
                    occurrence = getOccurrenceByUid(this._data, uid);
                }
                return occurrence;
            },
            occurrencesInRange: function (start, end) {
                return new kendo.data.Query(this._data).filter({
                    logic: 'or',
                    filters: [
                        {
                            logic: 'and',
                            filters: [
                                {
                                    field: 'start',
                                    operator: 'gte',
                                    value: start
                                },
                                {
                                    field: 'end',
                                    operator: 'gte',
                                    value: start
                                },
                                {
                                    field: 'start',
                                    operator: 'lt',
                                    value: end
                                }
                            ]
                        },
                        {
                            logic: 'and',
                            filters: [
                                {
                                    field: 'start',
                                    operator: 'lte',
                                    value: start
                                },
                                {
                                    field: 'end',
                                    operator: 'gt',
                                    value: start
                                }
                            ]
                        }
                    ]
                }).toArray();
            },
            _removeEvent: function (model) {
                if (!this.trigger(REMOVE, { event: model })) {
                    if (this.dataSource.remove(model)) {
                        this.dataSource.sync();
                    }
                }
            },
            _deleteRecurringDialog: function (model) {
                var that = this;
                var currentModel = model;
                var editable = that.options.editable;
                var deleteOccurrence;
                var deleteSeries;
                var deleteOccurrenceConfirmation;
                var deleteSeriesConfirmation;
                var editRecurringMode = isPlainObject(editable) ? editable.editRecurringMode : 'dialog';
                deleteOccurrence = function () {
                    var occurrence = currentModel.recurrenceId ? currentModel : currentModel.toOccurrence();
                    var head = that.dataSource.get(occurrence.recurrenceId);
                    that._convertDates(head);
                    that._removeEvent(occurrence);
                };
                deleteSeries = function () {
                    if (currentModel.recurrenceId) {
                        currentModel = that.dataSource.get(currentModel.recurrenceId);
                    }
                    that._removeEvent(currentModel);
                };
                if (editRecurringMode != 'dialog' || that._isEditorOpened()) {
                    deleteOccurrenceConfirmation = function () {
                        that._confirmation(function (cancel) {
                            if (!cancel) {
                                deleteOccurrence();
                            }
                        }, currentModel);
                    };
                    deleteSeriesConfirmation = function () {
                        that._confirmation(function (cancel) {
                            if (!cancel) {
                                deleteSeries();
                            }
                        }, currentModel);
                    };
                }
                var seriesCallback = deleteSeriesConfirmation || deleteSeries;
                var occurrenceCallback = deleteOccurrenceConfirmation || deleteOccurrence;
                if (that._isEditorOpened()) {
                    if (model.isException()) {
                        occurrenceCallback();
                    } else {
                        seriesCallback();
                    }
                } else {
                    var recurrenceMessages = that.options.messages.recurrenceMessages;
                    that._showRecurringDialog(model, occurrenceCallback, seriesCallback, {
                        title: recurrenceMessages.deleteWindowTitle,
                        text: recurrenceMessages.deleteRecurring ? recurrenceMessages.deleteRecurring : DELETERECURRING,
                        occurrenceText: recurrenceMessages.deleteWindowOccurrence,
                        seriesText: recurrenceMessages.deleteWindowSeries
                    });
                }
            },
            _isEditorOpened: function () {
                return !!this._editor.container;
            },
            _unbindView: function (view) {
                var that = this;
                that.angular('cleanup', function () {
                    return { elements: that.items() };
                });
                view.destroy();
            },
            _bindView: function (view) {
                var that = this;
                if (that.options.editable) {
                    if (that._viewRemoveHandler) {
                        view.unbind(REMOVE, that._viewRemoveHandler);
                    }
                    that._viewRemoveHandler = function (e) {
                        that.removeEvent(e.uid);
                    };
                    view.bind(REMOVE, that._viewRemoveHandler);
                    if (that._viewAddHandler) {
                        view.unbind(ADD, that._viewAddHandler);
                    }
                    that._viewAddHandler = function (e) {
                        that.addEvent(e.eventInfo);
                    };
                    view.bind(ADD, this._viewAddHandler);
                    if (that._viewEditHandler) {
                        view.unbind(EDIT, that._viewEditHandler);
                    }
                    that._viewEditHandler = function (e) {
                        that.editEvent(e.uid);
                    };
                    view.bind(EDIT, this._viewEditHandler);
                }
                if (that._viewNavigateHandler) {
                    view.unbind('navigate', that._viewNavigateHandler);
                }
                that._viewNavigateHandler = function (e) {
                    if (e.view) {
                        var switchWorkDay = 'isWorkDay' in e;
                        var action = switchWorkDay ? 'changeWorkDay' : 'changeView';
                        if (!that.trigger('navigate', {
                                view: e.view,
                                isWorkDay: e.isWorkDay,
                                action: action,
                                date: e.date
                            })) {
                            if (switchWorkDay) {
                                that._workDayMode = e.isWorkDay;
                            }
                            that._selectView(e.view);
                            that.date(e.date);
                        }
                    }
                };
                view.bind('navigate', that._viewNavigateHandler);
                if (that._viewActivateHandler) {
                    view.unbind('activate', that._viewActivateHandler);
                }
                that._viewActivateHandler = function () {
                    var view = this;
                    if (that._selection) {
                        view.constrainSelection(that._selection);
                        that._select();
                        that._adjustSelectedDate();
                    }
                };
                view.bind('activate', that._viewActivateHandler);
            },
            _selectView: function (name) {
                var that = this;
                if (name && that.views[name]) {
                    if (that._selectedView) {
                        that._unbindView(that._selectedView);
                    }
                    that._selectedView = that._renderView(name);
                    that._selectedViewName = name;
                    if (that._viewsCount > 1 && !that._isMobile()) {
                        var viewButton = VIEWBUTTONTEMPLATE({
                            views: that.views,
                            view: name,
                            ns: kendo.ns
                        });
                        var firstButton = that.toolbar.find('.k-scheduler-views li:first-child');
                        if (firstButton.is('.k-current-view')) {
                            firstButton.replaceWith(viewButton);
                        } else {
                            that.toolbar.find('.k-scheduler-views').prepend(viewButton);
                        }
                        var viewButtons = that.toolbar.find('.k-scheduler-views li').removeClass('k-state-selected');
                        viewButtons.end().find('.k-view-' + name.replace(/\./g, '\\.').toLowerCase()).addClass('k-state-selected');
                    } else {
                        var viewSelect = that.toolbar.find('.k-scheduler-mobile-views');
                        viewSelect.find('[value=' + name.replace(/\./g, '\\.') + ']').prop('selected', 'selected');
                    }
                }
            },
            view: function (name) {
                var that = this;
                if (name) {
                    that._selectView(name);
                    that.rebind();
                    return;
                }
                return that._selectedView;
            },
            viewName: function () {
                return this.view().name;
            },
            _renderView: function (name) {
                var view = this._initializeView(name);
                this._bindView(view);
                if (kendo.support.mouseAndTouchPresent || kendo.support.pointers) {
                    view.content.css('-ms-touch-action', 'pinch-zoom');
                    view.content.css('touch-action', 'pinch-zoom');
                }
                this._model.set('formattedDate', view.dateForTitle());
                this._model.set('formattedShortDate', view.shortDateForTitle());
                this._model.set('formattedMobileDate', view.mobileDateForTitle ? view.mobileDateForTitle() : view.shortDateForTitle());
                this._model.set('formattedYear', kendo.format('{0:yyyy}', view.startDate()));
                return view;
            },
            resize: function (force) {
                var size = this.getSize();
                var currentSize = this._size;
                var view = this.view();
                if (!view || !view.groups) {
                    return;
                }
                if (force || !currentSize || size.width !== currentSize.width || size.height !== currentSize.height) {
                    this.refresh({ action: 'resize' });
                    this._size = size;
                }
            },
            _adjustSelectedDate: function () {
                var date = this._model.selectedDate, selection = this._selection, start = selection.start;
                if (start && !kendo.date.isInDateRange(date, getDate(start), getDate(selection.end))) {
                    date.setFullYear(start.getFullYear(), start.getMonth(), start.getDate());
                }
            },
            _initializeView: function (name) {
                var view = this.views[name];
                if (view) {
                    var isSettings = isPlainObject(view), type = view.type;
                    if (typeof type === STRING) {
                        type = kendo.getter(view.type)(window);
                    }
                    if (type) {
                        view = new type(this.wrapper, trimOptions(extend(true, {}, this.options, isSettings ? view : {}, {
                            resources: this.resources,
                            date: this.date(),
                            startTime: kendo.parseDate(this.options.startTime),
                            endTime: kendo.parseDate(this.options.endTime),
                            showWorkHours: this._workDayMode
                        })));
                    } else {
                        throw new Error('There is no such view');
                    }
                }
                return view;
            },
            _views: function () {
                var views = this.options.views;
                var view;
                var defaultView;
                var selected;
                var isSettings;
                var name;
                var type;
                var idx;
                var length;
                this.views = {};
                this._viewsCount = 0;
                for (idx = 0, length = views.length; idx < length; idx++) {
                    var hasType = false;
                    view = views[idx];
                    isSettings = isPlainObject(view);
                    if (isSettings) {
                        type = name = view.type ? view.type : view;
                        if (typeof type !== STRING) {
                            name = view.name || view.title;
                            hasType = true;
                        }
                    } else {
                        type = name = view;
                    }
                    defaultView = defaultViews[name];
                    if (defaultView && !hasType) {
                        view.type = defaultView.type;
                        defaultView.title = this.options.messages.views[name];
                        if (defaultView.type === 'day') {
                            defaultView.messages = { allDay: this.options.messages.allDay };
                        } else if (defaultView.type === 'agenda') {
                            defaultView.messages = {
                                event: this.options.messages.event,
                                date: this.options.messages.date,
                                time: this.options.messages.time
                            };
                        }
                    }
                    view = extend({ title: name }, defaultView, isSettings ? view : {});
                    if (name) {
                        this.views[name] = view;
                        this._viewsCount++;
                        if (!selected || view.selected) {
                            selected = name;
                        }
                    }
                }
                if (selected) {
                    this._selectedViewName = selected;
                }
            },
            rebind: function () {
                this.dataSource.fetch();
            },
            _dataSource: function () {
                var that = this, options = that.options, dataSource = options.dataSource;
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                if (options.timezone && !(dataSource instanceof SchedulerDataSource)) {
                    dataSource = extend(true, dataSource, { schema: { timezone: options.timezone } });
                } else if (dataSource instanceof SchedulerDataSource) {
                    options.timezone = dataSource.options.schema ? dataSource.options.schema.timezone : '';
                }
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler);
                } else {
                    that._refreshHandler = proxy(that.refresh, that);
                    that._progressHandler = proxy(that._requestStart, that);
                    that._errorHandler = proxy(that._error, that);
                }
                that.dataSource = kendo.data.SchedulerDataSource.create(dataSource).bind(CHANGE, that._refreshHandler).bind(PROGRESS, that._progressHandler).bind(ERROR, that._errorHandler);
                that.options.dataSource = that.dataSource;
            },
            _error: function () {
                this._progress(false);
            },
            _requestStart: function () {
                this._progress(true);
            },
            _progress: function (toggle) {
                var element = this.element.find('.k-scheduler-content');
                kendo.ui.progress(element, toggle);
            },
            _resources: function () {
                var that = this;
                var resources = that.options.resources;
                var resourcePromises = [];
                for (var idx = 0; idx < resources.length; idx++) {
                    var resource = resources[idx];
                    var field = resource.field;
                    var name = resource.name || field;
                    var dataSource = resource.dataSource;
                    if (!field || !dataSource) {
                        throw new Error('The "field" and "dataSource" options of the scheduler resource are mandatory.');
                    }
                    that.resources.push({
                        field: field,
                        name: name,
                        title: resource.title || field,
                        dataTextField: resource.dataTextField || 'text',
                        dataValueField: resource.dataValueField || 'value',
                        dataColorField: resource.dataColorField || 'color',
                        valuePrimitive: resource.valuePrimitive != null ? resource.valuePrimitive : true,
                        multiple: resource.multiple || false,
                        dataSource: that._resourceDataSource(dataSource, name, resourcePromises)
                    });
                }
                if (!that.options.autoBind) {
                    that._selectView(that._selectedViewName);
                } else {
                    $.when.apply(null, resourcePromises).then(function () {
                        that.view(that._selectedViewName);
                    });
                }
            },
            _resourceDataSource: function (resourceDS, groupName, promises) {
                var that = this;
                var dataSource = isArray(resourceDS) ? { data: resourceDS } : resourceDS;
                var dataSourceInstance = kendo.data.DataSource.create(dataSource);
                if (that.options.autoBind) {
                    promises.push(dataSourceInstance.fetch(function () {
                        that._bindResourceEvents(this, groupName);
                    }));
                } else {
                    that._bindResourceEvents(dataSourceInstance, groupName);
                }
                return dataSourceInstance;
            },
            _bindResourceEvents: function (resourceDS, groupName) {
                var that = this;
                var isGrouped = that.options.group && that.options.group.resources.length;
                var isResourceGrouped = isGrouped && that.options.group.resources.indexOf(groupName) > -1;
                if (!that._resourceRefreshHandler && isResourceGrouped) {
                    that._resourceRefreshHandler = proxy(that._refreshResource, that);
                    that._resourceProgressHandler = proxy(that._requestStart, that);
                    that._resourceErrorHandler = proxy(that._error, that);
                }
                if (isResourceGrouped) {
                    resourceDS.bind(CHANGE, that._resourceRefreshHandler).bind(PROGRESS, that._resourceProgressHandler).bind(ERROR, that._resourceErrorHandler);
                }
            },
            _refreshResource: function () {
                var that = this;
                that.view(that._selectedViewName);
            },
            _initModel: function () {
                var that = this;
                that._model = kendo.observable({
                    selectedDate: new Date(this.options.date),
                    formattedDate: '',
                    formattedShortDate: ''
                });
                that._model.bind('change', function (e) {
                    if (e.field === 'selectedDate') {
                        that.view(that._selectedViewName);
                    }
                });
            },
            _wrapper: function () {
                var that = this;
                var options = that.options;
                var height = options.height;
                var width = options.width;
                that.wrapper = that.element.addClass('k-widget k-scheduler k-floatwrap').attr('role', 'grid').attr('aria-multiselectable', true);
                if (that._isMobile()) {
                    that.wrapper.addClass('k-scheduler-mobile');
                }
                if (height) {
                    that.wrapper.height(height);
                }
                if (width) {
                    that.wrapper.width(width);
                }
            },
            date: function (value) {
                if (value != null && getDate(value) >= getDate(this.options.min) && getDate(value) <= getDate(this.options.max)) {
                    this._model.set('selectedDate', value);
                }
                return getDate(this._model.get('selectedDate'));
            },
            _toolbar: function () {
                var that = this;
                var options = that.options;
                var commands = [];
                if (options.toolbar) {
                    commands = $.isArray(options.toolbar) ? options.toolbar : [options.toolbar];
                }
                var template = this._isMobile() ? MOBILETOOLBARTEMPLATE : TOOLBARTEMPLATE;
                var toolbar = $(template({
                    messages: options.messages,
                    pdf: $.grep(commands, function (item) {
                        return item == 'pdf' || item.name == 'pdf';
                    }).length > 0,
                    ns: kendo.ns,
                    view: that._selectedViewName,
                    views: that.views,
                    viewsCount: that._viewsCount,
                    editable: that.options.editable
                }));
                that.wrapper.append(toolbar);
                that.toolbar = toolbar;
                kendo.bind(that.toolbar, that._model);
                toolbar.on(CLICK + NS, '.k-pdf', function (e) {
                    e.preventDefault();
                    that.saveAsPDF();
                });
                toolbar.on(CLICK + NS, '.k-create-event', function (e) {
                    e.preventDefault();
                    that.addEvent();
                });
                toolbar.on(CLICK + NS, '.k-nav-calendar', function (e) {
                    e.preventDefault();
                    that._showCalendar(e.target);
                });
                toolbar.on(CLICK + NS, '.k-scheduler-navigation li', function (e) {
                    var li = $(this);
                    var date = new Date(that.date());
                    var action = '';
                    var currentDate = new Date();
                    var timezone = that.options.timezone;
                    e.preventDefault();
                    if (li.hasClass('k-nav-today')) {
                        action = 'today';
                        if (timezone) {
                            var timezoneOffset = kendo.timezone.offset(currentDate, timezone);
                            date = kendo.timezone.convert(currentDate, currentDate.getTimezoneOffset(), timezoneOffset);
                        } else {
                            date = currentDate;
                        }
                    } else if (li.hasClass('k-nav-next')) {
                        action = 'next';
                        date = that.view().nextDate();
                    } else if (li.hasClass('k-nav-prev')) {
                        action = 'previous';
                        date = that.view().previousDate();
                    } else if (li.hasClass('k-nav-current') && !that._isMobile()) {
                        that._showCalendar();
                        return;
                    }
                    if (!that.trigger('navigate', {
                            view: that._selectedViewName,
                            action: action,
                            date: date
                        })) {
                        that.date(date);
                    }
                });
                toolbar.on(CLICK + NS, '.k-scheduler-views li:not(.k-current-view), .k-scheduler-refresh', function (e) {
                    e.preventDefault();
                    var name = $(this).attr(kendo.attr('name'));
                    if (!that.trigger('navigate', {
                            view: name,
                            action: 'changeView',
                            date: that.date()
                        })) {
                        that.view(name);
                        that.element.find('.' + EXPANDEDSTATE).removeClass(EXPANDEDSTATE);
                    }
                });
                toolbar.on(CLICK + NS, '.k-scheduler-views li.k-current-view', function (e) {
                    e.preventDefault();
                    that.element.find('.k-scheduler-views').toggleClass(EXPANDEDSTATE);
                    $(document).on(MOUSEDOWN + NS, function (e) {
                        if ($(e.target).closest('.k-scheduler-views').length === 0) {
                            that.element.find('.' + EXPANDEDSTATE).removeClass(EXPANDEDSTATE);
                            $(document).off(CLICK + NS);
                        }
                    });
                });
                toolbar.find('.k-scheduler-mobile-views').on('change', function (e) {
                    that.view(e.target.value);
                });
                toolbar.find('li').hover(function () {
                    $(this).addClass('k-state-hover');
                }, function () {
                    $(this).removeClass('k-state-hover');
                });
            },
            _showCalendar: function (targetElm) {
                var that = this, target = targetElm || that.toolbar.find('.k-nav-current'), html = $('<div class="k-calendar-container"><div class="k-scheduler-calendar"/></div>');
                if (!that.popup) {
                    that.popup = new Popup(html, {
                        anchor: target,
                        activate: function () {
                            if (that.popup && that.calendar) {
                                that.popup._toggleResize(false);
                                that.calendar.element.find('table').focus();
                                that.popup._toggleResize(true);
                            }
                        },
                        open: function () {
                            if (!that.calendar) {
                                that.calendar = new Calendar(this.element.find('.k-scheduler-calendar'), {
                                    change: function () {
                                        var date = this.value();
                                        if (!that.trigger('navigate', {
                                                view: that._selectedViewName,
                                                action: 'changeDate',
                                                date: date
                                            })) {
                                            that.date(date);
                                            that.popup.close();
                                        }
                                        if (!that._isMobile) {
                                            that._selectedView.element.focus();
                                            that.toolbar.find('.k-nav-current').focus().addClass(FOCUSEDSTATE);
                                        }
                                    },
                                    min: that.options.min,
                                    max: that.options.max
                                });
                            }
                            that.calendar.element.on('keydown' + NS, function (e) {
                                if (e.keyCode === keys.ESC || e.keyCode === keys.TAB) {
                                    that.popup.close();
                                    that._selectedView.element.focus();
                                    that.toolbar.find('.k-nav-current').focus().addClass(FOCUSEDSTATE);
                                }
                            });
                            that.calendar.value(that.date());
                        },
                        copyAnchorStyles: false
                    });
                }
                that.popup.open();
            },
            refresh: function (e) {
                var that = this;
                var view = this.view();
                var preventRefresh = e && e.action === 'itemchange' && (this._editor.editable || this._preventRefresh) || this.dataSource.options.type === 'signalr' && this._preventRefresh;
                this._progress(false);
                this.angular('cleanup', function () {
                    return { elements: that.items() };
                });
                e = e || {};
                if (!view) {
                    return;
                }
                if (preventRefresh) {
                    this._attemptRefresh = true && this.dataSource.options.type === 'signalr';
                    return;
                }
                if (this.trigger('dataBinding', {
                        action: e.action || 'rebind',
                        index: e.index,
                        items: e.items
                    })) {
                    return;
                }
                if (!(e && e.action === 'resize') && this._editor) {
                    this._editor.close();
                }
                this._data = this.dataSource.expand(view.startDate(), view.visibleEndDate());
                view.refreshLayout();
                view.render(this._data);
                this.trigger('dataBound');
                this._attemptRefresh = false;
            },
            slotByPosition: function (x, y) {
                var view = this.view();
                if (!view._slotByPosition) {
                    return null;
                }
                var slot = view._slotByPosition(x, y);
                if (!slot) {
                    return null;
                }
                return {
                    startDate: slot.startDate(),
                    endDate: slot.endDate(),
                    groupIndex: slot.groupIndex,
                    element: slot.element,
                    isDaySlot: slot.isDaySlot
                };
            },
            slotByElement: function (element) {
                var offset = $(element).offset();
                return this.slotByPosition(offset.left, offset.top);
            },
            resourcesBySlot: function (slot) {
                return this.view()._resourceBySlot(slot);
            }
        });
        var defaultViews = {
            day: { type: 'kendo.ui.DayView' },
            week: { type: 'kendo.ui.WeekView' },
            workWeek: { type: 'kendo.ui.WorkWeekView' },
            agenda: { type: 'kendo.ui.AgendaView' },
            month: { type: 'kendo.ui.MonthView' },
            timeline: { type: 'kendo.ui.TimelineView' },
            timelineWeek: { type: 'kendo.ui.TimelineWeekView' },
            timelineWorkWeek: { type: 'kendo.ui.TimelineWorkWeekView' },
            timelineMonth: { type: 'kendo.ui.TimelineMonthView' }
        };
        ui.plugin(Scheduler);
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(Scheduler.prototype);
            var SCHEDULER_EXPORT = 'k-scheduler-pdf-export';
            Scheduler.fn._drawPDF = function (progress) {
                var wrapper = this.wrapper;
                var styles = wrapper[0].style.cssText;
                wrapper.css({
                    width: wrapper.width(),
                    height: wrapper.height()
                });
                wrapper.addClass(SCHEDULER_EXPORT);
                var scheduler = this;
                var promise = new $.Deferred();
                var table = wrapper.find('.k-scheduler-content').find('table').css('table-layout', 'auto');
                setTimeout(function () {
                    table.css('table-layout', 'fixed');
                    scheduler.resize(true);
                    scheduler._drawPDFShadow({}, { avoidLinks: scheduler.options.pdf.avoidLinks }).done(function (group) {
                        var args = {
                            page: group,
                            pageNumber: 1,
                            progress: 1,
                            totalPages: 1
                        };
                        progress.notify(args);
                        promise.resolve(args.page);
                    }).fail(function (err) {
                        promise.reject(err);
                    }).always(function () {
                        wrapper[0].style.cssText = styles;
                        wrapper.removeClass(SCHEDULER_EXPORT);
                        scheduler.resize(true);
                        scheduler.resize(true);
                    });
                });
                return promise;
            };
        }
        var TimezoneEditor = Widget.extend({
            init: function (element, options) {
                var that = this, zones = kendo.timezone.windows_zones;
                if (!zones || !kendo.timezone.zones_titles) {
                    throw new Error('kendo.timezones.min.js is not included.');
                }
                Widget.fn.init.call(that, element, options);
                that.wrapper = that.element;
                that._zonesQuery = new kendo.data.Query(zones);
                that._zoneTitleId = kendo.guid();
                that._zoneTitlePicker();
                that._zonePicker();
                that._zoneTitle.bind('cascade', function () {
                    if (!this.value()) {
                        that._zone.wrapper.hide();
                    }
                });
                that._zone.bind('cascade', function () {
                    that._value = this.value();
                    that.trigger('change');
                });
                that.value(that.options.value);
            },
            options: {
                name: 'TimezoneEditor',
                value: '',
                optionLabel: 'No timezone'
            },
            events: ['change'],
            _zoneTitlePicker: function () {
                var that = this, zoneTitle = $('<input id="' + that._zoneTitleId + '" aria-label="' + that.options.title + '"/>').appendTo(that.wrapper);
                that._zoneTitle = new kendo.ui.DropDownList(zoneTitle, {
                    dataSource: kendo.timezone.zones_titles,
                    dataValueField: 'other_zone',
                    dataTextField: 'name',
                    optionLabel: that.options.optionLabel
                });
            },
            _zonePicker: function () {
                var that = this, zone = $('<input aria-label="' + that.options.title + '"/>').appendTo(this.wrapper);
                that._zone = new kendo.ui.DropDownList(zone, {
                    dataValueField: 'zone',
                    dataTextField: 'territory',
                    dataSource: that._zonesQuery.data,
                    cascadeFrom: that._zoneTitleId,
                    dataBound: function () {
                        that._value = this.value();
                        this.wrapper.toggle(this.dataSource.view().length > 1);
                    }
                });
                that._zone.wrapper.hide();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                kendo.destroy(this.wrapper);
            },
            value: function (value) {
                var that = this, zone;
                if (value === undefined) {
                    return that._value;
                }
                zone = that._zonesQuery.filter({
                    field: 'zone',
                    operator: 'eq',
                    value: value
                }).data[0];
                if (zone) {
                    that._zoneTitle.value(zone.other_zone);
                    that._zone.value(zone.zone);
                } else {
                    that._zoneTitle.select(0);
                }
            }
        });
        ui.plugin(TimezoneEditor);
        var ZONETITLEOPTIONTEMPLATE = kendo.template('<option value="#=other_zone#">#=name#</option>');
        var ZONEOPTIONTEMPLATE = kendo.template('<option value="#=zone#">#=territory#</option>');
        var MobileTimezoneEditor = Widget.extend({
            init: function (element, options) {
                var that = this, zones = kendo.timezone.windows_zones;
                if (!zones || !kendo.timezone.zones_titles) {
                    throw new Error('kendo.timezones.min.js is not included.');
                }
                Widget.fn.init.call(that, element, options);
                that.wrapper = that.element;
                that._zonesQuery = new kendo.data.Query(zones);
                that._zoneTitlePicker();
                that._zonePicker();
                that.value(that.options.value);
            },
            options: {
                name: 'MobileTimezoneEditor',
                optionLabel: 'No timezone',
                value: ''
            },
            events: ['change'],
            _bindZones: function (value) {
                var data = value ? this._filter(value) : [];
                this._zone.html(this._options(data, ZONEOPTIONTEMPLATE));
            },
            _filter: function (value) {
                return this._zonesQuery.filter({
                    field: 'other_zone',
                    operator: 'eq',
                    value: value
                }).data;
            },
            _options: function (data, template, optionLabel) {
                var idx = 0;
                var html = '';
                var length = data.length;
                if (optionLabel) {
                    html += template({
                        other_zone: '',
                        name: optionLabel
                    });
                }
                for (; idx < length; idx++) {
                    html += template(data[idx]);
                }
                return html;
            },
            _zoneTitlePicker: function () {
                var that = this;
                var options = that._options(kendo.timezone.zones_titles, ZONETITLEOPTIONTEMPLATE, that.options.optionLabel);
                that._zoneTitle = $('<select>' + options + '</select>').appendTo(that.wrapper).change(function () {
                    var value = this.value;
                    var zone = that._zonePickerLabel;
                    var zoneSelect = zone.find('select');
                    that._bindZones(value);
                    if (value && zoneSelect.children().length > 1) {
                        zone.show();
                    } else {
                        zone.hide();
                    }
                    that._value = that._zone[0].value;
                    that.trigger('change');
                });
            },
            _zonePicker: function () {
                var that = this;
                that._zonePickerLabel = $('<li class=\'k-item k-zonepicker\' style=\'display:none\'>' + '<label class=\'k-label\'><span class=\'k-item-title\'></span>' + '<div></div>' + '</label>' + '</li>');
                that._zone = $('<select></select>').appendTo(that._zonePickerLabel.find('div')).change(function () {
                    that._value = this.value;
                    that.trigger('change');
                });
                this.wrapper.closest('.k-item').after(that._zonePickerLabel);
                that._bindZones(that._zoneTitle.val());
                that._value = that._zone[0].value;
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                kendo.destroy(this.wrapper);
            },
            value: function (value) {
                var that = this;
                var zonePicker = that._zone;
                var other_zone = '';
                var zone_value = '';
                var zone;
                if (value === undefined) {
                    return that._value;
                }
                zone = that._zonesQuery.filter({
                    field: 'zone',
                    operator: 'eq',
                    value: value
                }).data[0];
                if (zone) {
                    zone_value = zone.zone;
                    other_zone = zone.other_zone;
                }
                that._zoneTitle.val(other_zone);
                that._bindZones(other_zone);
                zonePicker.val(zone_value);
                zone_value = zonePicker[0].value;
                if (zone_value && zonePicker.children.length > 1) {
                    that._zonePickerLabel.show();
                } else {
                    that._zonePickerLabel.hide();
                }
                that._value = zone_value;
            }
        });
        ui.plugin(MobileTimezoneEditor);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.touch', [
        'kendo.core',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'touch',
        name: 'Touch',
        category: 'mobile',
        description: 'The kendo Touch widget provides a cross-platform compatible API for handling user-initiated touch events, multi-touch gestures and event sequences (drag, swipe, etc.). ',
        depends: [
            'core',
            'userevents'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, proxy = $.proxy, abs = Math.abs, MAX_DOUBLE_TAP_DISTANCE = 20;
        var Touch = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element;
                that.wrapper = element;
                function eventProxy(name) {
                    return function (e) {
                        that._triggerTouch(name, e);
                    };
                }
                function gestureEventProxy(name) {
                    return function (e) {
                        that.trigger(name, {
                            touches: e.touches,
                            distance: e.distance,
                            center: e.center,
                            event: e.event
                        });
                    };
                }
                that.events = new kendo.UserEvents(element, {
                    filter: options.filter,
                    surface: options.surface,
                    minHold: options.minHold,
                    multiTouch: options.multiTouch,
                    allowSelection: true,
                    fastTap: options.fastTap,
                    press: eventProxy('touchstart'),
                    hold: eventProxy('hold'),
                    tap: proxy(that, '_tap'),
                    gesturestart: gestureEventProxy('gesturestart'),
                    gesturechange: gestureEventProxy('gesturechange'),
                    gestureend: gestureEventProxy('gestureend')
                });
                if (options.enableSwipe) {
                    that.events.bind('start', proxy(that, '_swipestart'));
                    that.events.bind('move', proxy(that, '_swipemove'));
                } else {
                    that.events.bind('start', proxy(that, '_dragstart'));
                    that.events.bind('move', eventProxy('drag'));
                    that.events.bind('end', eventProxy('dragend'));
                }
                kendo.notify(that);
            },
            events: [
                'touchstart',
                'dragstart',
                'drag',
                'dragend',
                'tap',
                'doubletap',
                'hold',
                'swipe',
                'gesturestart',
                'gesturechange',
                'gestureend'
            ],
            options: {
                name: 'Touch',
                surface: null,
                global: false,
                fastTap: false,
                filter: null,
                multiTouch: false,
                enableSwipe: false,
                minXDelta: 30,
                maxYDelta: 20,
                maxDuration: 1000,
                minHold: 800,
                doubleTapTimeout: 800
            },
            cancel: function () {
                this.events.cancel();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.events.destroy();
            },
            _triggerTouch: function (type, e) {
                if (this.trigger(type, {
                        touch: e.touch,
                        event: e.event
                    })) {
                    e.preventDefault();
                }
            },
            _tap: function (e) {
                var that = this, lastTap = that.lastTap, touch = e.touch;
                if (lastTap && touch.endTime - lastTap.endTime < that.options.doubleTapTimeout && kendo.touchDelta(touch, lastTap).distance < MAX_DOUBLE_TAP_DISTANCE) {
                    that._triggerTouch('doubletap', e);
                    that.lastTap = null;
                } else {
                    that._triggerTouch('tap', e);
                    that.lastTap = touch;
                }
            },
            _dragstart: function (e) {
                this._triggerTouch('dragstart', e);
            },
            _swipestart: function (e) {
                if (abs(e.x.velocity) * 2 >= abs(e.y.velocity)) {
                    e.sender.capture();
                }
            },
            _swipemove: function (e) {
                var that = this, options = that.options, touch = e.touch, duration = e.event.timeStamp - touch.startTime, direction = touch.x.initialDelta > 0 ? 'right' : 'left';
                if (abs(touch.x.initialDelta) >= options.minXDelta && abs(touch.y.initialDelta) < options.maxYDelta && duration < options.maxDuration) {
                    that.trigger('swipe', {
                        direction: direction,
                        touch: e.touch
                    });
                    touch.cancel();
                }
            }
        });
        kendo.ui.plugin(Touch);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.gantt.list', [
        'kendo.dom',
        'kendo.touch',
        'kendo.draganddrop',
        'kendo.columnsorter',
        'kendo.datetimepicker',
        'kendo.editable'
    ], f);
}(function () {
    var __meta__ = {
        id: 'gantt.list',
        name: 'Gantt List',
        category: 'web',
        description: 'The Gantt List',
        depends: [
            'dom',
            'touch',
            'draganddrop',
            'columnsorter',
            'datetimepicker',
            'editable'
        ],
        hidden: true
    };
    (function ($) {
        var kendo = window.kendo;
        var kendoDom = kendo.dom;
        var kendoDomElement = kendoDom.element;
        var kendoTextElement = kendoDom.text;
        var browser = kendo.support.browser;
        var mobileOS = kendo.support.mobileOS;
        var ui = kendo.ui;
        var Widget = ui.Widget;
        var extend = $.extend;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var map = $.map;
        var isFunction = $.isFunction;
        var oldIE = browser.msie && browser.version < 9;
        var keys = kendo.keys;
        var titleFromField = {
            'title': 'Title',
            'start': 'Start Time',
            'end': 'End Time',
            'percentComplete': '% Done',
            'parentId': 'Predecessor ID',
            'id': 'ID',
            'orderId': 'Order ID'
        };
        var STRING = 'string';
        var NS = '.kendoGanttList';
        var CLICK = 'click';
        var DOT = '.';
        var SIZE_CALCULATION_TEMPLATE = '<table style=\'visibility: hidden;\'>' + '<tbody>' + '<tr style=\'height:{0}\'>' + '<td>&nbsp;</td>' + '</tr>' + '</tbody>' + '</table>';
        var listStyles = {
            wrapper: 'k-treelist k-grid k-widget',
            header: 'k-header',
            alt: 'k-alt',
            rtl: 'k-rtl',
            editCell: 'k-edit-cell',
            group: 'k-treelist-group',
            gridHeader: 'k-grid-header',
            gridHeaderWrap: 'k-grid-header-wrap',
            gridContent: 'k-grid-content',
            gridContentWrap: 'k-grid-content',
            selected: 'k-state-selected',
            icon: 'k-icon',
            iconCollapse: 'k-i-collapse',
            iconExpand: 'k-i-expand',
            iconHidden: 'k-i-none',
            iconPlaceHolder: 'k-icon k-i-none',
            input: 'k-input',
            link: 'k-link',
            resizeHandle: 'k-resize-handle',
            resizeHandleInner: 'k-resize-handle-inner',
            dropPositions: 'k-i-insert-up k-i-insert-down k-i-plus k-i-insert-middle',
            dropTop: 'k-i-insert-up',
            dropBottom: 'k-i-insert-down',
            dropAdd: 'k-i-plus',
            dropMiddle: 'k-i-insert-middle',
            dropDenied: 'k-i-cancel',
            dragStatus: 'k-drag-status',
            dragClue: 'k-drag-clue',
            dragClueText: 'k-clue-text'
        };
        function createPlaceholders(options) {
            var spans = [];
            var className = options.className;
            for (var i = 0, level = options.level; i < level; i++) {
                spans.push(kendoDomElement('span', { className: className }));
            }
            return spans;
        }
        function blurActiveElement() {
            var activeElement = kendo._activeElement();
            if (activeElement && activeElement.nodeName.toLowerCase() !== 'body') {
                $(activeElement).blur();
            }
        }
        var GanttList = ui.GanttList = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                if (this.options.columns.length === 0) {
                    this.options.columns.push('title');
                }
                this.dataSource = this.options.dataSource;
                this._columns();
                this._layout();
                this._domTrees();
                this._header();
                this._sortable();
                this._editable();
                this._selectable();
                this._draggable();
                this._resizable();
                this._attachEvents();
                this._adjustHeight();
                this.bind('render', function () {
                    var headerCols;
                    var tableCols;
                    if (this.options.resizable) {
                        headerCols = this.header.find('col');
                        tableCols = this.content.find('col');
                        this.header.find('th').not(':last').each(function (index) {
                            var width = outerWidth($(this));
                            headerCols.eq(index).width(width);
                            tableCols.eq(index).width(width);
                        });
                        headerCols.last().css('width', 'auto');
                        tableCols.last().css('width', 'auto');
                    }
                }, true);
            },
            _adjustHeight: function () {
                if (this.content) {
                    this.content.height(this.element.height() - outerHeight(this.header.parent()));
                }
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (this._reorderDraggable) {
                    this._reorderDraggable.destroy();
                }
                if (this._tableDropArea) {
                    this._tableDropArea.destroy();
                }
                if (this._contentDropArea) {
                    this._contentDropArea.destroy();
                }
                if (this._columnResizable) {
                    this._columnResizable.destroy();
                }
                if (this.touch) {
                    this.touch.destroy();
                }
                if (this.timer) {
                    clearTimeout(this.timer);
                }
                this.content.off(NS);
                this.header.find('thead').off(NS);
                this.header.find(DOT + GanttList.link).off(NS);
                this.header = null;
                this.content = null;
                this.levels = null;
                kendo.destroy(this.element);
            },
            options: {
                name: 'GanttList',
                selectable: true,
                editable: true,
                resizable: false
            },
            _attachEvents: function () {
                var that = this;
                var listStyles = GanttList.styles;
                that.content.on(CLICK + NS, 'td > span.' + listStyles.icon + ':not(.' + listStyles.iconHidden + ')', function (e) {
                    var element = $(this);
                    var model = that._modelFromElement(element);
                    model.set('expanded', !model.get('expanded'));
                    e.stopPropagation();
                });
            },
            _domTrees: function () {
                this.headerTree = new kendoDom.Tree(this.header[0]);
                this.contentTree = new kendoDom.Tree(this.content[0]);
            },
            _columns: function () {
                var columns = this.options.columns;
                var model = function () {
                    this.field = '';
                    this.title = '';
                    this.editable = false;
                    this.sortable = false;
                };
                this.columns = map(columns, function (column) {
                    column = typeof column === STRING ? {
                        field: column,
                        title: titleFromField[column]
                    } : column;
                    return extend(new model(), column);
                });
            },
            _layout: function () {
                var that = this;
                var options = this.options;
                var element = this.element;
                var listStyles = GanttList.styles;
                var calculateRowHeight = function () {
                    var rowHeight = typeof options.rowHeight === STRING ? options.rowHeight : options.rowHeight + 'px';
                    var table = $(kendo.format(SIZE_CALCULATION_TEMPLATE, rowHeight));
                    var height;
                    that.content.append(table);
                    height = outerHeight(table.find('tr'));
                    table.remove();
                    return height;
                };
                element.addClass(listStyles.wrapper).append('<div class=\'' + listStyles.gridHeader + '\'><div class=\'' + listStyles.gridHeaderWrap + '\'></div></div>').append('<div class=\'' + listStyles.gridContentWrap + '\'></div>');
                this.header = element.find(DOT + listStyles.gridHeaderWrap);
                this.content = element.find(DOT + listStyles.gridContent);
                if (options.rowHeight) {
                    this._rowHeight = calculateRowHeight();
                }
            },
            _header: function () {
                var domTree = this.headerTree;
                var colgroup;
                var thead;
                var table;
                colgroup = kendoDomElement('colgroup', null, this._cols());
                thead = kendoDomElement('thead', { 'role': 'rowgroup' }, [kendoDomElement('tr', { 'role': 'row' }, this._ths())]);
                table = kendoDomElement('table', {
                    'style': { 'minWidth': this.options.listWidth + 'px' },
                    'role': 'grid'
                }, [
                    colgroup,
                    thead
                ]);
                domTree.render([table]);
            },
            _render: function (tasks) {
                var colgroup;
                var tbody;
                var table;
                var tableAttr = {
                    'style': { 'minWidth': this.options.listWidth + 'px' },
                    'tabIndex': 0,
                    'role': 'treegrid'
                };
                if (this._rowHeight) {
                    tableAttr.style.height = tasks.length * this._rowHeight + 'px';
                }
                this.levels = [{
                        field: null,
                        value: 0
                    }];
                colgroup = kendoDomElement('colgroup', null, this._cols());
                tbody = kendoDomElement('tbody', { 'role': 'rowgroup' }, this._trs(tasks));
                table = kendoDomElement('table', tableAttr, [
                    colgroup,
                    tbody
                ]);
                this.contentTree.render([table]);
                this.trigger('render');
            },
            _ths: function () {
                var columns = this.columns;
                var column;
                var attr;
                var ths = [];
                for (var i = 0, length = columns.length; i < length; i++) {
                    column = columns[i];
                    attr = {
                        'data-field': column.field,
                        'data-title': column.title,
                        className: GanttList.styles.header,
                        'role': 'columnheader'
                    };
                    ths.push(kendoDomElement('th', attr, [kendoTextElement(column.title)]));
                }
                if (this.options.resizable) {
                    ths.push(kendoDomElement('th', {
                        className: GanttList.styles.header,
                        'role': 'columnheader'
                    }));
                }
                return ths;
            },
            _cols: function () {
                var columns = this.columns;
                var column;
                var style;
                var width;
                var cols = [];
                for (var i = 0, length = columns.length; i < length; i++) {
                    column = columns[i];
                    width = column.width;
                    if (width && parseInt(width, 10) !== 0) {
                        style = { style: { width: typeof width === STRING ? width : width + 'px' } };
                    } else {
                        style = null;
                    }
                    cols.push(kendoDomElement('col', style, []));
                }
                if (this.options.resizable) {
                    cols.push(kendoDomElement('col', { style: { width: '1px' } }));
                }
                return cols;
            },
            _trs: function (tasks) {
                var task;
                var rows = [];
                var attr;
                var className = [];
                var level;
                var listStyles = GanttList.styles;
                for (var i = 0, length = tasks.length; i < length; i++) {
                    task = tasks[i];
                    level = this._levels({
                        idx: task.parentId,
                        id: task.id,
                        summary: task.summary
                    });
                    attr = {
                        'data-uid': task.uid,
                        'data-level': level,
                        'role': 'row'
                    };
                    if (task.summary) {
                        attr['aria-expanded'] = task.expanded;
                    }
                    if (i % 2 !== 0) {
                        className.push(listStyles.alt);
                    }
                    if (task.summary) {
                        className.push(listStyles.group);
                    }
                    if (className.length) {
                        attr.className = className.join(' ');
                    }
                    rows.push(this._tds({
                        task: task,
                        attr: attr,
                        level: level
                    }));
                    className = [];
                }
                return rows;
            },
            _tds: function (options) {
                var children = [];
                var columns = this.columns;
                var column;
                for (var i = 0, l = columns.length; i < l; i++) {
                    column = columns[i];
                    children.push(this._td({
                        task: options.task,
                        column: column,
                        level: options.level
                    }));
                }
                if (this.options.resizable) {
                    children.push(kendoDomElement('td', { 'role': 'gridcell' }));
                }
                return kendoDomElement('tr', options.attr, children);
            },
            _td: function (options) {
                var children = [];
                var resourcesField = this.options.resourcesField;
                var listStyles = GanttList.styles;
                var task = options.task;
                var column = options.column;
                var value = task.get(column.field);
                var formatedValue;
                var label;
                if (column.field == resourcesField) {
                    value = value || [];
                    formatedValue = [];
                    for (var i = 0; i < value.length; i++) {
                        formatedValue.push(kendo.format('{0} [{1}]', value[i].get('name'), value[i].get('formatedValue')));
                    }
                    formatedValue = formatedValue.join(', ');
                } else {
                    formatedValue = column.format ? kendo.format(column.format, value) : value;
                }
                if (column.field === 'title') {
                    children = createPlaceholders({
                        level: options.level,
                        className: listStyles.iconPlaceHolder
                    });
                    children.push(kendoDomElement('span', { className: listStyles.icon + ' ' + (task.summary ? task.expanded ? listStyles.iconCollapse : listStyles.iconExpand : listStyles.iconHidden) }));
                    label = kendo.format('{0}, {1:P0}', formatedValue, task.percentComplete);
                }
                children.push(kendoDomElement('span', { 'aria-label': label }, [kendoTextElement(formatedValue)]));
                return kendoDomElement('td', { 'role': 'gridcell' }, children);
            },
            _levels: function (options) {
                var levels = this.levels;
                var level;
                var summary = options.summary;
                var idx = options.idx;
                var id = options.id;
                for (var i = 0, length = levels.length; i < length; i++) {
                    level = levels[i];
                    if (level.field == idx) {
                        if (summary) {
                            levels.push({
                                field: id,
                                value: level.value + 1
                            });
                        }
                        return level.value;
                    }
                }
            },
            _sortable: function () {
                var that = this;
                var resourcesField = this.options.resourcesField;
                var columns = this.columns;
                var column;
                var sortableInstance;
                var cells = this.header.find('th[' + kendo.attr('field') + ']');
                var cell;
                var changeHandler = function (e) {
                    if (that.dataSource.total() === 0 || that.editable && that.editable.trigger('validate')) {
                        e.preventDefault();
                    }
                };
                for (var idx = 0, length = cells.length; idx < length; idx++) {
                    column = columns[idx];
                    if (column.sortable && column.field !== resourcesField) {
                        cell = cells.eq(idx);
                        sortableInstance = cell.data('kendoColumnSorter');
                        if (sortableInstance) {
                            sortableInstance.destroy();
                        }
                        cell.attr('data-' + kendo.ns + 'field', column.field).kendoColumnSorter({
                            dataSource: this.dataSource,
                            change: changeHandler
                        });
                    }
                }
                cells = null;
            },
            _selectable: function () {
                var that = this;
                var selectable = this.options.selectable;
                if (selectable) {
                    this.content.on(CLICK + NS, 'tr', function (e) {
                        var element = $(this);
                        if (that.editable) {
                            that.editable.trigger('validate');
                        }
                        if (!e.ctrlKey) {
                            that.select(element);
                        } else {
                            that.clearSelection();
                        }
                    });
                }
            },
            select: function (value) {
                var element = this.content.find(value);
                var selectedClassName = GanttList.styles.selected;
                if (element.length) {
                    element.siblings(DOT + selectedClassName).removeClass(selectedClassName).attr('aria-selected', false).end().addClass(selectedClassName).attr('aria-selected', true);
                    this.trigger('change');
                    return;
                }
                return this.content.find(DOT + selectedClassName);
            },
            clearSelection: function () {
                var selected = this.select();
                if (selected.length) {
                    selected.removeClass(GanttList.styles.selected);
                    this.trigger('change');
                }
            },
            _setDataSource: function (dataSource) {
                this.dataSource = dataSource;
                this._sortable();
            },
            _editable: function () {
                var that = this;
                var editable = this.options.editable;
                var listStyles = GanttList.styles;
                var iconSelector = 'span.' + listStyles.icon + ':not(' + listStyles.iconHidden + ')';
                var finishEdit = function () {
                    var editable = that.editable;
                    if (editable) {
                        if (editable.end()) {
                            that._closeCell();
                        } else {
                            editable.trigger('validate');
                        }
                    }
                };
                var mousedown = function (e) {
                    var currentTarget = $(e.currentTarget);
                    if (!currentTarget.hasClass(listStyles.editCell)) {
                        blurActiveElement();
                    }
                };
                if (!editable || editable.update === false) {
                    return;
                }
                this._startEditHandler = function (e) {
                    var td = e.currentTarget ? $(e.currentTarget) : e;
                    var column = that._columnFromElement(td);
                    if (that.editable) {
                        return;
                    }
                    if (column && column.editable) {
                        that._editCell({
                            cell: td,
                            column: column
                        });
                    }
                };
                that.content.on('focusin' + NS, function () {
                    clearTimeout(that.timer);
                    that.timer = null;
                }).on('focusout' + NS, function () {
                    that.timer = setTimeout(finishEdit, 1);
                }).on('keydown' + NS, function (e) {
                    if (e.keyCode === keys.ENTER) {
                        e.preventDefault();
                    }
                }).on('keyup' + NS, function (e) {
                    var key = e.keyCode;
                    var cell;
                    var model;
                    switch (key) {
                    case keys.ENTER:
                        blurActiveElement();
                        finishEdit();
                        break;
                    case keys.ESC:
                        if (that.editable) {
                            cell = that._editableContainer;
                            model = that._modelFromElement(cell);
                            if (!that.trigger('cancel', {
                                    model: model,
                                    cell: cell
                                })) {
                                that._closeCell(true);
                            }
                        }
                        break;
                    }
                });
                if (!mobileOS) {
                    that.content.on('mousedown' + NS, 'td', function (e) {
                        mousedown(e);
                    }).on('dblclick' + NS, 'td', function (e) {
                        if (!$(e.target).is(iconSelector)) {
                            that._startEditHandler(e);
                        }
                    });
                } else {
                    that.touch = that.content.kendoTouch({
                        filter: 'td',
                        touchstart: function (e) {
                            mousedown(e.touch);
                        },
                        doubletap: function (e) {
                            if (!$(e.touch.initialTouch).is(iconSelector)) {
                                that._startEditHandler(e.touch);
                            }
                        }
                    }).data('kendoTouch');
                }
            },
            _editCell: function (options) {
                var resourcesField = this.options.resourcesField;
                var listStyles = GanttList.styles;
                var cell = options.cell;
                var column = options.column;
                var model = this._modelFromElement(cell);
                var modelCopy = this.dataSource._createNewModel(model.toJSON());
                var field = modelCopy.fields[column.field] || modelCopy[column.field];
                var validation = field.validation;
                var DATATYPE = kendo.attr('type');
                var BINDING = kendo.attr('bind');
                var FORMAT = kendo.attr('format');
                var attr = {
                    'name': column.field,
                    'required': field.validation ? field.validation.required === true : false
                };
                var editor;
                if (column.field === resourcesField) {
                    column.editor(cell, modelCopy);
                    return;
                }
                this._editableContent = cell.children().detach();
                this._editableContainer = cell;
                cell.data('modelCopy', modelCopy);
                if ((field.type === 'date' || $.type(field) === 'date') && (!column.format || /H|m|s|F|g|u/.test(column.format))) {
                    attr[BINDING] = 'value:' + column.field;
                    attr[DATATYPE] = 'date';
                    if (column.format) {
                        attr[FORMAT] = kendo._extractFormat(column.format);
                    }
                    editor = function (container, options) {
                        $('<input type="text"/>').attr(attr).appendTo(container).kendoDateTimePicker({ format: options.format });
                    };
                }
                this.editable = cell.addClass(listStyles.editCell).kendoEditable({
                    fields: {
                        field: column.field,
                        format: column.format,
                        editor: column.editor || editor
                    },
                    model: modelCopy,
                    clearContainer: false
                }).data('kendoEditable');
                if (validation && validation.dateCompare && isFunction(validation.dateCompare) && validation.message) {
                    $('<span ' + kendo.attr('for') + '="' + column.field + '" class="k-invalid-msg"/>').hide().appendTo(cell);
                    cell.find('[name=' + column.field + ']').attr(kendo.attr('dateCompare-msg'), validation.message);
                }
                this.editable.bind('validate', function (e) {
                    var focusable = this.element.find(':kendoFocusable:first').focus();
                    if (oldIE) {
                        focusable.focus();
                    }
                    e.preventDefault();
                });
                if (this.trigger('edit', {
                        model: model,
                        cell: cell
                    })) {
                    this._closeCell(true);
                }
            },
            _closeCell: function (cancelUpdate) {
                var listStyles = GanttList.styles;
                var cell = this._editableContainer;
                var model = this._modelFromElement(cell);
                var column = this._columnFromElement(cell);
                var field = column.field;
                var copy = cell.data('modelCopy');
                var taskInfo = {};
                taskInfo[field] = copy.get(field);
                cell.empty().removeData('modelCopy').removeClass(listStyles.editCell).append(this._editableContent);
                this.editable.unbind();
                this.editable.destroy();
                this.editable = null;
                this._editableContainer = null;
                this._editableContent = null;
                if (!cancelUpdate) {
                    if (field === 'start') {
                        taskInfo.end = new Date(taskInfo.start.getTime() + model.duration());
                    }
                    this.trigger('update', {
                        task: model,
                        updateInfo: taskInfo
                    });
                }
            },
            _draggable: function () {
                var that = this;
                var draggedTask = null;
                var dropAllowed = true;
                var dropTarget;
                var listStyles = GanttList.styles;
                var isRtl = kendo.support.isRtl(this.element);
                var selector = 'tr[' + kendo.attr('level') + ' = 0]:last';
                var action = {};
                var editable = this.options.editable;
                var clear = function () {
                    draggedTask = null;
                    dropTarget = null;
                    dropAllowed = true;
                    action = {};
                };
                var allowDrop = function (task) {
                    var parent = task;
                    while (parent) {
                        if (draggedTask.get('id') === parent.get('id')) {
                            dropAllowed = false;
                            break;
                        }
                        parent = that.dataSource.taskParent(parent);
                    }
                };
                var defineLimits = function () {
                    var height = $(dropTarget).height();
                    var offsetTop = kendo.getOffset(dropTarget).top;
                    extend(dropTarget, {
                        beforeLimit: offsetTop + height * 0.25,
                        afterLimit: offsetTop + height * 0.75
                    });
                };
                var defineAction = function (coordinate) {
                    if (!dropTarget) {
                        return;
                    }
                    var location = coordinate.location;
                    var className = listStyles.dropAdd;
                    var command = 'add';
                    var level = parseInt(dropTarget.attr(kendo.attr('level')), 10);
                    var sibling;
                    if (location <= dropTarget.beforeLimit) {
                        sibling = dropTarget.prev();
                        className = listStyles.dropTop;
                        command = 'insert-before';
                    } else if (location >= dropTarget.afterLimit) {
                        sibling = dropTarget.next();
                        className = listStyles.dropBottom;
                        command = 'insert-after';
                    }
                    if (sibling && parseInt(sibling.attr(kendo.attr('level')), 10) === level) {
                        className = listStyles.dropMiddle;
                    }
                    action.className = className;
                    action.command = command;
                };
                var status = function () {
                    return that._reorderDraggable.hint.children(DOT + listStyles.dragStatus).removeClass(listStyles.dropPositions);
                };
                if (!editable || editable.reorder === false || editable.update === false) {
                    return;
                }
                this._reorderDraggable = this.content.kendoDraggable({
                    distance: 10,
                    holdToDrag: mobileOS,
                    group: 'listGroup',
                    filter: 'tr[data-uid]',
                    ignore: DOT + listStyles.input,
                    hint: function (target) {
                        return $('<div class="' + listStyles.header + ' ' + listStyles.dragClue + '"/>').css({
                            width: 300,
                            paddingLeft: target.css('paddingLeft'),
                            paddingRight: target.css('paddingRight'),
                            lineHeight: target.height() + 'px',
                            paddingTop: target.css('paddingTop'),
                            paddingBottom: target.css('paddingBottom')
                        }).append('<span class="' + listStyles.icon + ' ' + listStyles.dragStatus + '" /><span class="' + listStyles.dragClueText + '"/>');
                    },
                    cursorOffset: {
                        top: -20,
                        left: 0
                    },
                    container: this.content,
                    'dragstart': function (e) {
                        var editable = that.editable;
                        if (editable && editable.reorder !== false && editable.trigger('validate')) {
                            e.preventDefault();
                            return;
                        }
                        draggedTask = that._modelFromElement(e.currentTarget);
                        this.hint.children(DOT + listStyles.dragClueText).text(draggedTask.get('title'));
                        if (isRtl) {
                            this.hint.addClass(listStyles.rtl);
                        }
                    },
                    'drag': function (e) {
                        if (dropAllowed) {
                            defineAction(e.y);
                            status().addClass(action.className);
                        }
                    },
                    'dragend': function () {
                        clear();
                    },
                    'dragcancel': function () {
                        clear();
                    }
                }).data('kendoDraggable');
                this._tableDropArea = this.content.kendoDropTargetArea({
                    distance: 0,
                    group: 'listGroup',
                    filter: 'tr[data-uid]',
                    'dragenter': function (e) {
                        dropTarget = e.dropTarget;
                        allowDrop(that._modelFromElement(dropTarget));
                        defineLimits();
                        status().toggleClass(listStyles.dropDenied, !dropAllowed);
                    },
                    'dragleave': function () {
                        dropAllowed = true;
                        status();
                    },
                    'drop': function () {
                        var target = that._modelFromElement(dropTarget);
                        var orderId = target.orderId;
                        var taskInfo = { parentId: target.parentId };
                        if (dropAllowed) {
                            switch (action.command) {
                            case 'add':
                                taskInfo.parentId = target.id;
                                break;
                            case 'insert-before':
                                if (target.parentId === draggedTask.parentId && target.orderId > draggedTask.orderId) {
                                    taskInfo.orderId = orderId - 1;
                                } else {
                                    taskInfo.orderId = orderId;
                                }
                                break;
                            case 'insert-after':
                                if (target.parentId === draggedTask.parentId && target.orderId > draggedTask.orderId) {
                                    taskInfo.orderId = orderId;
                                } else {
                                    taskInfo.orderId = orderId + 1;
                                }
                                break;
                            }
                            that.trigger('update', {
                                task: draggedTask,
                                updateInfo: taskInfo
                            });
                        }
                    }
                }).data('kendoDropTargetArea');
                this._contentDropArea = this.element.kendoDropTargetArea({
                    distance: 0,
                    group: 'listGroup',
                    filter: DOT + listStyles.gridContent,
                    'drop': function () {
                        var target = that._modelFromElement(that.content.find(selector));
                        var orderId = target.orderId;
                        var taskInfo = {
                            parentId: null,
                            orderId: draggedTask.parentId !== null ? orderId + 1 : orderId
                        };
                        that.trigger('update', {
                            task: draggedTask,
                            updateInfo: taskInfo
                        });
                    }
                }).data('kendoDropTargetArea');
            },
            _resizable: function () {
                var that = this;
                var listStyles = GanttList.styles;
                var positionResizeHandle = function (e) {
                    var th = $(e.currentTarget);
                    var resizeHandle = that.resizeHandle;
                    var position = th.position();
                    var left = position.left;
                    var cellWidth = outerWidth(th);
                    var container = th.closest('div');
                    var clientX = e.clientX + $(window).scrollLeft();
                    var indicatorWidth = that.options.columnResizeHandleWidth;
                    left += container.scrollLeft();
                    if (!resizeHandle) {
                        resizeHandle = that.resizeHandle = $('<div class="' + listStyles.resizeHandle + '"><div class="' + listStyles.resizeHandleInner + '" /></div>');
                    }
                    var cellOffset = th.offset().left + cellWidth;
                    var show = clientX > cellOffset - indicatorWidth && clientX < cellOffset + indicatorWidth;
                    if (!show) {
                        resizeHandle.hide();
                        return;
                    }
                    container.append(resizeHandle);
                    resizeHandle.show().css({
                        top: position.top,
                        left: left + cellWidth - indicatorWidth - 1,
                        height: outerHeight(th),
                        width: indicatorWidth * 3
                    }).data('th', th);
                };
                if (!this.options.resizable) {
                    return;
                }
                if (this._columnResizable) {
                    this._columnResizable.destroy();
                }
                this.header.find('thead').on('mousemove' + NS, 'th', positionResizeHandle);
                this._columnResizable = this.header.kendoResizable({
                    handle: DOT + listStyles.resizeHandle,
                    start: function (e) {
                        var th = $(e.currentTarget).data('th');
                        var colSelector = 'col:eq(' + th.index() + ')';
                        var header = that.header.find('table');
                        var contentTable = that.content.find('table');
                        that.element.addClass('k-grid-column-resizing');
                        this.col = contentTable.children('colgroup').find(colSelector).add(header.find(colSelector));
                        this.th = th;
                        this.startLocation = e.x.location;
                        this.columnWidth = outerWidth(th);
                        this.table = header.add(contentTable);
                        this.totalWidth = this.table.width() - outerWidth(header.find('th:last'));
                    },
                    resize: function (e) {
                        var minColumnWidth = 11;
                        var delta = e.x.location - this.startLocation;
                        if (this.columnWidth + delta < minColumnWidth) {
                            delta = minColumnWidth - this.columnWidth;
                        }
                        this.table.css({ 'minWidth': this.totalWidth + delta });
                        this.col.width(this.columnWidth + delta);
                    },
                    resizeend: function () {
                        that.element.removeClass('k-grid-column-resizing');
                        var oldWidth = Math.floor(this.columnWidth);
                        var newWidth = Math.floor(outerWidth(this.th));
                        var column = that.columns[this.th.index()];
                        that.trigger('columnResize', {
                            column: column,
                            oldWidth: oldWidth,
                            newWidth: newWidth
                        });
                        this.table = this.col = this.th = null;
                    }
                }).data('kendoResizable');
            },
            _modelFromElement: function (element) {
                var row = element.closest('tr');
                var model = this.dataSource.getByUid(row.attr(kendo.attr('uid')));
                return model;
            },
            _columnFromElement: function (element) {
                var td = element.closest('td');
                var tr = td.parent();
                var idx = tr.children().index(td);
                return this.columns[idx];
            }
        });
        extend(true, ui.GanttList, { styles: listStyles });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.gantt.timeline', [
        'kendo.dom',
        'kendo.touch',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'gantt.timeline',
        name: 'Gantt Timeline',
        category: 'web',
        description: 'The Gantt Timeline',
        depends: [
            'dom',
            'touch',
            'draganddrop'
        ],
        hidden: true
    };
    (function ($) {
        var Widget = kendo.ui.Widget;
        var kendoDomElement = kendo.dom.element;
        var kendoTextElement = kendo.dom.text;
        var kendoHtmlElement = kendo.dom.html;
        var isPlainObject = $.isPlainObject;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var extend = $.extend;
        var proxy = $.proxy;
        var browser = kendo.support.browser;
        var isRtl = false;
        var keys = kendo.keys;
        var Query = kendo.data.Query;
        var STRING = 'string';
        var NS = '.kendoGanttTimeline';
        var CLICK = 'click';
        var DBLCLICK = 'dblclick';
        var MOUSEMOVE = 'mousemove';
        var MOUSEENTER = 'mouseenter';
        var MOUSELEAVE = 'mouseleave';
        var KEYDOWN = 'keydown';
        var DOT = '.';
        var TIME_HEADER_TEMPLATE = kendo.template('#=kendo.toString(start, \'t\')#');
        var DAY_HEADER_TEMPLATE = kendo.template('#=kendo.toString(start, \'ddd M/dd\')#');
        var WEEK_HEADER_TEMPLATE = kendo.template('#=kendo.toString(start, \'ddd M/dd\')# - #=kendo.toString(kendo.date.addDays(end, -1), \'ddd M/dd\')#');
        var MONTH_HEADER_TEMPLATE = kendo.template('#=kendo.toString(start, \'MMM\')#');
        var YEAR_HEADER_TEMPLATE = kendo.template('#=kendo.toString(start, \'yyyy\')#');
        var RESIZE_HINT = kendo.template('<div class="#=styles.marquee#">' + '<div class="#=styles.marqueeColor#"></div>' + '</div>');
        var RESIZE_TOOLTIP_TEMPLATE = kendo.template('<div style="z-index: 100002;" class="#=styles.tooltipWrapper#">' + '<div class="#=styles.tooltipContent#">' + '<div>#=messages.start#: #=kendo.toString(start, format)#</div>' + '<div>#=messages.end#: #=kendo.toString(end, format)#</div>' + '</div>' + '</div>');
        var PERCENT_RESIZE_TOOLTIP_TEMPLATE = kendo.template('<div style="z-index: 100002;" class="#=styles.tooltipWrapper#" >' + '<div class="#=styles.tooltipContent#">#=text#%</div>' + '<div class="#=styles.tooltipCallout#" style="left:13px;"></div>' + '</div>');
        var TASK_TOOLTIP_TEMPLATE = kendo.template('<div class="#=kendo.htmlEncode(styles.taskDetails)#">' + '<strong>#=kendo.htmlEncode(task.title)#</strong>' + '<div class="#=styles.taskDetailsPercent#">#=kendo.toString(task.percentComplete, "p0")#</div>' + '<ul class="#=styles.reset#">' + '<li>#=messages.start#: #=kendo.toString(task.start, "h:mm tt ddd, MMM d")#</li>' + '<li>#=messages.end#: #=kendo.toString(task.end, "h:mm tt ddd, MMM d")#</li>' + '</ul>' + '</div>');
        var SIZE_CALCULATION_TEMPLATE = '<table style=\'visibility: hidden;\'>' + '<tbody>' + '<tr style=\'height:{0}\'>' + '<td>&nbsp;</td>' + '</tr>' + '</tbody>' + '</table>';
        var defaultViews = {
            day: { type: 'kendo.ui.GanttDayView' },
            week: { type: 'kendo.ui.GanttWeekView' },
            month: { type: 'kendo.ui.GanttMonthView' },
            year: { type: 'kendo.ui.GanttYearView' }
        };
        function trimOptions(options) {
            delete options.name;
            delete options.prefix;
            delete options.views;
            return options;
        }
        function getWorkDays(options) {
            var workDays = [];
            var dayIndex = options.workWeekStart;
            workDays.push(dayIndex);
            while (options.workWeekEnd != dayIndex) {
                if (dayIndex > 6) {
                    dayIndex -= 7;
                } else {
                    dayIndex++;
                }
                workDays.push(dayIndex);
            }
            return workDays;
        }
        function blurActiveElement() {
            var activeElement = kendo._activeElement();
            if (activeElement && activeElement.nodeName.toLowerCase() !== 'body') {
                $(activeElement).blur();
            }
        }
        var viewStyles = {
            alt: 'k-alt',
            reset: 'k-reset',
            nonWorking: 'k-nonwork-hour',
            header: 'k-header',
            gridHeader: 'k-grid-header',
            gridHeaderWrap: 'k-grid-header-wrap',
            gridContent: 'k-grid-content',
            tasksWrapper: 'k-gantt-tables',
            rowsTable: 'k-gantt-rows',
            columnsTable: 'k-gantt-columns',
            tasksTable: 'k-gantt-tasks',
            dependenciesWrapper: 'k-gantt-dependencies',
            resource: 'k-resource',
            resourceAlt: 'k-resource k-alt',
            task: 'k-task',
            taskSingle: 'k-task-single',
            taskMilestone: 'k-task-milestone',
            taskSummary: 'k-task-summary',
            taskWrap: 'k-task-wrap',
            taskMilestoneWrap: 'k-milestone-wrap',
            resourcesWrap: 'k-resources-wrap',
            taskDot: 'k-task-dot',
            taskDotStart: 'k-task-start',
            taskDotEnd: 'k-task-end',
            taskDragHandle: 'k-task-draghandle',
            taskContent: 'k-task-content',
            taskTemplate: 'k-task-template',
            taskActions: 'k-task-actions',
            taskDelete: 'k-task-delete',
            taskComplete: 'k-task-complete',
            taskDetails: 'k-task-details',
            taskDetailsPercent: 'k-task-pct',
            link: 'k-link',
            icon: 'k-icon',
            iconDelete: 'k-i-close',
            taskResizeHandle: 'k-resize-handle',
            taskResizeHandleWest: 'k-resize-w',
            taskResizeHandleEast: 'k-resize-e',
            taskSummaryProgress: 'k-task-summary-progress',
            taskSummaryComplete: 'k-task-summary-complete',
            line: 'k-line',
            lineHorizontal: 'k-line-h',
            lineVertical: 'k-line-v',
            arrowWest: 'k-arrow-w',
            arrowEast: 'k-arrow-e',
            dragHint: 'k-drag-hint',
            dependencyHint: 'k-dependency-hint',
            tooltipWrapper: 'k-widget k-tooltip k-popup k-group k-reset',
            tooltipContent: 'k-tooltip-content',
            tooltipCallout: 'k-callout k-callout-s',
            callout: 'k-callout',
            marquee: 'k-marquee k-gantt-marquee',
            marqueeColor: 'k-marquee-color'
        };
        var GanttView = kendo.ui.GanttView = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.title = this.options.title || this.options.name;
                this.header = this.element.find(DOT + GanttView.styles.gridHeader);
                this.content = this.element.find(DOT + GanttView.styles.gridContent);
                this.contentWidth = this.content.width();
                this._workDays = getWorkDays(this.options);
                this._headerTree = options.headerTree;
                this._taskTree = options.taskTree;
                this._taskTemplate = options.taskTemplate ? kendo.template(options.taskTemplate, extend({}, kendo.Template, options.templateSettings)) : null;
                this._dependencyTree = options.dependencyTree;
                this._taskCoordinates = {};
                this._currentTime();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                clearTimeout(this._tooltipTimeout);
                this.headerRow = null;
                this.header = null;
                this.content = null;
                this._dragHint = null;
                this._resizeHint = null;
                this._resizeTooltip = null;
                this._taskTooltip = null;
                this._percentCompleteResizeTooltip = null;
                this._headerTree = null;
                this._taskTree = null;
                this._dependencyTree = null;
            },
            options: {
                showWorkHours: false,
                showWorkDays: false,
                workDayStart: new Date(1980, 1, 1, 8, 0, 0),
                workDayEnd: new Date(1980, 1, 1, 17, 0, 0),
                workWeekStart: 1,
                workWeekEnd: 5,
                hourSpan: 1,
                slotSize: 100,
                currentTimeMarker: { updateInterval: 10000 }
            },
            renderLayout: function () {
                this._slots = this._createSlots();
                this._tableWidth = this._calculateTableWidth();
                this.createLayout(this._layout());
                this._slotDimensions();
                this._adjustHeight();
                this.content.find(DOT + GanttView.styles.dependenciesWrapper).width(this._tableWidth);
            },
            _adjustHeight: function () {
                if (this.content) {
                    this.content.height(this.element.height() - outerHeight(this.header));
                }
            },
            createLayout: function (rows) {
                var headers = this._headers(rows);
                var colgroup = this._colgroup();
                var tree = this._headerTree;
                var header = kendoDomElement('thead', null, headers);
                var table = kendoDomElement('table', { style: { width: this._tableWidth + 'px' } }, [
                    colgroup,
                    header
                ]);
                tree.render([table]);
                this.headerRow = this.header.find('table:first tr').last();
            },
            _slotDimensions: function () {
                var headers = this.headerRow[0].children;
                var slots = this._timeSlots();
                var slot;
                var header;
                for (var i = 0, length = headers.length; i < length; i++) {
                    header = headers[i];
                    slot = slots[i];
                    slot.offsetLeft = header.offsetLeft;
                    slot.offsetWidth = header.offsetWidth;
                }
            },
            render: function (tasks) {
                var taskCount = tasks.length;
                var styles = GanttView.styles;
                var contentTable;
                var rowsTable = this._rowsTable(taskCount);
                var columnsTable = this._columnsTable(taskCount);
                var tasksTable = this._tasksTable(tasks);
                var currentTimeMarker = this.options.currentTimeMarker;
                var calculatedSize = this.options.calculatedSize;
                var totalHeight;
                this._taskTree.render([
                    rowsTable,
                    columnsTable,
                    tasksTable
                ]);
                contentTable = this.content.find(DOT + styles.rowsTable);
                if (calculatedSize) {
                    totalHeight = calculatedSize.row * tasks.length;
                    this.content.find(DOT + styles.tasksTable).height(totalHeight);
                    contentTable.height(totalHeight);
                }
                this._contentHeight = contentTable.height();
                this._rowHeight = calculatedSize ? calculatedSize.row : this._contentHeight / contentTable.find('tr').length;
                this.content.find(DOT + styles.columnsTable).height(this._contentHeight);
                if (currentTimeMarker !== false && currentTimeMarker.updateInterval !== undefined) {
                    this._renderCurrentTime();
                }
            },
            _rowsTable: function (rowCount) {
                var rows = [];
                var row;
                var styles = GanttView.styles;
                var attributes = [
                    null,
                    { className: styles.alt }
                ];
                for (var i = 0; i < rowCount; i++) {
                    row = kendoDomElement('tr', attributes[i % 2], [kendoDomElement('td', null, [kendoTextElement('\xA0')])]);
                    rows.push(row);
                }
                return this._createTable(1, rows, { className: styles.rowsTable });
            },
            _columnsTable: function () {
                var cells = [];
                var row;
                var styles = GanttView.styles;
                var slots = this._timeSlots();
                var slotsCount = slots.length;
                var slot;
                var slotSpan;
                var totalSpan = 0;
                var attributes;
                for (var i = 0; i < slotsCount; i++) {
                    slot = slots[i];
                    attributes = {};
                    slotSpan = slot.span;
                    totalSpan += slotSpan;
                    if (slotSpan !== 1) {
                        attributes.colspan = slotSpan;
                    }
                    if (slot.isNonWorking) {
                        attributes.className = styles.nonWorking;
                    }
                    cells.push(kendoDomElement('td', attributes, [kendoTextElement('\xA0')]));
                }
                row = kendoDomElement('tr', null, cells);
                return this._createTable(totalSpan, [row], { className: styles.columnsTable });
            },
            _tasksTable: function (tasks) {
                var rows = [];
                var row;
                var cell;
                var position;
                var task;
                var styles = GanttView.styles;
                var coordinates = this._taskCoordinates = {};
                var size = this._calculateMilestoneWidth();
                var milestoneWidth = Math.round(size.width);
                var resourcesField = this.options.resourcesField;
                var className = [
                    styles.resource,
                    styles.resourceAlt
                ];
                var calculatedSize = this.options.calculatedSize;
                var resourcesPosition;
                var resourcesMargin = this._calculateResourcesMargin();
                var taskBorderWidth = this._calculateTaskBorderWidth();
                var resourceStyle;
                var addCoordinates = function (rowIndex) {
                    var taskLeft;
                    var taskRight;
                    taskLeft = position.left;
                    taskRight = taskLeft + position.width;
                    if (task.isMilestone()) {
                        taskLeft -= milestoneWidth / 2;
                        taskRight = taskLeft + milestoneWidth;
                    }
                    coordinates[task.id] = {
                        start: taskLeft,
                        end: taskRight,
                        rowIndex: rowIndex
                    };
                };
                for (var i = 0, l = tasks.length; i < l; i++) {
                    task = tasks[i];
                    position = this._taskPosition(task);
                    position.borderWidth = taskBorderWidth;
                    row = kendoDomElement('tr', null);
                    cell = kendoDomElement('td');
                    if (task.start <= this.end && task.end >= this.start) {
                        cell.children.push(this._renderTask(tasks[i], position));
                        if (task[resourcesField] && task[resourcesField].length) {
                            if (isRtl) {
                                resourcesPosition = this._tableWidth - position.left;
                            } else {
                                resourcesPosition = Math.max(position.width || size.clientWidth, 0) + position.left;
                            }
                            resourceStyle = { width: this._tableWidth - (resourcesPosition + resourcesMargin) + 'px' };
                            resourceStyle[isRtl ? 'right' : 'left'] = resourcesPosition + 'px';
                            if (calculatedSize) {
                                resourceStyle.height = calculatedSize.cell + 'px';
                            }
                            cell.children.push(kendoDomElement('div', {
                                className: styles.resourcesWrap,
                                style: resourceStyle
                            }, this._renderResources(task[resourcesField], className[i % 2])));
                        }
                        addCoordinates(i);
                    }
                    row.children.push(cell);
                    rows.push(row);
                }
                return this._createTable(1, rows, { className: GanttView.styles.tasksTable });
            },
            _createTable: function (colspan, rows, styles) {
                var cols = [];
                var colgroup;
                var tbody;
                for (var i = 0; i < colspan; i++) {
                    cols.push(kendoDomElement('col'));
                }
                colgroup = kendoDomElement('colgroup', null, cols);
                tbody = kendoDomElement('tbody', null, rows);
                if (!styles.style) {
                    styles.style = {};
                }
                styles.style.width = this._tableWidth + 'px';
                return kendoDomElement('table', styles, [
                    colgroup,
                    tbody
                ]);
            },
            _calculateTableWidth: function () {
                var slots = this._timeSlots();
                var maxSpan = 0;
                var totalSpan = 0;
                var currentSpan;
                var tableWidth;
                for (var i = 0, length = slots.length; i < length; i++) {
                    currentSpan = slots[i].span;
                    totalSpan += currentSpan;
                    if (currentSpan > maxSpan) {
                        maxSpan = currentSpan;
                    }
                }
                tableWidth = Math.round(totalSpan * this.options.slotSize / maxSpan);
                return tableWidth;
            },
            _calculateMilestoneWidth: function () {
                var size;
                var className = GanttView.styles.task + ' ' + GanttView.styles.taskMilestone;
                var milestone = $('<div class=\'' + className + '\' style=\'visibility: hidden; position: absolute\'>');
                var boundingClientRect;
                this.content.append(milestone);
                boundingClientRect = milestone[0].getBoundingClientRect();
                size = {
                    'width': boundingClientRect.right - boundingClientRect.left,
                    'clientWidth': milestone[0].clientWidth
                };
                milestone.remove();
                return size;
            },
            _calculateResourcesMargin: function () {
                var margin;
                var wrapper = $('<div class=\'' + GanttView.styles.resourcesWrap + '\' style=\'visibility: hidden; position: absolute\'>');
                this.content.append(wrapper);
                margin = parseInt(wrapper.css(isRtl ? 'margin-right' : 'margin-left'), 10);
                wrapper.remove();
                return margin;
            },
            _calculateTaskBorderWidth: function () {
                var width;
                var className = GanttView.styles.task + ' ' + GanttView.styles.taskSingle;
                var task = $('<div class=\'' + className + '\' style=\'visibility: hidden; position: absolute\'>');
                var computedStyle;
                this.content.append(task);
                computedStyle = kendo.getComputedStyles(task[0], ['border-left-width']);
                width = parseFloat(computedStyle['border-left-width'], 10);
                task.remove();
                return width;
            },
            _renderTask: function (task, position) {
                var taskWrapper;
                var taskElement;
                var editable = this.options.editable;
                var progressHandleOffset;
                var taskLeft = position.left;
                var styles = GanttView.styles;
                var wrapClassName = styles.taskWrap;
                var calculatedSize = this.options.calculatedSize;
                var dragHandleStyle = {};
                var taskWrapAttr = {
                    className: wrapClassName,
                    style: { left: taskLeft + 'px' }
                };
                if (calculatedSize) {
                    taskWrapAttr.style.height = calculatedSize.cell + 'px';
                }
                if (task.summary) {
                    taskElement = this._renderSummary(task, position);
                } else if (task.isMilestone()) {
                    taskElement = this._renderMilestone(task, position);
                    taskWrapAttr.className += ' ' + styles.taskMilestoneWrap;
                } else {
                    taskElement = this._renderSingleTask(task, position);
                }
                taskWrapper = kendoDomElement('div', taskWrapAttr, [taskElement]);
                if (editable && editable.dependencyCreate !== false) {
                    taskWrapper.children.push(kendoDomElement('div', { className: styles.taskDot + ' ' + styles.taskDotStart }));
                    taskWrapper.children.push(kendoDomElement('div', { className: styles.taskDot + ' ' + styles.taskDotEnd }));
                }
                if (!task.summary && !task.isMilestone() && editable && editable.dragPercentComplete !== false && editable.update !== false && this._taskTemplate === null) {
                    progressHandleOffset = Math.round(position.width * task.percentComplete);
                    dragHandleStyle[isRtl ? 'right' : 'left'] = progressHandleOffset + 'px';
                    taskWrapper.children.push(kendoDomElement('div', {
                        className: styles.taskDragHandle,
                        style: dragHandleStyle
                    }));
                }
                return taskWrapper;
            },
            _renderSingleTask: function (task, position) {
                var styles = GanttView.styles;
                var progressWidth = Math.round(position.width * task.percentComplete);
                var taskChildren = [];
                var taskContent;
                var editable = this.options.editable;
                if (this._taskTemplate !== null) {
                    taskContent = kendoHtmlElement(this._taskTemplate(task));
                } else {
                    taskContent = kendoTextElement(task.title);
                    taskChildren.push(kendoDomElement('div', {
                        className: styles.taskComplete,
                        style: { width: progressWidth + 'px' }
                    }));
                }
                var content = kendoDomElement('div', { className: styles.taskContent }, [kendoDomElement('div', { className: styles.taskTemplate }, [taskContent])]);
                taskChildren.push(content);
                if (editable) {
                    if (editable.destroy !== false) {
                        content.children.push(kendoDomElement('span', { className: styles.taskActions }, [kendoDomElement('a', {
                                className: styles.link + ' ' + styles.taskDelete,
                                href: '#',
                                'aria-label': 'Delete'
                            }, [kendoDomElement('span', { className: styles.icon + ' ' + styles.iconDelete })])]));
                    }
                    if (editable.resize !== false && editable.update !== false) {
                        content.children.push(kendoDomElement('span', { className: styles.taskResizeHandle + ' ' + styles.taskResizeHandleWest }));
                        content.children.push(kendoDomElement('span', { className: styles.taskResizeHandle + ' ' + styles.taskResizeHandleEast }));
                    }
                }
                var element = kendoDomElement('div', {
                    className: styles.task + ' ' + styles.taskSingle,
                    'data-uid': task.uid,
                    style: { width: Math.max(position.width - position.borderWidth * 2, 0) + 'px' }
                }, taskChildren);
                return element;
            },
            _renderMilestone: function (task) {
                var styles = GanttView.styles;
                var element = kendoDomElement('div', {
                    className: styles.task + ' ' + styles.taskMilestone,
                    'data-uid': task.uid
                });
                return element;
            },
            _renderSummary: function (task, position) {
                var styles = GanttView.styles;
                var progressWidth = Math.round(position.width * task.percentComplete);
                var element = kendoDomElement('div', {
                    className: styles.task + ' ' + styles.taskSummary,
                    'data-uid': task.uid,
                    style: { width: position.width + 'px' }
                }, [kendoDomElement('div', {
                        className: styles.taskSummaryProgress,
                        style: { width: progressWidth + 'px' }
                    }, [kendoDomElement('div', {
                            className: styles.taskSummaryComplete,
                            style: { width: position.width + 'px' }
                        })])]);
                return element;
            },
            _renderResources: function (resources, className) {
                var children = [];
                var resource;
                for (var i = 0, length = resources.length; i < length; i++) {
                    resource = resources[i];
                    children.push(kendoDomElement('span', {
                        className: className,
                        style: { 'color': resource.get('color') }
                    }, [kendoTextElement(resource.get('name'))]));
                }
                if (isRtl) {
                    children.reverse();
                }
                return children;
            },
            _taskPosition: function (task) {
                var round = Math.round;
                var startLeft = round(this._offset(isRtl ? task.end : task.start));
                var endLeft = round(this._offset(isRtl ? task.start : task.end));
                return {
                    left: startLeft,
                    width: endLeft - startLeft
                };
            },
            _offset: function (date) {
                var slots = this._timeSlots();
                var slot;
                var startOffset;
                var slotDuration;
                var slotOffset = 0;
                var startIndex;
                if (!slots.length) {
                    return 0;
                }
                startIndex = this._slotIndex('start', date);
                slot = slots[startIndex];
                if (slot.end < date) {
                    slotOffset = slot.offsetWidth;
                } else if (slot.start <= date) {
                    startOffset = date - slot.start;
                    slotDuration = slot.end - slot.start;
                    slotOffset = startOffset / slotDuration * slot.offsetWidth;
                }
                if (isRtl) {
                    slotOffset = slot.offsetWidth + 1 - slotOffset;
                }
                return slot.offsetLeft + slotOffset;
            },
            _slotIndex: function (field, value, reverse) {
                var slots = this._timeSlots();
                var startIdx = 0;
                var endIdx = slots.length - 1;
                var middle;
                if (reverse) {
                    slots = [].slice.call(slots).reverse();
                }
                do {
                    middle = Math.ceil((endIdx + startIdx) / 2);
                    if (slots[middle][field] < value) {
                        startIdx = middle;
                    } else {
                        if (middle === endIdx) {
                            middle--;
                        }
                        endIdx = middle;
                    }
                } while (startIdx !== endIdx);
                if (reverse) {
                    startIdx = slots.length - 1 - startIdx;
                }
                return startIdx;
            },
            _timeByPosition: function (x, snap, snapToEnd) {
                var slot = this._slotByPosition(x);
                if (snap) {
                    return snapToEnd ? slot.end : slot.start;
                }
                var offsetLeft = x - $(DOT + GanttView.styles.tasksTable).offset().left;
                var duration = slot.end - slot.start;
                var slotOffset = offsetLeft - slot.offsetLeft;
                if (isRtl) {
                    slotOffset = slot.offsetWidth - slotOffset;
                }
                return new Date(slot.start.getTime() + duration * (slotOffset / slot.offsetWidth));
            },
            _slotByPosition: function (x) {
                var offsetLeft = x - $(DOT + GanttView.styles.tasksTable).offset().left;
                var slotIndex = this._slotIndex('offsetLeft', offsetLeft, isRtl);
                return this._timeSlots()[slotIndex];
            },
            _renderDependencies: function (dependencies) {
                var elements = [];
                var tree = this._dependencyTree;
                for (var i = 0, l = dependencies.length; i < l; i++) {
                    elements.push.apply(elements, this._renderDependency(dependencies[i]));
                }
                tree.render(elements);
            },
            _renderDependency: function (dependency) {
                var predecessor = this._taskCoordinates[dependency.predecessorId];
                var successor = this._taskCoordinates[dependency.successorId];
                var elements;
                var method;
                if (!predecessor || !successor) {
                    return [];
                }
                method = '_render' + [
                    'FF',
                    'FS',
                    'SF',
                    'SS'
                ][isRtl ? 3 - dependency.type : dependency.type];
                elements = this[method](predecessor, successor);
                for (var i = 0, length = elements.length; i < length; i++) {
                    elements[i].attr['data-uid'] = dependency.uid;
                }
                return elements;
            },
            _renderFF: function (from, to) {
                var lines = this._dependencyFF(from, to, false);
                lines[lines.length - 1].children[0] = this._arrow(true);
                return lines;
            },
            _renderSS: function (from, to) {
                var lines = this._dependencyFF(to, from, true);
                lines[0].children[0] = this._arrow(false);
                return lines.reverse();
            },
            _renderFS: function (from, to) {
                var lines = this._dependencyFS(from, to, false);
                lines[lines.length - 1].children[0] = this._arrow(false);
                return lines;
            },
            _renderSF: function (from, to) {
                var lines = this._dependencyFS(to, from, true);
                lines[0].children[0] = this._arrow(true);
                return lines.reverse();
            },
            _dependencyFF: function (from, to, reverse) {
                var that = this;
                var lines = [];
                var left = 0;
                var top = 0;
                var width = 0;
                var height = 0;
                var dir = reverse ? 'start' : 'end';
                var delta;
                var overlap = 2;
                var arrowOverlap = 1;
                var rowHeight = this._rowHeight;
                var minLineWidth = 10;
                var fromTop = from.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
                var toTop = to.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
                var styles = GanttView.styles;
                var addHorizontal = function () {
                    lines.push(that._line(styles.line + ' ' + styles.lineHorizontal, {
                        left: left + 'px',
                        top: top + 'px',
                        width: width + 'px'
                    }));
                };
                var addVertical = function () {
                    lines.push(that._line(styles.line + ' ' + styles.lineVertical, {
                        left: left + 'px',
                        top: top + 'px',
                        height: height + 'px'
                    }));
                };
                left = from[dir];
                top = fromTop;
                width = minLineWidth;
                delta = to[dir] - from[dir];
                if (delta > 0 !== reverse) {
                    width = Math.abs(delta) + minLineWidth;
                }
                if (reverse) {
                    left -= width;
                    width -= arrowOverlap;
                    addHorizontal();
                } else {
                    addHorizontal();
                    left += width - overlap;
                }
                if (toTop < top) {
                    height = top - toTop;
                    height += overlap;
                    top = toTop;
                    addVertical();
                } else {
                    height = toTop - top;
                    height += overlap;
                    addVertical();
                    top += height - overlap;
                }
                width = Math.abs(left - to[dir]);
                if (!reverse) {
                    width -= arrowOverlap;
                    left -= width;
                }
                addHorizontal();
                return lines;
            },
            _dependencyFS: function (from, to, reverse) {
                var that = this;
                var lines = [];
                var left = 0;
                var top = 0;
                var width = 0;
                var height = 0;
                var rowHeight = this._rowHeight;
                var minLineHeight = Math.floor(rowHeight / 2);
                var minLineWidth = 10;
                var minDistance = 2 * minLineWidth;
                var delta = to.start - from.end;
                var overlap = 2;
                var arrowOverlap = 1;
                var fromTop = from.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
                var toTop = to.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
                var styles = GanttView.styles;
                var addHorizontal = function () {
                    lines.push(that._line(styles.line + ' ' + styles.lineHorizontal, {
                        left: left + 'px',
                        top: top + 'px',
                        width: width + 'px'
                    }));
                };
                var addVertical = function () {
                    lines.push(that._line(styles.line + ' ' + styles.lineVertical, {
                        left: left + 'px',
                        top: top + 'px',
                        height: height + 'px'
                    }));
                };
                left = from.end;
                top = fromTop;
                width = minLineWidth;
                if (reverse) {
                    left += arrowOverlap;
                    if (delta > minDistance) {
                        width = delta - (minLineWidth - overlap);
                    }
                    width -= arrowOverlap;
                }
                addHorizontal();
                left += width - overlap;
                if (delta <= minDistance) {
                    height = reverse ? Math.abs(toTop - fromTop) - minLineHeight : minLineHeight;
                    if (toTop < fromTop) {
                        top -= height;
                        height += overlap;
                        addVertical();
                    } else {
                        addVertical();
                        top += height;
                    }
                    width = from.end - to.start + minDistance;
                    if (width < minLineWidth) {
                        width = minLineWidth;
                    }
                    left -= width - overlap;
                    addHorizontal();
                }
                if (toTop < fromTop) {
                    height = top - toTop;
                    top = toTop;
                    height += overlap;
                    addVertical();
                } else {
                    height = toTop - top;
                    addVertical();
                    top += height;
                }
                width = to.start - left;
                if (!reverse) {
                    width -= arrowOverlap;
                }
                addHorizontal();
                return lines;
            },
            _line: function (className, styles) {
                return kendoDomElement('div', {
                    className: className,
                    style: styles
                });
            },
            _arrow: function (direction) {
                return kendoDomElement('span', { className: direction ? GanttView.styles.arrowWest : GanttView.styles.arrowEast });
            },
            _colgroup: function () {
                var slots = this._timeSlots();
                var count = slots.length;
                var cols = [];
                for (var i = 0; i < count; i++) {
                    for (var j = 0, length = slots[i].span; j < length; j++) {
                        cols.push(kendoDomElement('col'));
                    }
                }
                return kendoDomElement('colgroup', null, cols);
            },
            _createDragHint: function (element) {
                this._dragHint = element.clone().addClass(GanttView.styles.dragHint).css('cursor', 'move');
                element.parent().append(this._dragHint);
            },
            _updateDragHint: function (start) {
                var left = this._offset(start);
                this._dragHint.css({ 'left': left });
            },
            _removeDragHint: function () {
                this._dragHint.remove();
                this._dragHint = null;
            },
            _createResizeHint: function (task) {
                var styles = GanttView.styles;
                var taskTop = this._taskCoordinates[task.id].rowIndex * this._rowHeight;
                var tooltipHeight;
                var tooltipTop;
                var options = this.options;
                var messages = options.messages;
                this._resizeHint = $(RESIZE_HINT({ styles: styles })).css({
                    'top': 0,
                    'height': this._contentHeight
                });
                this.content.append(this._resizeHint);
                this._resizeTooltip = $(RESIZE_TOOLTIP_TEMPLATE({
                    styles: styles,
                    start: task.start,
                    end: task.end,
                    messages: messages.views,
                    format: options.resizeTooltipFormat
                })).css({
                    'top': 0,
                    'left': 0
                });
                this.content.append(this._resizeTooltip);
                this._resizeTooltipWidth = outerWidth(this._resizeTooltip);
                tooltipHeight = outerHeight(this._resizeTooltip);
                tooltipTop = taskTop - tooltipHeight;
                if (tooltipTop < 0) {
                    tooltipTop = taskTop + this._rowHeight;
                }
                this._resizeTooltipTop = tooltipTop;
            },
            _updateResizeHint: function (start, end, resizeStart) {
                var left = this._offset(isRtl ? end : start);
                var right = this._offset(isRtl ? start : end);
                var width = right - left;
                var tooltipLeft = resizeStart !== isRtl ? left : right;
                var tablesWidth = this._tableWidth - kendo.support.scrollbar();
                var tooltipWidth = this._resizeTooltipWidth;
                var options = this.options;
                var messages = options.messages;
                var tableOffset = $(DOT + GanttView.styles.tasksTable).offset().left - $(DOT + GanttView.styles.tasksWrapper).offset().left;
                if (isRtl) {
                    left += tableOffset;
                }
                this._resizeHint.css({
                    'left': left,
                    'width': width
                });
                if (this._resizeTooltip) {
                    this._resizeTooltip.remove();
                }
                tooltipLeft -= Math.round(tooltipWidth / 2);
                if (tooltipLeft < 0) {
                    tooltipLeft = 0;
                } else if (tooltipLeft + tooltipWidth > tablesWidth) {
                    tooltipLeft = tablesWidth - tooltipWidth;
                }
                if (isRtl) {
                    tooltipLeft += tableOffset;
                }
                this._resizeTooltip = $(RESIZE_TOOLTIP_TEMPLATE({
                    styles: GanttView.styles,
                    start: start,
                    end: end,
                    messages: messages.views,
                    format: options.resizeTooltipFormat
                })).css({
                    'top': this._resizeTooltipTop,
                    'left': tooltipLeft,
                    'min-width': tooltipWidth
                }).appendTo(this.content);
            },
            _removeResizeHint: function () {
                this._resizeHint.remove();
                this._resizeHint = null;
                this._resizeTooltip.remove();
                this._resizeTooltip = null;
            },
            _updatePercentCompleteTooltip: function (top, left, text) {
                this._removePercentCompleteTooltip();
                var tooltip = this._percentCompleteResizeTooltip = $(PERCENT_RESIZE_TOOLTIP_TEMPLATE({
                    styles: GanttView.styles,
                    text: text
                })).appendTo(this.element);
                var tooltipMiddle = Math.round(outerWidth(tooltip) / 2);
                var arrow = tooltip.find(DOT + GanttView.styles.callout);
                var arrowHeight = Math.round(outerWidth(arrow) / 2);
                tooltip.css({
                    'top': top - (outerHeight(tooltip) + arrowHeight),
                    'left': left - tooltipMiddle
                });
                arrow.css('left', tooltipMiddle - arrowHeight);
            },
            _removePercentCompleteTooltip: function () {
                if (this._percentCompleteResizeTooltip) {
                    this._percentCompleteResizeTooltip.remove();
                }
                this._percentCompleteResizeTooltip = null;
            },
            _updateDependencyDragHint: function (from, to, useVML) {
                this._removeDependencyDragHint();
                if (useVML) {
                    this._creteVmlDependencyDragHint(from, to);
                } else {
                    this._creteDependencyDragHint(from, to);
                }
            },
            _creteDependencyDragHint: function (from, to) {
                var styles = GanttView.styles;
                var deltaX = to.x - from.x;
                var deltaY = to.y - from.y;
                var width = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
                var angle = Math.atan(deltaY / deltaX);
                if (deltaX < 0) {
                    angle += Math.PI;
                }
                $('<div class=\'' + styles.line + ' ' + styles.lineHorizontal + ' ' + styles.dependencyHint + '\'></div>').css({
                    'top': from.y,
                    'left': from.x,
                    'width': width,
                    'transform-origin': '0% 0',
                    '-ms-transform-origin': '0% 0',
                    '-webkit-transform-origin': '0% 0',
                    'transform': 'rotate(' + angle + 'rad)',
                    '-ms-transform': 'rotate(' + angle + 'rad)',
                    '-webkit-transform': 'rotate(' + angle + 'rad)'
                }).appendTo(this.content);
            },
            _creteVmlDependencyDragHint: function (from, to) {
                var hint = $('<kvml:line class=\'' + GanttView.styles.dependencyHint + '\' style=\'position:absolute; top: 0px; left: 0px;\' strokecolor=\'black\' strokeweight=\'2px\' from=\'' + from.x + 'px,' + from.y + 'px\' to=\'' + to.x + 'px,' + to.y + 'px\'' + '></kvml:line>').appendTo(this.content);
                hint[0].outerHTML = hint[0].outerHTML;
            },
            _removeDependencyDragHint: function () {
                this.content.find(DOT + GanttView.styles.dependencyHint).remove();
            },
            _createTaskTooltip: function (task, element, mouseLeft) {
                var styles = GanttView.styles;
                var options = this.options;
                var content = this.content;
                var contentOffset = content.offset();
                var contentWidth = content.width();
                var contentScrollLeft = kendo.scrollLeft(content);
                var row = $(element).parents('tr').first();
                var rowOffset = row.offset();
                var template = options.tooltip && options.tooltip.template ? kendo.template(options.tooltip.template) : TASK_TOOLTIP_TEMPLATE;
                var left = isRtl ? mouseLeft - (contentOffset.left + contentScrollLeft + kendo.support.scrollbar()) : mouseLeft - (contentOffset.left - contentScrollLeft);
                var top = rowOffset.top + outerHeight(row) - contentOffset.top + content.scrollTop();
                var tooltip = this._taskTooltip = $('<div style="z-index: 100002;" class="' + styles.tooltipWrapper + '" >' + '<div class="' + styles.taskContent + '"></div></div>');
                var tooltipWidth;
                tooltip.css({
                    'left': left,
                    'top': top
                }).appendTo(content).find(DOT + styles.taskContent).append(template({
                    styles: styles,
                    task: task,
                    messages: options.messages.views
                }));
                if (outerHeight(tooltip) < rowOffset.top - contentOffset.top) {
                    tooltip.css('top', rowOffset.top - contentOffset.top - outerHeight(tooltip) + content.scrollTop());
                }
                tooltipWidth = outerWidth(tooltip);
                if (tooltipWidth + left - contentScrollLeft > contentWidth) {
                    left -= tooltipWidth;
                    if (left < contentScrollLeft) {
                        left = contentScrollLeft + contentWidth - (tooltipWidth + 17);
                    }
                    tooltip.css('left', left);
                }
            },
            _removeTaskTooltip: function () {
                if (this._taskTooltip) {
                    this._taskTooltip.remove();
                }
                this._taskTooltip = null;
            },
            _scrollTo: function (element) {
                var elementLeft = element.offset().left;
                var elementWidth = element.width();
                var elementRight = elementLeft + elementWidth;
                var row = element.closest('tr');
                var rowTop = row.offset().top;
                var rowHeight = row.height();
                var rowBottom = rowTop + rowHeight;
                var content = this.content;
                var contentOffset = content.offset();
                var contentTop = contentOffset.top;
                var contentHeight = content.height();
                var contentBottom = contentTop + contentHeight;
                var contentLeft = contentOffset.left;
                var contentWidth = content.width();
                var contentRight = contentLeft + contentWidth;
                var scrollbarWidth = kendo.support.scrollbar();
                if (rowTop < contentTop) {
                    content.scrollTop(content.scrollTop() + (rowTop - contentTop));
                } else if (rowBottom > contentBottom) {
                    content.scrollTop(content.scrollTop() + (rowBottom + scrollbarWidth - contentBottom));
                }
                if (elementLeft < contentLeft && elementWidth > contentWidth && elementRight < contentRight || elementRight > contentRight && elementWidth < contentWidth) {
                    content.scrollLeft(content.scrollLeft() + (elementRight + scrollbarWidth - contentRight));
                } else if (elementRight > contentRight && elementWidth > contentWidth && elementLeft > contentLeft || elementLeft < contentLeft && elementWidth < contentWidth) {
                    content.scrollLeft(content.scrollLeft() + (elementLeft - contentLeft));
                }
            },
            _scrollToDate: function (date) {
                var viewStart = this.start;
                var viewEnd = this.end;
                var offset;
                if (date >= viewStart && date < viewEnd) {
                    offset = this._offset(date);
                    if (kendo.support.isRtl(this.element)) {
                        offset = this._tableWidth - offset;
                    }
                    kendo.scrollLeft(this.content, offset);
                }
            },
            _timeSlots: function () {
                if (!this._slots || !this._slots.length) {
                    return [];
                }
                return this._slots[this._slots.length - 1];
            },
            _headers: function (columnLevels) {
                var rows = [];
                var level;
                var headers;
                var column;
                var headerText;
                var styles = GanttView.styles;
                for (var levelIndex = 0, levelCount = columnLevels.length; levelIndex < levelCount; levelIndex++) {
                    level = columnLevels[levelIndex];
                    headers = [];
                    for (var columnIndex = 0, columnCount = level.length; columnIndex < columnCount; columnIndex++) {
                        column = level[columnIndex];
                        headerText = kendoHtmlElement(column.text);
                        headers.push(kendoDomElement('th', {
                            colspan: column.span,
                            className: styles.header + (column.isNonWorking ? ' ' + styles.nonWorking : '')
                        }, [headerText]));
                    }
                    rows.push(kendoDomElement('tr', null, headers));
                }
                return rows;
            },
            _hours: function (start, end) {
                var slotEnd;
                var slots = [];
                var options = this.options;
                var workDayStart = options.workDayStart.getHours();
                var workDayEnd = options.workDayEnd.getHours();
                var isWorkHour;
                var hours;
                var hourSpan = options.hourSpan;
                start = new Date(start);
                end = new Date(end);
                if (options.showWorkHours) {
                    start.setHours(workDayStart);
                }
                while (start < end) {
                    slotEnd = new Date(start);
                    hours = slotEnd.getHours();
                    isWorkHour = hours >= workDayStart && hours < workDayEnd;
                    slotEnd.setHours(slotEnd.getHours() + hourSpan);
                    if (hours == slotEnd.getHours()) {
                        slotEnd.setHours(slotEnd.getHours() + 2 * hourSpan);
                    }
                    if (!options.showWorkHours || isWorkHour) {
                        slots.push({
                            start: start,
                            end: slotEnd,
                            isNonWorking: !isWorkHour,
                            span: 1
                        });
                    }
                    start = slotEnd;
                }
                return slots;
            },
            _days: function (start, end) {
                var slotEnd;
                var slots = [];
                var isWorkDay;
                start = new Date(start);
                end = new Date(end);
                while (start < end) {
                    slotEnd = end < kendo.date.nextDay(start) ? end : kendo.date.nextDay(start);
                    isWorkDay = this._isWorkDay(start);
                    if (!this.options.showWorkDays || isWorkDay) {
                        slots.push({
                            start: start,
                            end: slotEnd,
                            isNonWorking: !isWorkDay,
                            span: 1
                        });
                    }
                    start = slotEnd;
                }
                return slots;
            },
            _weeks: function (start, end) {
                var slotEnd;
                var slots = [];
                var firstDay = this.calendarInfo().firstDay;
                var daySlots;
                var span;
                start = new Date(start);
                end = new Date(end);
                while (start < end) {
                    slotEnd = kendo.date.dayOfWeek(kendo.date.addDays(start, 1), firstDay, 1);
                    if (slotEnd > end) {
                        slotEnd = end;
                    }
                    daySlots = this._days(start, slotEnd);
                    span = daySlots.length;
                    if (span > 0) {
                        slots.push({
                            start: daySlots[0].start,
                            end: daySlots[span - 1].end,
                            span: span
                        });
                    }
                    start = slotEnd;
                }
                return slots;
            },
            _months: function (start, end) {
                var slotEnd;
                var endMonth;
                var slots = [];
                var daySlots;
                var span;
                start = new Date(start);
                end = new Date(end);
                while (start < end) {
                    slotEnd = new Date(start);
                    endMonth = kendo.date.firstDayOfMonth(new Date(slotEnd.setMonth(slotEnd.getMonth() + 1)));
                    slotEnd = end < endMonth ? end : endMonth;
                    daySlots = this._days(start, slotEnd);
                    span = daySlots.length;
                    if (span > 0) {
                        slots.push({
                            start: daySlots[0].start,
                            end: daySlots[span - 1].end,
                            span: span
                        });
                    }
                    start = slotEnd;
                }
                return slots;
            },
            _years: function (start, end) {
                var slotEnd;
                var monthSpan;
                var endMonth;
                var slots = [];
                start = new Date(start);
                end = new Date(end);
                while (start < end) {
                    slotEnd = new Date(start);
                    slotEnd = kendo.date.firstDayOfMonth(new Date(slotEnd.setMonth(12)));
                    if (slotEnd >= end) {
                        slotEnd = end;
                    }
                    endMonth = slotEnd.getMonth() || 12;
                    monthSpan = endMonth - start.getMonth();
                    slots.push({
                        start: start,
                        end: slotEnd,
                        span: monthSpan
                    });
                    start = slotEnd;
                }
                return slots;
            },
            _slotHeaders: function (slots, template) {
                var columns = [];
                var slot;
                for (var i = 0, l = slots.length; i < l; i++) {
                    slot = slots[i];
                    columns.push({
                        text: template(slot),
                        isNonWorking: !!slot.isNonWorking,
                        span: slot.span
                    });
                }
                return columns;
            },
            _isWorkDay: function (date) {
                var day = date.getDay();
                var workDays = this._workDays;
                for (var i = 0, l = workDays.length; i < l; i++) {
                    if (workDays[i] === day) {
                        return true;
                    }
                }
                return false;
            },
            calendarInfo: function () {
                return kendo.getCulture().calendars.standard;
            },
            _renderCurrentTime: function () {
                var currentTime = this._getCurrentTime();
                var timeOffset = this._offset(currentTime);
                var element = $('<div class=\'k-current-time\'></div>');
                var viewStyles = GanttView.styles;
                var tablesWrap = $(DOT + viewStyles.tasksWrapper);
                var tasksTable = $(DOT + viewStyles.tasksTable);
                var slot;
                if (!this.content || !this._timeSlots().length) {
                    return;
                }
                this.content.find('.k-current-time').remove();
                slot = this._timeSlots()[this._slotIndex('start', currentTime)];
                if (currentTime < slot.start || currentTime > slot.end) {
                    return;
                }
                if (tablesWrap.length && tasksTable.length) {
                    timeOffset += tasksTable.offset().left - tablesWrap.offset().left;
                }
                element.css({
                    left: timeOffset + 'px',
                    top: '0px',
                    width: '1px',
                    height: this._contentHeight + 'px'
                }).appendTo(this.content);
            },
            _getCurrentTime: function () {
                return new Date();
            },
            _currentTime: function () {
                var markerOptions = this.options.currentTimeMarker;
                if (markerOptions !== false && markerOptions.updateInterval !== undefined) {
                    this._renderCurrentTime();
                    this._currentTimeUpdateTimer = setInterval(proxy(this._renderCurrentTime, this), markerOptions.updateInterval);
                }
            }
        });
        extend(true, GanttView, { styles: viewStyles });
        kendo.ui.GanttDayView = GanttView.extend({
            name: 'day',
            options: {
                timeHeaderTemplate: TIME_HEADER_TEMPLATE,
                dayHeaderTemplate: DAY_HEADER_TEMPLATE,
                resizeTooltipFormat: 'h:mm tt ddd, MMM d'
            },
            range: function (range) {
                var optionsRange = this.options.range;
                this.start = kendo.date.getDate(range.start);
                this.end = kendo.date.getDate(range.end);
                if (kendo.date.getMilliseconds(range.end) > 0 || this.end.getTime() === this.start.getTime()) {
                    this.end = kendo.date.addDays(this.end, 1);
                }
                if (optionsRange && optionsRange.start) {
                    this.start = kendo.date.getDate(optionsRange.start);
                    this.start.setHours(optionsRange.start.getHours());
                }
                if (optionsRange && optionsRange.end) {
                    this.end = kendo.date.getDate(optionsRange.end);
                    this.end.setHours(optionsRange.end.getHours());
                }
            },
            _createSlots: function () {
                var daySlots;
                var daySlot;
                var hourSlots;
                var hours;
                var slots = [];
                daySlots = this._days(this.start, this.end);
                hourSlots = [];
                for (var i = 0, l = daySlots.length; i < l; i++) {
                    daySlot = daySlots[i];
                    hours = this._hours(daySlot.start, daySlot.end);
                    daySlot.span = hours.length;
                    hourSlots.push.apply(hourSlots, hours);
                }
                slots.push(daySlots);
                slots.push(hourSlots);
                return slots;
            },
            _layout: function () {
                var rows = [];
                var options = this.options;
                rows.push(this._slotHeaders(this._slots[0], kendo.template(options.dayHeaderTemplate)));
                rows.push(this._slotHeaders(this._slots[1], kendo.template(options.timeHeaderTemplate)));
                return rows;
            }
        });
        kendo.ui.GanttWeekView = GanttView.extend({
            name: 'week',
            options: {
                dayHeaderTemplate: DAY_HEADER_TEMPLATE,
                weekHeaderTemplate: WEEK_HEADER_TEMPLATE,
                resizeTooltipFormat: 'h:mm tt ddd, MMM d'
            },
            range: function (range) {
                var optionsRange = this.options.range;
                var calendarInfo = this.calendarInfo();
                var firstDay = calendarInfo.firstDay;
                var rangeEnd = range.end;
                var endDay;
                if (firstDay === rangeEnd.getDay()) {
                    rangeEnd.setDate(rangeEnd.getDate() + 7);
                }
                this.start = kendo.date.getDate(kendo.date.dayOfWeek(range.start, firstDay, -1));
                this.end = kendo.date.getDate(kendo.date.dayOfWeek(rangeEnd, firstDay, 1));
                if (optionsRange && optionsRange.start) {
                    this.start = kendo.date.getDate(optionsRange.start);
                }
                if (optionsRange && optionsRange.end) {
                    endDay = new Date(optionsRange.end);
                    if (kendo.date.getDate(endDay) < optionsRange.end) {
                        this.end = kendo.date.getDate(new Date(endDay.setDate(endDay.getDate() + 1)));
                    } else {
                        this.end = kendo.date.getDate(endDay);
                    }
                }
            },
            _createSlots: function () {
                var slots = [];
                slots.push(this._weeks(this.start, this.end));
                slots.push(this._days(this.start, this.end));
                return slots;
            },
            _layout: function () {
                var rows = [];
                var options = this.options;
                rows.push(this._slotHeaders(this._slots[0], kendo.template(options.weekHeaderTemplate)));
                rows.push(this._slotHeaders(this._slots[1], kendo.template(options.dayHeaderTemplate)));
                return rows;
            }
        });
        kendo.ui.GanttMonthView = GanttView.extend({
            name: 'month',
            options: {
                weekHeaderTemplate: WEEK_HEADER_TEMPLATE,
                monthHeaderTemplate: MONTH_HEADER_TEMPLATE,
                resizeTooltipFormat: 'dddd, MMM d, yyyy'
            },
            range: function (range) {
                var optionsRange = this.options.range;
                var endDay;
                this.start = kendo.date.firstDayOfMonth(range.start);
                this.end = kendo.date.addDays(kendo.date.getDate(kendo.date.lastDayOfMonth(range.end)), 1);
                if (optionsRange && optionsRange.start) {
                    this.start = kendo.date.getDate(optionsRange.start);
                }
                if (optionsRange && optionsRange.end) {
                    endDay = new Date(optionsRange.end);
                    if (kendo.date.getDate(endDay) < optionsRange.end) {
                        this.end = kendo.date.getDate(new Date(endDay.setDate(endDay.getDate() + 1)));
                    } else {
                        this.end = kendo.date.getDate(endDay);
                    }
                }
            },
            _createSlots: function () {
                var slots = [];
                slots.push(this._months(this.start, this.end));
                slots.push(this._weeks(this.start, this.end));
                return slots;
            },
            _layout: function () {
                var rows = [];
                var options = this.options;
                rows.push(this._slotHeaders(this._slots[0], kendo.template(options.monthHeaderTemplate)));
                rows.push(this._slotHeaders(this._slots[1], kendo.template(options.weekHeaderTemplate)));
                return rows;
            }
        });
        kendo.ui.GanttYearView = GanttView.extend({
            name: 'year',
            options: {
                yearHeaderTemplate: YEAR_HEADER_TEMPLATE,
                monthHeaderTemplate: MONTH_HEADER_TEMPLATE,
                resizeTooltipFormat: 'dddd, MMM d, yyyy'
            },
            range: function (range) {
                var optionsRange = this.options.range;
                var firstDayOfMonth;
                this.start = kendo.date.firstDayOfMonth(new Date(range.start.setMonth(0)));
                this.end = kendo.date.firstDayOfMonth(new Date(range.end.setMonth(12)));
                if (optionsRange && optionsRange.start) {
                    this.start = kendo.date.firstDayOfMonth(optionsRange.start);
                }
                if (optionsRange && optionsRange.end) {
                    firstDayOfMonth = kendo.date.firstDayOfMonth(optionsRange.end);
                    this.end = kendo.date.getDate(new Date(firstDayOfMonth.setMonth(firstDayOfMonth.getMonth() + 1)));
                }
            },
            _createSlots: function () {
                var slots = [];
                var monthSlots = this._months(this.start, this.end);
                $(monthSlots).each(function (index, slot) {
                    slot.span = 1;
                });
                slots.push(this._years(this.start, this.end));
                slots.push(monthSlots);
                return slots;
            },
            _layout: function () {
                var rows = [];
                var options = this.options;
                rows.push(this._slotHeaders(this._slots[0], kendo.template(options.yearHeaderTemplate)));
                rows.push(this._slotHeaders(this._slots[1], kendo.template(options.monthHeaderTemplate)));
                return rows;
            }
        });
        var timelineStyles = {
            wrapper: 'k-timeline k-grid k-widget',
            gridHeader: 'k-grid-header',
            gridHeaderWrap: 'k-grid-header-wrap',
            gridContent: 'k-grid-content',
            gridContentWrap: 'k-grid-content',
            tasksWrapper: 'k-gantt-tables',
            dependenciesWrapper: 'k-gantt-dependencies',
            task: 'k-task',
            line: 'k-line',
            taskResizeHandle: 'k-resize-handle',
            taskResizeHandleWest: 'k-resize-w',
            taskDragHandle: 'k-task-draghandle',
            taskComplete: 'k-task-complete',
            taskDelete: 'k-task-delete',
            taskWrapActive: 'k-task-wrap-active',
            taskWrap: 'k-task-wrap',
            taskDot: 'k-task-dot',
            taskDotStart: 'k-task-start',
            taskDotEnd: 'k-task-end',
            hovered: 'k-state-hover',
            selected: 'k-state-selected',
            origin: 'k-origin'
        };
        var GanttTimeline = kendo.ui.GanttTimeline = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                if (!this.options.views || !this.options.views.length) {
                    this.options.views = [
                        'day',
                        'week',
                        'month'
                    ];
                }
                isRtl = kendo.support.isRtl(element);
                this._wrapper();
                this._domTrees();
                this._views();
                this._selectable();
                this._draggable();
                this._resizable();
                this._percentResizeDraggable();
                this._createDependencyDraggable();
                this._attachEvents();
                this._tooltip();
            },
            options: {
                name: 'GanttTimeline',
                messages: {
                    views: {
                        day: 'Day',
                        week: 'Week',
                        month: 'Month',
                        year: 'Year',
                        start: 'Start',
                        end: 'End'
                    }
                },
                snap: true,
                selectable: true,
                editable: true
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                clearTimeout(this._tooltipTimeout);
                if (this._currentTimeUpdateTimer) {
                    clearInterval(this._currentTimeUpdateTimer);
                }
                this._unbindView(this._selectedView);
                if (this._moveDraggable) {
                    this._moveDraggable.destroy();
                }
                if (this._resizeDraggable) {
                    this._resizeDraggable.destroy();
                }
                if (this._percentDraggable) {
                    this._percentDraggable.destroy();
                }
                if (this._dependencyDraggable) {
                    this._dependencyDraggable.destroy();
                }
                if (this.touch) {
                    this.touch.destroy();
                }
                this._headerTree = null;
                this._taskTree = null;
                this._dependencyTree = null;
                this.wrapper.off(NS);
                kendo.destroy(this.wrapper);
            },
            _wrapper: function () {
                var styles = GanttTimeline.styles;
                var that = this;
                var options = this.options;
                var calculateSize = function () {
                    var rowHeight = typeof options.rowHeight === STRING ? options.rowHeight : options.rowHeight + 'px';
                    var table = $(kendo.format(SIZE_CALCULATION_TEMPLATE, rowHeight));
                    var calculatedRowHeight;
                    var calculatedCellHeight;
                    var content = that.wrapper.find(DOT + styles.tasksWrapper);
                    content.append(table);
                    calculatedRowHeight = outerHeight(table.find('tr'));
                    calculatedCellHeight = table.find('td').height();
                    table.remove();
                    return {
                        'row': calculatedRowHeight,
                        'cell': calculatedCellHeight
                    };
                };
                this.wrapper = this.element.addClass(styles.wrapper).append('<div class=\'' + styles.gridHeader + '\'><div class=\'' + styles.gridHeaderWrap + '\'></div></div>').append('<div class=\'' + styles.gridContentWrap + '\'><div class=\'' + styles.tasksWrapper + '\'></div><div class=\'' + styles.dependenciesWrapper + '\'></div></div>');
                if (options.rowHeight) {
                    this._calculatedSize = calculateSize();
                }
            },
            _domTrees: function () {
                var styles = GanttTimeline.styles;
                var tree = kendo.dom.Tree;
                var wrapper = this.wrapper;
                this._headerTree = new tree(wrapper.find(DOT + styles.gridHeaderWrap)[0]);
                this._taskTree = new tree(wrapper.find(DOT + styles.tasksWrapper)[0]);
                this._dependencyTree = new tree(wrapper.find(DOT + styles.dependenciesWrapper)[0]);
            },
            _views: function () {
                var views = this.options.views;
                var view;
                var isSettings;
                var name;
                var defaultView;
                var selected;
                this.views = {};
                for (var i = 0, l = views.length; i < l; i++) {
                    view = views[i];
                    isSettings = isPlainObject(view);
                    if (isSettings && view.selectable === false) {
                        continue;
                    }
                    name = isSettings ? typeof view.type !== 'string' ? view.title : view.type : view;
                    defaultView = defaultViews[name];
                    if (defaultView) {
                        if (isSettings) {
                            view.type = defaultView.type;
                        }
                        defaultView.title = this.options.messages.views[name];
                    }
                    view = extend({ title: name }, defaultView, isSettings ? view : {});
                    if (name) {
                        this.views[name] = view;
                        if (!selected || view.selected) {
                            selected = name;
                        }
                    }
                }
                if (selected) {
                    this._selectedViewName = selected;
                }
            },
            view: function (name) {
                if (name) {
                    this._selectView(name);
                    this.trigger('navigate', {
                        view: name,
                        action: 'changeView'
                    });
                }
                return this._selectedView;
            },
            _selectView: function (name) {
                if (name && this.views[name]) {
                    if (this._selectedView) {
                        this._unbindView(this._selectedView);
                    }
                    this._selectedView = this._initializeView(name);
                    this._selectedViewName = name;
                }
            },
            _viewByIndex: function (index) {
                var view;
                var views = this.views;
                for (view in views) {
                    if (!index) {
                        return view;
                    }
                    index--;
                }
            },
            _initializeView: function (name) {
                var view = this.views[name];
                if (view) {
                    var type = view.type;
                    if (typeof type === 'string') {
                        type = kendo.getter(view.type)(window);
                    }
                    if (type) {
                        var newRange = {};
                        extend(newRange, this.options.range, view.range);
                        var newDate = view.date || this.options.date;
                        view = new type(this.wrapper, trimOptions(extend(true, {
                            headerTree: this._headerTree,
                            taskTree: this._taskTree,
                            dependencyTree: this._dependencyTree,
                            calculatedSize: this._calculatedSize
                        }, view, this.options, {
                            date: newDate,
                            range: newRange
                        })));
                    } else {
                        throw new Error('There is no such view');
                    }
                }
                return view;
            },
            _unbindView: function (view) {
                if (view) {
                    view.destroy();
                }
            },
            _range: function (tasks) {
                var startOrder = {
                    field: 'start',
                    dir: 'asc'
                };
                var endOrder = {
                    field: 'end',
                    dir: 'desc'
                };
                if (!tasks || !tasks.length) {
                    return {
                        start: new Date(),
                        end: new Date()
                    };
                }
                var start = new Query(tasks).sort(startOrder).toArray()[0].start || new Date();
                var end = new Query(tasks).sort(endOrder).toArray()[0].end || new Date();
                return {
                    start: new Date(start),
                    end: new Date(end)
                };
            },
            _render: function (tasks) {
                var view = this.view();
                var range = this._range(tasks);
                var date = view.options.date;
                this._tasks = tasks;
                view.range(range);
                view.renderLayout();
                view.render(tasks);
                if (date) {
                    view._scrollToDate(date);
                }
            },
            _renderDependencies: function (dependencies) {
                this.view()._renderDependencies(dependencies);
            },
            _taskByUid: function (uid) {
                var tasks = this._tasks;
                var length = tasks.length;
                var task;
                for (var i = 0; i < length; i++) {
                    task = tasks[i];
                    if (task.uid === uid) {
                        return task;
                    }
                }
            },
            _draggable: function () {
                var that = this;
                var element;
                var task;
                var currentStart;
                var startOffset;
                var snap = this.options.snap;
                var styles = GanttTimeline.styles;
                var editable = this.options.editable;
                var cleanUp = function () {
                    that.view()._removeDragHint();
                    if (element) {
                        element.css('opacity', 1);
                    }
                    element = null;
                    task = null;
                    that.dragInProgress = false;
                };
                if (!editable || editable.move === false || editable.update === false) {
                    return;
                }
                this._moveDraggable = new kendo.ui.Draggable(this.wrapper, {
                    distance: 0,
                    filter: DOT + styles.task,
                    holdToDrag: kendo.support.mobileOS,
                    ignore: DOT + styles.taskResizeHandle
                });
                this._moveDraggable.bind('dragstart', function (e) {
                    var view = that.view();
                    element = e.currentTarget.parent();
                    task = that._taskByUid(e.currentTarget.attr('data-uid'));
                    if (that.trigger('moveStart', { task: task })) {
                        e.preventDefault();
                        return;
                    }
                    currentStart = task.start;
                    startOffset = view._timeByPosition(e.x.location, snap) - currentStart;
                    view._createDragHint(element);
                    element.css('opacity', 0.5);
                    clearTimeout(that._tooltipTimeout);
                    that.dragInProgress = true;
                }).bind('drag', kendo.throttle(function (e) {
                    if (!that.dragInProgress) {
                        return;
                    }
                    var view = that.view();
                    var date = new Date(view._timeByPosition(e.x.location, snap) - startOffset);
                    var updateHintDate = date;
                    if (!that.trigger('move', {
                            task: task,
                            start: date
                        })) {
                        currentStart = date;
                        if (isRtl) {
                            updateHintDate = new Date(currentStart.getTime() + task.duration());
                        }
                        view._updateDragHint(updateHintDate);
                    }
                }, 15)).bind('dragend', function () {
                    that.trigger('moveEnd', {
                        task: task,
                        start: currentStart
                    });
                    cleanUp();
                }).bind('dragcancel', function () {
                    cleanUp();
                }).userEvents.bind('select', function () {
                    blurActiveElement();
                });
            },
            _resizable: function () {
                var that = this;
                var element;
                var task;
                var currentStart;
                var currentEnd;
                var resizeStart;
                var snap = this.options.snap;
                var styles = GanttTimeline.styles;
                var editable = this.options.editable;
                var cleanUp = function () {
                    that.view()._removeResizeHint();
                    element = null;
                    task = null;
                    that.dragInProgress = false;
                };
                if (!editable || editable.resize === false || editable.update === false) {
                    return;
                }
                this._resizeDraggable = new kendo.ui.Draggable(this.wrapper, {
                    distance: 0,
                    filter: DOT + styles.taskResizeHandle,
                    holdToDrag: false
                });
                this._resizeDraggable.bind('dragstart', function (e) {
                    resizeStart = e.currentTarget.hasClass(styles.taskResizeHandleWest);
                    if (isRtl) {
                        resizeStart = !resizeStart;
                    }
                    element = e.currentTarget.closest(DOT + styles.task);
                    task = that._taskByUid(element.attr('data-uid'));
                    if (that.trigger('resizeStart', { task: task })) {
                        e.preventDefault();
                        return;
                    }
                    currentStart = task.start;
                    currentEnd = task.end;
                    that.view()._createResizeHint(task);
                    clearTimeout(that._tooltipTimeout);
                    that.dragInProgress = true;
                }).bind('drag', kendo.throttle(function (e) {
                    if (!that.dragInProgress) {
                        return;
                    }
                    var view = that.view();
                    var date = view._timeByPosition(e.x.location, snap, !resizeStart);
                    if (resizeStart) {
                        if (date < currentEnd) {
                            currentStart = date;
                        } else {
                            currentStart = currentEnd;
                        }
                    } else {
                        if (date > currentStart) {
                            currentEnd = date;
                        } else {
                            currentEnd = currentStart;
                        }
                    }
                    if (!that.trigger('resize', {
                            task: task,
                            start: currentStart,
                            end: currentEnd
                        })) {
                        view._updateResizeHint(currentStart, currentEnd, resizeStart);
                    }
                }, 15)).bind('dragend', function () {
                    that.trigger('resizeEnd', {
                        task: task,
                        resizeStart: resizeStart,
                        start: currentStart,
                        end: currentEnd
                    });
                    cleanUp();
                }).bind('dragcancel', function () {
                    cleanUp();
                }).userEvents.bind('select', function () {
                    blurActiveElement();
                });
            },
            _percentResizeDraggable: function () {
                var that = this;
                var task;
                var taskElement;
                var taskElementOffset;
                var timelineOffset;
                var originalPercentWidth;
                var maxPercentWidth;
                var currentPercentComplete;
                var tooltipTop;
                var tooltipLeft;
                var styles = GanttTimeline.styles;
                var delta;
                var editable = this.options.editable;
                var cleanUp = function () {
                    that.view()._removePercentCompleteTooltip();
                    taskElement = null;
                    task = null;
                    that.dragInProgress = false;
                };
                var updateElement = function (width) {
                    taskElement.find(DOT + styles.taskComplete).width(width).end().siblings(DOT + styles.taskDragHandle).css(isRtl ? 'right' : 'left', width);
                };
                if (!editable || editable.dragPercentComplete === false || editable.update === false) {
                    return;
                }
                this._percentDraggable = new kendo.ui.Draggable(this.wrapper, {
                    distance: 0,
                    filter: DOT + styles.taskDragHandle,
                    holdToDrag: false
                });
                this._percentDraggable.bind('dragstart', function (e) {
                    if (that.trigger('percentResizeStart')) {
                        e.preventDefault();
                        return;
                    }
                    taskElement = e.currentTarget.siblings(DOT + styles.task);
                    task = that._taskByUid(taskElement.attr('data-uid'));
                    currentPercentComplete = task.percentComplete;
                    taskElementOffset = taskElement.offset();
                    timelineOffset = this.element.offset();
                    originalPercentWidth = taskElement.find(DOT + styles.taskComplete).width();
                    maxPercentWidth = outerWidth(taskElement);
                    clearTimeout(that._tooltipTimeout);
                    that.dragInProgress = true;
                }).bind('drag', kendo.throttle(function (e) {
                    if (!that.dragInProgress) {
                        return;
                    }
                    delta = isRtl ? -e.x.initialDelta : e.x.initialDelta;
                    var currentWidth = Math.max(0, Math.min(maxPercentWidth, originalPercentWidth + delta));
                    currentPercentComplete = Math.round(currentWidth / maxPercentWidth * 100);
                    updateElement(currentWidth);
                    tooltipTop = taskElementOffset.top - timelineOffset.top;
                    tooltipLeft = taskElementOffset.left + currentWidth - timelineOffset.left;
                    if (isRtl) {
                        tooltipLeft += maxPercentWidth - 2 * currentWidth;
                    }
                    that.view()._updatePercentCompleteTooltip(tooltipTop, tooltipLeft, currentPercentComplete);
                }, 15)).bind('dragend', function () {
                    that.trigger('percentResizeEnd', {
                        task: task,
                        percentComplete: currentPercentComplete / 100
                    });
                    cleanUp();
                }).bind('dragcancel', function () {
                    updateElement(originalPercentWidth);
                    cleanUp();
                }).userEvents.bind('select', function () {
                    blurActiveElement();
                });
            },
            _createDependencyDraggable: function () {
                var that = this;
                var originalHandle;
                var hoveredHandle = $();
                var hoveredTask = $();
                var startX;
                var startY;
                var useVML = browser.msie && browser.version < 9;
                var styles = GanttTimeline.styles;
                var editable = this.options.editable;
                var cleanUp = function () {
                    originalHandle.css('display', '').removeClass(styles.hovered);
                    originalHandle.parent().removeClass(styles.origin);
                    originalHandle = null;
                    toggleHandles(false);
                    hoveredTask = $();
                    hoveredHandle = $();
                    that.view()._removeDependencyDragHint();
                    that.dragInProgress = false;
                };
                var toggleHandles = function (value) {
                    if (!hoveredTask.hasClass(styles.origin)) {
                        hoveredTask.find(DOT + styles.taskDot).css('display', value ? 'block' : '');
                        hoveredHandle.toggleClass(styles.hovered, value);
                    }
                };
                if (!editable || editable.dependencyCreate === false) {
                    return;
                }
                if (useVML && document.namespaces) {
                    document.namespaces.add('kvml', 'urn:schemas-microsoft-com:vml', '#default#VML');
                }
                this._dependencyDraggable = new kendo.ui.Draggable(this.wrapper, {
                    distance: 0,
                    filter: DOT + styles.taskDot,
                    holdToDrag: false
                });
                this._dependencyDraggable.bind('dragstart', function (e) {
                    if (that.trigger('dependencyDragStart')) {
                        e.preventDefault();
                        return;
                    }
                    originalHandle = e.currentTarget.css('display', 'block').addClass(styles.hovered);
                    originalHandle.parent().addClass(styles.origin);
                    var elementOffset = originalHandle.offset();
                    var tablesOffset = that.wrapper.find(DOT + styles.tasksWrapper).offset();
                    startX = Math.round(elementOffset.left - tablesOffset.left + outerHeight(originalHandle) / 2);
                    startY = Math.round(elementOffset.top - tablesOffset.top + outerWidth(originalHandle) / 2);
                    clearTimeout(that._tooltipTimeout);
                    that.dragInProgress = true;
                }).bind('drag', kendo.throttle(function (e) {
                    if (!that.dragInProgress) {
                        return;
                    }
                    that.view()._removeDependencyDragHint();
                    var target = $(kendo.elementUnderCursor(e));
                    var tablesOffset = that.wrapper.find(DOT + styles.tasksWrapper).offset();
                    var currentX = e.x.location - tablesOffset.left;
                    var currentY = e.y.location - tablesOffset.top;
                    that.view()._updateDependencyDragHint({
                        x: startX,
                        y: startY
                    }, {
                        x: currentX,
                        y: currentY
                    }, useVML);
                    toggleHandles(false);
                    hoveredHandle = target.hasClass(styles.taskDot) ? target : $();
                    hoveredTask = target.closest(DOT + styles.taskWrap);
                    toggleHandles(true);
                }, 15)).bind('dragend', function () {
                    if (hoveredHandle.length) {
                        var fromStart = originalHandle.hasClass(styles.taskDotStart);
                        var toStart = hoveredHandle.hasClass(styles.taskDotStart);
                        var type = fromStart ? toStart ? 3 : 2 : toStart ? 1 : 0;
                        var predecessor = that._taskByUid(originalHandle.siblings(DOT + styles.task).attr('data-uid'));
                        var successor = that._taskByUid(hoveredHandle.siblings(DOT + styles.task).attr('data-uid'));
                        if (predecessor !== successor) {
                            that.trigger('dependencyDragEnd', {
                                type: type,
                                predecessor: predecessor,
                                successor: successor
                            });
                        }
                    }
                    cleanUp();
                }).bind('dragcancel', function () {
                    cleanUp();
                }).userEvents.bind('select', function () {
                    blurActiveElement();
                });
            },
            _selectable: function () {
                var that = this;
                var styles = GanttTimeline.styles;
                if (this.options.selectable) {
                    this.wrapper.on(CLICK + NS, DOT + styles.task, function (e) {
                        e.stopPropagation();
                        if (!e.ctrlKey) {
                            that.trigger('select', { uid: $(this).attr('data-uid') });
                        } else {
                            that.trigger('clear');
                        }
                    }).on(CLICK + NS, DOT + styles.taskWrap, function (e) {
                        e.stopPropagation();
                        $(this).css('z-index', '0');
                        var target = $(document.elementFromPoint(e.clientX, e.clientY));
                        if (target.hasClass(styles.line)) {
                            target.click();
                        }
                        $(this).css('z-index', '');
                    }).on(CLICK + NS, DOT + styles.tasksWrapper, function () {
                        if (that.selectDependency().length > 0) {
                            that.clearSelection();
                        } else {
                            that.trigger('clear');
                        }
                    }).on(CLICK + NS, DOT + styles.line, function (e) {
                        e.stopPropagation();
                        that.selectDependency(this);
                    });
                }
            },
            select: function (value) {
                var element = this.wrapper.find(value);
                var styles = GanttTimeline.styles;
                if (element.length) {
                    this.clearSelection();
                    element.addClass(styles.selected);
                    if (kendo.support.mobileOS) {
                        element.parent().addClass(styles.taskWrapActive);
                    }
                    return;
                }
                return this.wrapper.find(DOT + styles.task + DOT + styles.selected);
            },
            selectDependency: function (value) {
                var element = this.wrapper.find(value);
                var uid;
                var styles = GanttTimeline.styles;
                if (element.length) {
                    this.clearSelection();
                    this.trigger('clear');
                    uid = $(element).attr('data-uid');
                    this.wrapper.find(DOT + styles.line + '[data-uid=\'' + uid + '\']').addClass(styles.selected);
                    return;
                }
                return this.wrapper.find(DOT + styles.line + DOT + styles.selected);
            },
            clearSelection: function () {
                var styles = GanttTimeline.styles;
                this.wrapper.find(DOT + styles.selected).removeClass(styles.selected);
                if (kendo.support.mobileOS) {
                    this.wrapper.find(DOT + styles.taskWrapActive).removeClass(styles.taskWrapActive);
                }
            },
            _attachEvents: function () {
                var that = this;
                var styles = GanttTimeline.styles;
                var editable = this.options.editable;
                if (editable) {
                    this._tabindex();
                    this.wrapper.on(CLICK + NS, DOT + styles.taskDelete, function (e) {
                        that.trigger('removeTask', { uid: $(this).closest(DOT + styles.task).attr('data-uid') });
                        e.stopPropagation();
                        e.preventDefault();
                    }).on(KEYDOWN + NS, function (e) {
                        var selectedDependency;
                        var editable = that.options.editable;
                        if (e.keyCode === keys.DELETE && editable && editable.dependencyDestroy !== false) {
                            selectedDependency = that.selectDependency();
                            if (selectedDependency.length) {
                                that.trigger('removeDependency', { uid: selectedDependency.attr('data-uid') });
                                that.clearSelection();
                            }
                        }
                    });
                    if (!kendo.support.mobileOS) {
                        this.wrapper.on(DBLCLICK + NS, DOT + styles.task, function (e) {
                            if (that.options.editable.update !== false) {
                                that.trigger('editTask', { uid: $(this).attr('data-uid') });
                                e.stopPropagation();
                                e.preventDefault();
                            }
                        });
                    } else {
                        this.touch = this.wrapper.kendoTouch({
                            filter: DOT + styles.task,
                            doubletap: function (e) {
                                if (that.options.editable.update !== false) {
                                    that.trigger('editTask', { uid: $(e.touch.currentTarget).attr('data-uid') });
                                }
                            }
                        }).data('kendoTouch');
                    }
                }
            },
            _tooltip: function () {
                var that = this;
                var tooltipOptions = this.options.tooltip;
                var styles = GanttTimeline.styles;
                var currentMousePosition;
                var mouseMoveHandler = function (e) {
                    currentMousePosition = e.clientX;
                };
                if (tooltipOptions && tooltipOptions.visible === false) {
                    return;
                }
                if (!kendo.support.mobileOS) {
                    this.wrapper.on(MOUSEENTER + NS, DOT + styles.task, function () {
                        var element = this;
                        var task = that._taskByUid($(this).attr('data-uid'));
                        if (that.dragInProgress) {
                            return;
                        }
                        that._tooltipTimeout = setTimeout(function () {
                            that.view()._createTaskTooltip(task, element, currentMousePosition);
                        }, 800);
                        $(this).on(MOUSEMOVE, mouseMoveHandler);
                    }).on(MOUSELEAVE + NS, DOT + styles.task, function () {
                        clearTimeout(that._tooltipTimeout);
                        that.view()._removeTaskTooltip();
                        $(this).off(MOUSEMOVE, mouseMoveHandler);
                    });
                } else {
                    this.wrapper.on(CLICK + NS, DOT + styles.taskDelete, function (e) {
                        e.stopPropagation();
                        that.view()._removeTaskTooltip();
                    }).on(MOUSELEAVE + NS, DOT + styles.task, function (e) {
                        var parents = $(e.relatedTarget).parents(DOT + styles.taskWrap, DOT + styles.task);
                        if (parents.length === 0) {
                            that.view()._removeTaskTooltip();
                        }
                    });
                    if (this.touch) {
                        this.touch.bind('tap', function (e) {
                            var element = e.touch.target;
                            var task = that._taskByUid($(element).attr('data-uid'));
                            var currentPosition = e.touch.x.client;
                            if (that.view()._taskTooltip) {
                                that.view()._removeTaskTooltip();
                            }
                            that.view()._createTaskTooltip(task, element, currentPosition);
                        }).bind('doubletap', function () {
                            that.view()._removeTaskTooltip();
                        });
                    }
                }
            }
        });
        extend(true, GanttTimeline, { styles: timelineStyles });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.gantt', [
        'kendo.data',
        'kendo.popup',
        'kendo.window',
        'kendo.resizable',
        'kendo.gantt.list',
        'kendo.gantt.timeline',
        'kendo.grid',
        'kendo.pdf'
    ], f);
}(function () {
    var __meta__ = {
        id: 'gantt',
        name: 'Gantt',
        category: 'web',
        description: 'The Gantt component.',
        depends: [
            'data',
            'popup',
            'resizable',
            'window',
            'gantt.list',
            'gantt.timeline',
            'grid'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var keys = $.extend({ F10: 121 }, kendo.keys);
        var supportsMedia = 'matchMedia' in window;
        var browser = kendo.support.browser;
        var mobileOS = kendo.support.mobileOS;
        var Observable = kendo.Observable;
        var Widget = kendo.ui.Widget;
        var DataSource = kendo.data.DataSource;
        var ObservableObject = kendo.data.ObservableObject;
        var ObservableArray = kendo.data.ObservableArray;
        var Query = kendo.data.Query;
        var isArray = $.isArray;
        var inArray = $.inArray;
        var isFunction = kendo.isFunction;
        var proxy = $.proxy;
        var extend = $.extend;
        var isPlainObject = $.isPlainObject;
        var map = $.map;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var defaultIndicatorWidth = 3;
        var NS = '.kendoGantt';
        var PERCENTAGE_FORMAT = 'p0';
        var TABINDEX = 'tabIndex';
        var CLICK = 'click';
        var WIDTH = 'width';
        var STRING = 'string';
        var DIRECTIONS = {
            'down': {
                origin: 'bottom left',
                position: 'top left'
            },
            'up': {
                origin: 'top left',
                position: 'bottom left'
            }
        };
        var ARIA_DESCENDANT = 'aria-activedescendant';
        var ARIA_LABEL = 'aria-label';
        var ACTIVE_CELL = 'gantt_active_cell';
        var ACTIVE_OPTION = 'action-option-focused';
        var DOT = '.';
        var TASK_DELETE_CONFIRM = 'Are you sure you want to delete this task?';
        var DEPENDENCY_DELETE_CONFIRM = 'Are you sure you want to delete this dependency?';
        var TOGGLE_BUTTON_TEMPLATE = kendo.template('<button class="#=styles.buttonToggle#" type="button" ' + ARIA_LABEL + '="Toggle"><span class="#=styles.iconToggle#"></span></button>');
        var BUTTON_TEMPLATE = '<button class="#=styles.button# #=className#" type="button" ' + '#if (action) {#' + 'data-action="#=action#"' + '#}#' + '><span class="#=iconClass#"></span><span>#=text#</span></button>';
        var COMMAND_BUTTON_TEMPLATE = '<a class="#=className#" #=attr# href="\\#">#=text#</a>';
        var VIEWBUTTONTEMPLATE = kendo.template('<li class="#=styles.currentView# #=styles.viewButtonDefault#"><a href="\\#" class="#=styles.link#">&nbps;</a></li>');
        var HEADER_VIEWS_TEMPLATE = kendo.template('<ul class="#=styles.viewsWrapper#">' + '#for(var view in views){#' + '<li class="#=styles.viewButtonDefault# #=styles.viewButton#-#= view.toLowerCase() #" data-#=ns#name="#=view#"><a href="\\#" class="#=styles.link#">#=views[view].title#</a></li>' + '#}#' + '</ul>');
        var TASK_DROPDOWN_TEMPLATE = kendo.template('<div class="#=styles.popupWrapper#">' + '<ul class="#=styles.popupList#" role="listbox">' + '#for(var i = 0, l = actions.length; i < l; i++){#' + '<li class="#=styles.item#" data-action="#=actions[i].data#" role="option">#=actions[i].text#</span>' + '#}#' + '</ul>' + '</div>');
        var DATERANGEEDITOR = function (container, options) {
            var attr = {
                name: options.field,
                title: options.title
            };
            var validationRules = options.model.fields[options.field].validation;
            if (validationRules && isPlainObject(validationRules) && validationRules.message) {
                attr[kendo.attr('dateCompare-msg')] = validationRules.message;
            }
            $('<input type="text" required ' + kendo.attr('type') + '="date" ' + kendo.attr('role') + '="datetimepicker" ' + kendo.attr('bind') + '="value:' + options.field + '" ' + kendo.attr('validate') + '=\'true\' />').attr(attr).appendTo(container);
            $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
        };
        var RESOURCESEDITOR = function (container, options) {
            $('<a href="#" class="' + options.styles.button + '">' + options.messages.assignButton + '</a>').click(options.click).appendTo(container);
        };
        var ganttStyles = {
            wrapper: 'k-widget k-gantt',
            rowHeight: 'k-gantt-rowheight',
            listWrapper: 'k-gantt-layout k-gantt-treelist',
            list: 'k-gantt-treelist',
            timelineWrapper: 'k-gantt-layout k-gantt-timeline',
            timeline: 'k-gantt-timeline',
            splitBarWrapper: 'k-splitbar k-state-default k-splitbar-horizontal k-splitbar-draggable-horizontal k-gantt-layout',
            splitBar: 'k-splitbar',
            splitBarHover: 'k-splitbar-horizontal-hover',
            popupWrapper: 'k-list-container',
            popupList: 'k-list k-reset',
            resizeHandle: 'k-resize-handle',
            icon: 'k-icon',
            item: 'k-item',
            line: 'k-line',
            buttonDelete: 'k-gantt-delete',
            buttonCancel: 'k-gantt-cancel',
            buttonSave: 'k-gantt-update',
            buttonToggle: 'k-gantt-toggle',
            primary: 'k-primary',
            hovered: 'k-state-hover',
            selected: 'k-state-selected',
            focused: 'k-state-focused',
            gridHeader: 'k-grid-header',
            gridHeaderWrap: 'k-grid-header-wrap',
            gridContent: 'k-grid-content',
            tasks: 'k-gantt-tasks',
            popup: {
                form: 'k-popup-edit-form',
                editForm: 'k-gantt-edit-form',
                formContainer: 'k-edit-form-container',
                resourcesFormContainer: 'k-resources-form-container',
                message: 'k-popup-message',
                buttonsContainer: 'k-edit-buttons k-state-default',
                button: 'k-button',
                editField: 'k-edit-field',
                editLabel: 'k-edit-label',
                resourcesField: 'k-gantt-resources'
            },
            toolbar: {
                headerWrapper: 'k-floatwrap k-header k-gantt-toolbar',
                footerWrapper: 'k-floatwrap k-header k-gantt-toolbar',
                toolbar: 'k-gantt-toolbar',
                expanded: 'k-state-expanded',
                views: 'k-gantt-views',
                viewsWrapper: 'k-reset k-header k-gantt-views',
                actions: 'k-gantt-actions',
                button: 'k-button k-button-icontext',
                buttonToggle: 'k-button k-button-icon k-gantt-toggle',
                iconPlus: 'k-icon k-i-plus',
                iconPdf: 'k-icon k-i-file-pdf',
                iconToggle: 'k-icon k-i-layout-1-by-4',
                viewButtonDefault: 'k-state-default',
                viewButton: 'k-view',
                currentView: 'k-current-view',
                link: 'k-link',
                pdfButton: 'k-gantt-pdf',
                appendButton: 'k-gantt-create'
            }
        };
        function selector(uid) {
            return '[' + kendo.attr('uid') + (uid ? '=\'' + uid + '\']' : ']');
        }
        function trimOptions(options) {
            delete options.name;
            delete options.prefix;
            delete options.remove;
            delete options.edit;
            delete options.add;
            delete options.navigate;
            return options;
        }
        function dateCompareValidator(input) {
            if (input.filter('[name=end], [name=start]').length) {
                var field = input.attr('name');
                var picker = kendo.widgetInstance(input, kendo.ui);
                var dates = {};
                var container = input;
                var editable;
                var model;
                while (container !== window && !editable) {
                    container = container.parent();
                    editable = container.data('kendoEditable');
                }
                model = editable ? editable.options.model : null;
                if (!model) {
                    return true;
                }
                dates.start = model.start;
                dates.end = model.end;
                dates[field] = picker ? picker.value() : kendo.parseDate(input.val());
                return dates.start <= dates.end;
            }
            return true;
        }
        function focusTable(table, direct) {
            var wrapper = table.parents('[' + kendo.attr('role') + '="gantt"]');
            var scrollPositions = [];
            var parents = scrollableParents(wrapper);
            table.attr(TABINDEX, 0);
            if (direct) {
                parents.each(function (index, parent) {
                    scrollPositions[index] = $(parent).scrollTop();
                });
            }
            try {
                table[0].setActive();
            } catch (e) {
                table[0].focus();
            }
            if (direct) {
                parents.each(function (index, parent) {
                    $(parent).scrollTop(scrollPositions[index]);
                });
            }
        }
        function scrollableParents(element) {
            return $(element).parentsUntil('body').filter(function (index, element) {
                var computedStyle = kendo.getComputedStyles(element, ['overflow']);
                return computedStyle.overflow != 'visible';
            }).add(window);
        }
        var defaultCommands;
        var TaskDropDown = Observable.extend({
            init: function (element, options) {
                Observable.fn.init.call(this);
                this.element = element;
                this.options = extend(true, {}, this.options, options);
                this._popup();
            },
            options: {
                direction: 'down',
                navigatable: false
            },
            _current: function (method) {
                var ganttStyles = Gantt.styles;
                var current = this.list.find(DOT + ganttStyles.focused);
                var sibling = current[method]();
                if (sibling.length) {
                    current.removeClass(ganttStyles.focused).removeAttr('id');
                    sibling.addClass(ganttStyles.focused).attr('id', ACTIVE_OPTION);
                    this.list.find('ul').removeAttr(ARIA_DESCENDANT).attr(ARIA_DESCENDANT, ACTIVE_OPTION);
                }
            },
            _popup: function () {
                var that = this;
                var ganttStyles = Gantt.styles;
                var itemSelector = 'li' + DOT + ganttStyles.item;
                var appendButtonSelector = DOT + ganttStyles.toolbar.appendButton;
                var actions = this.options.messages.actions;
                var navigatable = this.options.navigatable;
                this.list = $(TASK_DROPDOWN_TEMPLATE({
                    styles: ganttStyles,
                    actions: [
                        {
                            data: 'add',
                            text: actions.addChild
                        },
                        {
                            data: 'insert-before',
                            text: actions.insertBefore
                        },
                        {
                            data: 'insert-after',
                            text: actions.insertAfter
                        }
                    ]
                }));
                this.element.append(this.list);
                this.popup = new kendo.ui.Popup(this.list, extend({
                    anchor: this.element.find(appendButtonSelector),
                    open: function () {
                        that._adjustListWidth();
                    },
                    animation: this.options.animation
                }, DIRECTIONS[this.options.direction]));
                this.element.on(CLICK + NS, appendButtonSelector, function (e) {
                    var target = $(this);
                    var action = target.attr(kendo.attr('action'));
                    e.preventDefault();
                    if (action) {
                        that.trigger('command', { type: action });
                    } else {
                        that.popup.open();
                        if (navigatable) {
                            that.list.find('li:first').addClass(ganttStyles.focused).attr('id', ACTIVE_OPTION).end().find('ul').attr({
                                TABINDEX: 0,
                                'aria-activedescendant': ACTIVE_OPTION
                            }).focus();
                        }
                    }
                });
                this.list.find(itemSelector).hover(function () {
                    $(this).addClass(ganttStyles.hovered);
                }, function () {
                    $(this).removeClass(ganttStyles.hovered);
                }).end().on(CLICK + NS, itemSelector, function () {
                    that.trigger('command', { type: $(this).attr(kendo.attr('action')) });
                    that.popup.close();
                });
                if (navigatable) {
                    this.popup.bind('close', function () {
                        that.list.find(itemSelector).removeClass(ganttStyles.focused).end().find('ul').attr(TABINDEX, 0);
                        that.element.parents('[' + kendo.attr('role') + '="gantt"]').find(DOT + ganttStyles.gridContent + ' > table:first').focus();
                    });
                    this.list.find('ul').on('keydown' + NS, function (e) {
                        var key = e.keyCode;
                        switch (key) {
                        case keys.UP:
                            e.preventDefault();
                            that._current('prev');
                            break;
                        case keys.DOWN:
                            e.preventDefault();
                            that._current('next');
                            break;
                        case keys.ENTER:
                            that.list.find(DOT + ganttStyles.focused).click();
                            break;
                        case keys.ESC:
                            e.preventDefault();
                            that.popup.close();
                            break;
                        }
                    });
                }
            },
            _adjustListWidth: function () {
                var list = this.list;
                var ganttStyles = Gantt.styles;
                var width = list[0].style.width;
                var wrapper = this.element.find(DOT + ganttStyles.toolbar.appendButton);
                var listOuterWidth = outerWidth(list);
                var computedStyle;
                var computedWidth;
                if (!list.data(WIDTH) && width) {
                    return;
                }
                computedStyle = window.getComputedStyle ? window.getComputedStyle(wrapper[0], null) : 0;
                computedWidth = computedStyle ? parseFloat(computedStyle.width) : outerWidth(wrapper);
                if (computedStyle && (browser.mozilla || browser.msie)) {
                    computedWidth += parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) + parseFloat(computedStyle.borderLeftWidth) + parseFloat(computedStyle.borderRightWidth);
                }
                if (list.css('box-sizing') !== 'border-box') {
                    width = computedWidth - (outerWidth(list) - list.width());
                } else {
                    width = computedWidth;
                }
                if (listOuterWidth > width) {
                    width = listOuterWidth;
                }
                list.css({
                    fontFamily: wrapper.css('font-family'),
                    width: width
                }).data(WIDTH, width);
            },
            destroy: function () {
                clearTimeout(this._focusTimeout);
                this.popup.destroy();
                this.element.off(NS);
                this.list.off(NS);
                this.unbind();
            }
        });
        var createDataSource = function (type, name) {
            return function (options) {
                options = isArray(options) ? { data: options } : options;
                var dataSource = options || {};
                var data = dataSource.data;
                dataSource.data = data;
                if (!(dataSource instanceof type) && dataSource instanceof DataSource) {
                    throw new Error('Incorrect DataSource type. Only ' + name + ' instances are supported');
                }
                return dataSource instanceof type ? dataSource : new type(dataSource);
            };
        };
        var GanttDependency = kendo.data.Model.define({
            id: 'id',
            fields: {
                id: { type: 'number' },
                predecessorId: { type: 'number' },
                successorId: { type: 'number' },
                type: { type: 'number' }
            }
        });
        var GanttDependencyDataSource = DataSource.extend({
            init: function (options) {
                DataSource.fn.init.call(this, extend(true, {}, {
                    schema: {
                        modelBase: GanttDependency,
                        model: GanttDependency
                    }
                }, options));
            },
            successors: function (id) {
                return this._dependencies('predecessorId', id);
            },
            predecessors: function (id) {
                return this._dependencies('successorId', id);
            },
            dependencies: function (id) {
                var predecessors = this.predecessors(id);
                var successors = this.successors(id);
                predecessors.push.apply(predecessors, successors);
                return predecessors;
            },
            _dependencies: function (field, id) {
                var data = this.view();
                var filter = {
                    field: field,
                    operator: 'eq',
                    value: id
                };
                data = new Query(data).filter(filter).toArray();
                return data;
            }
        });
        GanttDependencyDataSource.create = createDataSource(GanttDependencyDataSource, 'GanttDependencyDataSource');
        var GanttTask = kendo.data.Model.define({
            duration: function () {
                var end = this.end;
                var start = this.start;
                return end - start;
            },
            isMilestone: function () {
                return this.duration() === 0;
            },
            _offset: function (value) {
                var field = [
                    'start',
                    'end'
                ];
                var newValue;
                for (var i = 0; i < field.length; i++) {
                    newValue = new Date(this.get(field[i]).getTime() + value);
                    this.set(field[i], newValue);
                }
            },
            id: 'id',
            fields: {
                id: { type: 'number' },
                parentId: {
                    type: 'number',
                    defaultValue: null,
                    validation: { required: true }
                },
                orderId: {
                    type: 'number',
                    validation: { required: true }
                },
                title: {
                    type: 'string',
                    defaultValue: 'New task'
                },
                start: {
                    type: 'date',
                    validation: { required: true }
                },
                end: {
                    type: 'date',
                    validation: {
                        required: true,
                        dateCompare: dateCompareValidator,
                        message: 'End date should be after or equal to the start date'
                    }
                },
                percentComplete: {
                    type: 'number',
                    validation: {
                        required: true,
                        min: 0,
                        max: 1,
                        step: 0.01
                    }
                },
                summary: { type: 'boolean' },
                expanded: {
                    type: 'boolean',
                    defaultValue: true
                }
            }
        });
        var GanttDataSource = DataSource.extend({
            init: function (options) {
                DataSource.fn.init.call(this, extend(true, {}, {
                    schema: {
                        modelBase: GanttTask,
                        model: GanttTask
                    }
                }, options));
            },
            remove: function (task) {
                var parentId = task.get('parentId');
                var children = this.taskAllChildren(task);
                this._removeItems(children);
                task = DataSource.fn.remove.call(this, task);
                this._childRemoved(parentId, task.get('orderId'));
                return task;
            },
            add: function (task) {
                if (!task) {
                    return;
                }
                task = this._toGanttTask(task);
                return this.insert(this.taskSiblings(task).length, task);
            },
            insert: function (index, task) {
                if (!task) {
                    return;
                }
                task = this._toGanttTask(task);
                task.set('orderId', index);
                task = DataSource.fn.insert.call(this, index, task);
                this._reorderSiblings(task, this.taskSiblings(task).length - 1);
                this._resolveSummaryFields(this.taskParent(task));
                return task;
            },
            taskChildren: function (task) {
                var data = this.view();
                var filter = {
                    field: 'parentId',
                    operator: 'eq',
                    value: null
                };
                var order = this._sort && this._sort.length ? this._sort : {
                    field: 'orderId',
                    dir: 'asc'
                };
                var taskId;
                if (!!task) {
                    taskId = task.get('id');
                    if (taskId === undefined || taskId === null || taskId === '') {
                        return [];
                    }
                    filter.value = taskId;
                }
                data = new Query(data).filter(filter).sort(order).toArray();
                return data;
            },
            taskAllChildren: function (task) {
                var data = [];
                var that = this;
                var callback = function (task) {
                    var tasks = that.taskChildren(task);
                    data.push.apply(data, tasks);
                    map(tasks, callback);
                };
                if (!!task) {
                    callback(task);
                } else {
                    data = this.view();
                }
                return data;
            },
            taskSiblings: function (task) {
                if (!task) {
                    return null;
                }
                var parent = this.taskParent(task);
                return this.taskChildren(parent);
            },
            taskParent: function (task) {
                if (!task || task.get('parentId') === null) {
                    return null;
                }
                return this.get(task.parentId);
            },
            taskLevel: function (task) {
                var level = 0;
                var parent = this.taskParent(task);
                while (parent !== null) {
                    level += 1;
                    parent = this.taskParent(parent);
                }
                return level;
            },
            taskTree: function (task) {
                var data = [];
                var current;
                var tasks = this.taskChildren(task);
                for (var i = 0, l = tasks.length; i < l; i++) {
                    current = tasks[i];
                    data.push(current);
                    if (current.get('expanded')) {
                        var children = this.taskTree(current);
                        data.push.apply(data, children);
                    }
                }
                return data;
            },
            update: function (task, taskInfo) {
                var that = this;
                var oldValue;
                var offsetChildren = function (parentTask, offset) {
                    var children = that.taskAllChildren(parentTask);
                    for (var i = 0, l = children.length; i < l; i++) {
                        children[i]._offset(offset);
                    }
                };
                var modelChangeHandler = function (e) {
                    var field = e.field;
                    var model = e.sender;
                    switch (field) {
                    case 'start':
                        that._resolveSummaryStart(that.taskParent(model));
                        offsetChildren(model, model.get(field).getTime() - oldValue.getTime());
                        break;
                    case 'end':
                        that._resolveSummaryEnd(that.taskParent(model));
                        break;
                    case 'percentComplete':
                        that._resolveSummaryPercentComplete(that.taskParent(model));
                        break;
                    case 'orderId':
                        that._reorderSiblings(model, oldValue);
                        break;
                    }
                };
                if (taskInfo.parentId !== undefined) {
                    oldValue = task.get('parentId');
                    if (oldValue !== taskInfo.parentId) {
                        task.set('parentId', taskInfo.parentId);
                        that._childRemoved(oldValue, task.get('orderId'));
                        task.set('orderId', that.taskSiblings(task).length - 1);
                        that._resolveSummaryFields(that.taskParent(task));
                    }
                    delete taskInfo.parentId;
                }
                task.bind('change', modelChangeHandler);
                for (var field in taskInfo) {
                    oldValue = task.get(field);
                    task.set(field, taskInfo[field]);
                }
                task.unbind('change', modelChangeHandler);
            },
            _resolveSummaryFields: function (summary) {
                if (!summary) {
                    return;
                }
                this._updateSummary(summary);
                if (!this.taskChildren(summary).length) {
                    return;
                }
                this._resolveSummaryStart(summary);
                this._resolveSummaryEnd(summary);
                this._resolveSummaryPercentComplete(summary);
            },
            _resolveSummaryStart: function (summary) {
                var that = this;
                var getSummaryStart = function (parentTask) {
                    var children = that.taskChildren(parentTask);
                    var min = children[0].start.getTime();
                    var currentMin;
                    for (var i = 1, l = children.length; i < l; i++) {
                        currentMin = children[i].start.getTime();
                        if (currentMin < min) {
                            min = currentMin;
                        }
                    }
                    return new Date(min);
                };
                this._updateSummaryRecursive(summary, 'start', getSummaryStart);
            },
            _resolveSummaryEnd: function (summary) {
                var that = this;
                var getSummaryEnd = function (parentTask) {
                    var children = that.taskChildren(parentTask);
                    var max = children[0].end.getTime();
                    var currentMax;
                    for (var i = 1, l = children.length; i < l; i++) {
                        currentMax = children[i].end.getTime();
                        if (currentMax > max) {
                            max = currentMax;
                        }
                    }
                    return new Date(max);
                };
                this._updateSummaryRecursive(summary, 'end', getSummaryEnd);
            },
            _resolveSummaryPercentComplete: function (summary) {
                var that = this;
                var getSummaryPercentComplete = function (parentTask) {
                    var children = that.taskChildren(parentTask);
                    var percentComplete = new Query(children).aggregate([{
                            field: 'percentComplete',
                            aggregate: 'average'
                        }]);
                    return percentComplete.percentComplete.average;
                };
                this._updateSummaryRecursive(summary, 'percentComplete', getSummaryPercentComplete);
            },
            _updateSummaryRecursive: function (summary, field, callback) {
                if (!summary) {
                    return;
                }
                var value = callback(summary);
                summary.set(field, value);
                var parent = this.taskParent(summary);
                if (parent) {
                    this._updateSummaryRecursive(parent, field, callback);
                }
            },
            _childRemoved: function (parentId, index) {
                var parent = parentId === null ? null : this.get(parentId);
                var children = this.taskChildren(parent);
                for (var i = index, l = children.length; i < l; i++) {
                    children[i].set('orderId', i);
                }
                this._resolveSummaryFields(parent);
            },
            _reorderSiblings: function (task, oldOrderId) {
                var orderId = task.get('orderId');
                var direction = orderId > oldOrderId;
                var startIndex = direction ? oldOrderId : orderId;
                var endIndex = direction ? orderId : oldOrderId;
                var newIndex = direction ? startIndex : startIndex + 1;
                var siblings = this.taskSiblings(task);
                endIndex = Math.min(endIndex, siblings.length - 1);
                for (var i = startIndex; i <= endIndex; i++) {
                    if (siblings[i] === task) {
                        continue;
                    }
                    siblings[i].set('orderId', newIndex);
                    newIndex += 1;
                }
            },
            _updateSummary: function (task) {
                if (task !== null) {
                    var childCount = this.taskChildren(task).length;
                    task.set('summary', childCount > 0);
                }
            },
            _toGanttTask: function (task) {
                if (!(task instanceof GanttTask)) {
                    var taskInfo = task;
                    task = this._createNewModel();
                    task.accept(taskInfo);
                }
                return task;
            }
        });
        GanttDataSource.create = createDataSource(GanttDataSource, 'GanttDataSource');
        extend(true, kendo.data, {
            GanttDataSource: GanttDataSource,
            GanttTask: GanttTask,
            GanttDependencyDataSource: GanttDependencyDataSource,
            GanttDependency: GanttDependency
        });
        var editors = {
            desktop: {
                dateRange: DATERANGEEDITOR,
                resources: RESOURCESEDITOR
            }
        };
        var Editor = kendo.Observable.extend({
            init: function (element, options) {
                kendo.Observable.fn.init.call(this);
                this.element = element;
                this.options = extend(true, {}, this.options, options);
                this.createButton = this.options.createButton;
            },
            fields: function (editors, model) {
                var that = this;
                var options = this.options;
                var messages = options.messages.editor;
                var resources = options.resources;
                var fields;
                var click = function (e) {
                    e.preventDefault();
                    resources.editor(that.container.find(DOT + Gantt.styles.popup.resourcesField), model);
                };
                if (options.editable.template) {
                    fields = $.map(model.fields, function (value, key) {
                        return { field: key };
                    });
                } else {
                    fields = [
                        {
                            field: 'title',
                            title: messages.title
                        },
                        {
                            field: 'start',
                            title: messages.start,
                            editor: editors.dateRange
                        },
                        {
                            field: 'end',
                            title: messages.end,
                            editor: editors.dateRange
                        },
                        {
                            field: 'percentComplete',
                            title: messages.percentComplete,
                            format: PERCENTAGE_FORMAT
                        }
                    ];
                    if (model.get(resources.field)) {
                        fields.push({
                            field: resources.field,
                            title: messages.resources,
                            messages: messages,
                            editor: editors.resources,
                            click: click,
                            styles: Gantt.styles.popup
                        });
                    }
                }
                return fields;
            },
            _buildEditTemplate: function (model, fields, editableFields) {
                var resources = this.options.resources;
                var template = this.options.editable.template;
                var settings = extend({}, kendo.Template, this.options.templateSettings);
                var paramName = settings.paramName;
                var popupStyles = Gantt.styles.popup;
                var html = '';
                if (template) {
                    if (typeof template === STRING) {
                        template = window.unescape(template);
                    }
                    html += kendo.template(template, settings)(model);
                } else {
                    for (var i = 0, length = fields.length; i < length; i++) {
                        var field = fields[i];
                        html += '<div class="' + popupStyles.editLabel + '"><label for="' + field.field + '">' + (field.title || field.field || '') + '</label></div>';
                        if (field.field === resources.field) {
                            html += '<div class="' + popupStyles.resourcesField + '" style="display:none"></div>';
                        }
                        if (!model.editable || model.editable(field.field)) {
                            editableFields.push(field);
                            html += '<div ' + kendo.attr('container-for') + '="' + field.field + '" class="' + popupStyles.editField + '"></div>';
                        } else {
                            var tmpl = '#:';
                            if (field.field) {
                                field = kendo.expr(field.field, paramName);
                                tmpl += field + '==null?\'\':' + field;
                            } else {
                                tmpl += '\'\'';
                            }
                            tmpl += '#';
                            tmpl = kendo.template(tmpl, settings);
                            html += '<div class="' + popupStyles.editField + '">' + tmpl(model) + '</div>';
                        }
                    }
                }
                return html;
            }
        });
        var PopupEditor = Editor.extend({
            destroy: function () {
                this.close();
                this.unbind();
            },
            editTask: function (task) {
                this.editable = this._createPopupEditor(task);
            },
            close: function () {
                var that = this;
                var destroy = function () {
                    if (that.editable) {
                        that.editable.destroy();
                        that.editable = null;
                        that.container = null;
                    }
                    if (that.popup) {
                        that.popup.destroy();
                        that.popup = null;
                    }
                };
                if (this.editable && this.container.is(':visible')) {
                    that.trigger('close', { window: that.container });
                    this.container.data('kendoWindow').bind('deactivate', destroy).close();
                } else {
                    destroy();
                }
            },
            showDialog: function (options) {
                var buttons = options.buttons;
                var popupStyles = Gantt.styles.popup;
                var html = kendo.format('<div class="{0}"><div class="{1}"><p class="{2}">{3}</p><div class="{4}">', popupStyles.form, popupStyles.formContainer, popupStyles.message, options.text, popupStyles.buttonsContainer);
                for (var i = 0, length = buttons.length; i < length; i++) {
                    html += this.createButton(buttons[i]);
                }
                html += '</div></div></div>';
                var wrapper = this.element;
                if (this.popup) {
                    this.popup.destroy();
                }
                var popup = this.popup = $(html).appendTo(wrapper).eq(0).on('click', DOT + popupStyles.button, function (e) {
                    e.preventDefault();
                    popup.close();
                    var buttonIndex = $(e.currentTarget).index();
                    buttons[buttonIndex].click();
                }).kendoWindow({
                    modal: true,
                    autoFocus: false,
                    resizable: false,
                    draggable: false,
                    title: options.title,
                    visible: false,
                    deactivate: function () {
                        this.destroy();
                        wrapper.focus();
                    }
                }).getKendoWindow();
                popup.center().open();
                popup.element.find('.k-primary').focus();
            },
            _createPopupEditor: function (task) {
                var that = this;
                var options = {};
                var messages = this.options.messages;
                var ganttStyles = Gantt.styles;
                var popupStyles = ganttStyles.popup;
                var html = kendo.format('<div {0}="{1}" class="{2} {3}"><div class="{4}">', kendo.attr('uid'), task.uid, popupStyles.form, popupStyles.editForm, popupStyles.formContainer);
                var fields = this.fields(editors.desktop, task);
                var editableFields = [];
                html += this._buildEditTemplate(task, fields, editableFields);
                html += '<div class="' + popupStyles.buttonsContainer + '">';
                html += this.createButton({
                    name: 'update',
                    text: messages.save,
                    className: Gantt.styles.primary
                });
                html += this.createButton({
                    name: 'cancel',
                    text: messages.cancel
                });
                if (that.options.editable.destroy !== false) {
                    html += this.createButton({
                        name: 'delete',
                        text: messages.destroy
                    });
                }
                html += '</div></div></div>';
                var container = this.container = $(html).appendTo(this.element).eq(0).kendoWindow(extend({
                    modal: true,
                    resizable: false,
                    draggable: true,
                    title: messages.editor.editorTitle,
                    visible: false,
                    close: function (e) {
                        if (e.userTriggered) {
                            if (that.trigger('cancel', {
                                    container: container,
                                    model: task
                                })) {
                                e.preventDefault();
                            }
                        }
                    }
                }, options));
                var editableWidget = container.kendoEditable({
                    fields: editableFields,
                    model: task,
                    clearContainer: false,
                    validateOnBlur: true,
                    target: that.options.target
                }).data('kendoEditable');
                kendo.cycleForm(container);
                if (!this.trigger('edit', {
                        container: container,
                        model: task
                    })) {
                    container.data('kendoWindow').center().open();
                    container.on(CLICK + NS, DOT + ganttStyles.buttonCancel, function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        that.trigger('cancel', {
                            container: container,
                            model: task
                        });
                    });
                    container.on(CLICK + NS, DOT + ganttStyles.buttonSave, function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        var fields = that.fields(editors.desktop, task);
                        var updateInfo = {};
                        var field;
                        for (var i = 0, length = fields.length; i < length; i++) {
                            field = fields[i].field;
                            updateInfo[field] = task.get(field);
                        }
                        that.trigger('save', {
                            container: container,
                            model: task,
                            updateInfo: updateInfo
                        });
                    });
                    container.on(CLICK + NS, DOT + ganttStyles.buttonDelete, function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        that.trigger('remove', {
                            container: container,
                            model: task
                        });
                    });
                } else {
                    that.trigger('cancel', {
                        container: container,
                        model: task
                    });
                }
                return editableWidget;
            }
        });
        var ResourceEditor = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.wrapper = this.element;
                this.model = this.options.model;
                this.resourcesField = this.options.resourcesField;
                this.createButton = this.options.createButton;
                this._initContainer();
                this._attachHandlers();
            },
            events: ['save'],
            open: function () {
                this.window.center().open();
            },
            close: function () {
                this.window.bind('deactivate', proxy(this.destroy, this)).close();
            },
            destroy: function () {
                this._dettachHandlers();
                this.grid.destroy();
                this.grid = null;
                this.window.destroy();
                this.window = null;
                Widget.fn.destroy.call(this);
                kendo.destroy(this.wrapper);
                this.element = this.wrapper = null;
            },
            _attachHandlers: function () {
                var ganttStyles = Gantt.styles;
                var grid = this.grid;
                var closeHandler = this._cancelProxy = proxy(this._cancel, this);
                this.container.on(CLICK + NS, DOT + ganttStyles.buttonCancel, this._cancelProxy);
                this._saveProxy = proxy(this._save, this);
                this.container.on(CLICK + NS, DOT + ganttStyles.buttonSave, this._saveProxy);
                this.window.bind('close', function (e) {
                    if (e.userTriggered) {
                        closeHandler(e);
                    }
                });
                grid.wrapper.on(CLICK + NS, 'input[type=\'checkbox\']', function () {
                    var element = $(this);
                    var row = $(element).closest('tr');
                    var model = grid.dataSource.getByUid(row.attr(kendo.attr('uid')));
                    var value = $(element).is(':checked') ? 1 : '';
                    model.set('value', value);
                });
            },
            _dettachHandlers: function () {
                this._cancelProxy = null;
                this._saveProxy = null;
                this.container.off(NS);
                this.grid.wrapper.off();
            },
            _cancel: function (e) {
                e.preventDefault();
                this.close();
            },
            _save: function (e) {
                e.preventDefault();
                this._updateModel();
                if (!this.wrapper.is(DOT + Gantt.styles.popup.resourcesField)) {
                    this.trigger('save', {
                        container: this.wrapper,
                        model: this.model
                    });
                }
                this.close();
            },
            _initContainer: function () {
                var that = this;
                var popupStyles = Gantt.styles.popup;
                var dom = kendo.format('<div class="{0} {1}"><div class="{2} {3}"/></div>"', popupStyles.form, popupStyles.editForm, popupStyles.formContainer, popupStyles.resourcesFormContainer);
                dom = $(dom);
                this.container = dom.find(DOT + popupStyles.resourcesFormContainer);
                this.window = dom.kendoWindow({
                    modal: true,
                    resizable: false,
                    draggable: true,
                    visible: false,
                    title: this.options.messages.resourcesEditorTitle,
                    open: function () {
                        that.grid.resize(true);
                    }
                }).data('kendoWindow');
                this._resourceGrid();
                this._createButtons();
            },
            _resourceGrid: function () {
                var that = this;
                var messages = this.options.messages;
                var element = $('<div id="resources-grid"/>').appendTo(this.container);
                this.grid = new kendo.ui.Grid(element, {
                    columns: [
                        {
                            field: 'name',
                            title: messages.resourcesHeader,
                            template: '<label><input type=\'checkbox\' value=\'#=name#\'' + '# if (value > 0 && value !== null) {#' + 'checked=\'checked\'' + '# } #' + '/>#=name#</labe>'
                        },
                        {
                            field: 'value',
                            title: messages.unitsHeader,
                            template: function (dataItem) {
                                var valueFormat = dataItem.format;
                                var value = dataItem.value !== null ? dataItem.value : '';
                                return valueFormat ? kendo.toString(value, valueFormat) : value;
                            }
                        }
                    ],
                    height: 280,
                    sortable: true,
                    editable: true,
                    filterable: true,
                    dataSource: {
                        data: that.options.data,
                        schema: {
                            model: {
                                id: 'id',
                                fields: {
                                    id: { from: 'id' },
                                    name: {
                                        from: 'name',
                                        type: 'string',
                                        editable: false
                                    },
                                    value: {
                                        from: 'value',
                                        type: 'number',
                                        validation: this.options.unitsValidation
                                    },
                                    format: {
                                        from: 'format',
                                        type: 'string'
                                    }
                                }
                            }
                        }
                    },
                    save: function (e) {
                        var value = !!e.values.value;
                        e.container.parent().find('input[type=\'checkbox\']').prop('checked', value);
                    }
                });
            },
            _createButtons: function () {
                var buttons = this.options.buttons;
                var html = '<div class="' + Gantt.styles.popup.buttonsContainer + '">';
                for (var i = 0, length = buttons.length; i < length; i++) {
                    html += this.createButton(buttons[i]);
                }
                html += '</div>';
                this.container.append(html);
            },
            _updateModel: function () {
                var resources = [];
                var value;
                var data = this.grid.dataSource.data();
                for (var i = 0, length = data.length; i < length; i++) {
                    value = data[i].get('value');
                    if (value !== null && value > 0) {
                        resources.push(data[i]);
                    }
                }
                this.model[this.resourcesField] = resources;
            }
        });
        var Gantt = Widget.extend({
            init: function (element, options, events) {
                if (isArray(options)) {
                    options = { dataSource: options };
                }
                defaultCommands = {
                    append: {
                        text: 'Add Task',
                        action: 'add',
                        className: Gantt.styles.toolbar.appendButton,
                        iconClass: Gantt.styles.toolbar.iconPlus
                    },
                    pdf: {
                        text: 'Export to PDF',
                        className: Gantt.styles.toolbar.pdfButton,
                        iconClass: Gantt.styles.toolbar.iconPdf
                    }
                };
                Widget.fn.init.call(this, element, options);
                if (events) {
                    this._events = events;
                }
                this._wrapper();
                this._resources();
                if (!this.options.views || !this.options.views.length) {
                    this.options.views = [
                        'day',
                        'week',
                        'month'
                    ];
                }
                this._timeline();
                this._toolbar();
                this._footer();
                this._adjustDimensions();
                this._preventRefresh = true;
                this.view(this.timeline._selectedViewName);
                this._preventRefresh = false;
                this._dataSource();
                this._assignments();
                this._dropDowns();
                this._list();
                this._dependencies();
                this._resizable();
                this._scrollable();
                this._dataBind();
                this._attachEvents();
                this._createEditor();
                kendo.notify(this);
            },
            events: [
                'dataBinding',
                'dataBound',
                'add',
                'edit',
                'remove',
                'cancel',
                'save',
                'change',
                'navigate',
                'moveStart',
                'move',
                'moveEnd',
                'resizeStart',
                'resize',
                'resizeEnd',
                'columnResize'
            ],
            options: {
                name: 'Gantt',
                autoBind: true,
                navigatable: false,
                selectable: true,
                editable: true,
                resizable: false,
                columnResizeHandleWidth: defaultIndicatorWidth,
                columns: [],
                views: [],
                dataSource: {},
                dependencies: {},
                resources: {},
                assignments: {},
                taskTemplate: null,
                messages: {
                    save: 'Save',
                    cancel: 'Cancel',
                    destroy: 'Delete',
                    deleteTaskConfirmation: TASK_DELETE_CONFIRM,
                    deleteDependencyConfirmation: DEPENDENCY_DELETE_CONFIRM,
                    deleteTaskWindowTitle: 'Delete task',
                    deleteDependencyWindowTitle: 'Delete dependency',
                    views: {
                        day: 'Day',
                        week: 'Week',
                        month: 'Month',
                        year: 'Year',
                        start: 'Start',
                        end: 'End'
                    },
                    actions: {
                        append: 'Add Task',
                        addChild: 'Add Child',
                        insertBefore: 'Add Above',
                        insertAfter: 'Add Below',
                        pdf: 'Export to PDF'
                    },
                    editor: {
                        editorTitle: 'Task',
                        resourcesEditorTitle: 'Resources',
                        title: 'Title',
                        start: 'Start',
                        end: 'End',
                        percentComplete: 'Complete',
                        resources: 'Resources',
                        assignButton: 'Assign',
                        resourcesHeader: 'Resources',
                        unitsHeader: 'Units'
                    }
                },
                showWorkHours: true,
                showWorkDays: true,
                toolbar: null,
                workDayStart: new Date(1980, 1, 1, 8, 0, 0),
                workDayEnd: new Date(1980, 1, 1, 17, 0, 0),
                workWeekStart: 1,
                workWeekEnd: 5,
                hourSpan: 1,
                snap: true,
                height: 600,
                listWidth: '30%',
                rowHeight: null
            },
            select: function (value) {
                var list = this.list;
                if (!value) {
                    return list.select();
                }
                list.select(value);
                this.list.element.find('table[role=treegrid]').focus();
                return;
            },
            clearSelection: function () {
                this.list.clearSelection();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (this.dataSource) {
                    this.dataSource.unbind('change', this._refreshHandler);
                    this.dataSource.unbind('progress', this._progressHandler);
                    this.dataSource.unbind('error', this._errorHandler);
                }
                if (this.dependencies) {
                    this.dependencies.unbind('change', this._dependencyRefreshHandler);
                    this.dependencies.unbind('error', this._dependencyErrorHandler);
                }
                if (this.timeline) {
                    this.timeline.unbind();
                    this.timeline.destroy();
                }
                if (this.list) {
                    this.list.unbind();
                    this.list.destroy();
                }
                if (this.footerDropDown) {
                    this.footerDropDown.destroy();
                }
                if (this.headerDropDown) {
                    this.headerDropDown.destroy();
                }
                if (this._editor) {
                    this._editor.destroy();
                }
                if (this._resizeDraggable) {
                    this._resizeDraggable.destroy();
                }
                this.toolbar.off(NS);
                if (supportsMedia) {
                    this._mediaQuery.removeListener(this._mediaQueryHandler);
                    this._mediaQuery = null;
                }
                $(window).off('resize' + NS, this._resizeHandler);
                $(this.wrapper).off(NS);
                this.toolbar = null;
                this.footer = null;
            },
            setOptions: function (options) {
                var newOptions = kendo.deepExtend({}, this.options, options);
                var events = this._events;
                if (!options.views) {
                    var selectedView = this.view().name;
                    newOptions.views = $.map(this.options.views, function (view) {
                        var isSettings = isPlainObject(view);
                        var name = isSettings ? typeof view.type !== 'string' ? view.title : view.type : view;
                        if (selectedView === name) {
                            if (isSettings) {
                                view.selected = true;
                            } else {
                                view = {
                                    type: name,
                                    selected: true
                                };
                            }
                        } else if (isSettings) {
                            view.selected = false;
                        }
                        return view;
                    });
                }
                if (!options.dataSource) {
                    newOptions.dataSource = this.dataSource;
                }
                if (!options.dependencies) {
                    newOptions.dependencies = this.dependencies;
                }
                if (!options.resources) {
                    newOptions.resources = this.resources;
                }
                if (!options.assignments) {
                    newOptions.assignments = this.assignments;
                }
                this.destroy();
                this.element.empty();
                this.options = null;
                this.init(this.element, newOptions, events);
                Widget.fn._setEvents.call(this, newOptions);
            },
            _attachEvents: function () {
                this._resizeHandler = proxy(this.resize, this, false);
                $(window).on('resize' + NS, this._resizeHandler);
            },
            _wrapper: function () {
                var ganttStyles = Gantt.styles;
                var splitBarHandleClassName = [
                    ganttStyles.icon,
                    ganttStyles.resizeHandle
                ].join(' ');
                var options = this.options;
                var height = options.height;
                var width = options.width;
                this.wrapper = this.element.addClass(ganttStyles.wrapper).append('<div class=\'' + ganttStyles.listWrapper + '\'><div></div></div>').append('<div class=\'' + ganttStyles.splitBarWrapper + '\'><div class=\'' + splitBarHandleClassName + '\'></div></div>').append('<div class=\'' + ganttStyles.timelineWrapper + '\'><div></div></div>');
                this.wrapper.find(DOT + ganttStyles.list).width(options.listWidth);
                if (height) {
                    this.wrapper.height(height);
                }
                if (width) {
                    this.wrapper.width(width);
                }
                if (options.rowHeight) {
                    this.wrapper.addClass(ganttStyles.rowHeight);
                }
            },
            _toolbar: function () {
                var that = this;
                var ganttStyles = Gantt.styles;
                var viewsSelector = DOT + ganttStyles.toolbar.views + ' > li';
                var pdfSelector = DOT + ganttStyles.toolbar.pdfButton;
                var toggleSelector = DOT + ganttStyles.buttonToggle;
                var contentSelector = DOT + ganttStyles.gridContent;
                var treelist = $(DOT + ganttStyles.list);
                var timeline = $(DOT + ganttStyles.timeline);
                var hoveredClassName = ganttStyles.hovered;
                var actions = this.options.toolbar;
                var actionsWrap = $('<div class=\'' + ganttStyles.toolbar.actions + '\'>');
                var toolbar;
                var views;
                var toggleButton;
                var handler = function (e) {
                    if (e.matches) {
                        treelist.css({
                            'display': 'none',
                            'max-width': 0
                        });
                    } else {
                        treelist.css({
                            'display': 'inline-block',
                            'width': '30%',
                            'max-width': 'none'
                        });
                        timeline.css('display', 'inline-block');
                        that.refresh();
                        timeline.find(contentSelector).scrollTop(that.scrollTop);
                    }
                    that._resize();
                };
                if (!isFunction(actions)) {
                    actions = typeof actions === STRING ? actions : this._actions(actions);
                    actions = proxy(kendo.template(actions), this);
                }
                toggleButton = $(TOGGLE_BUTTON_TEMPLATE({ styles: ganttStyles.toolbar }));
                views = $(HEADER_VIEWS_TEMPLATE({
                    ns: kendo.ns,
                    views: this.timeline.views,
                    styles: ganttStyles.toolbar
                }));
                actionsWrap.append(actions({}));
                toolbar = $('<div class=\'' + ganttStyles.toolbar.headerWrapper + '\'>').append(toggleButton).append(views).append(actionsWrap);
                if (views.find('li').length > 1) {
                    views.prepend(VIEWBUTTONTEMPLATE({ styles: ganttStyles.toolbar }));
                }
                this.wrapper.prepend(toolbar);
                this.toolbar = toolbar;
                if (supportsMedia) {
                    this._mediaQueryHandler = proxy(handler, this);
                    this._mediaQuery = window.matchMedia('(max-width: 480px)');
                    this._mediaQuery.addListener(this._mediaQueryHandler);
                }
                toolbar.on(CLICK + NS, viewsSelector, function (e) {
                    e.preventDefault();
                    var list = that.list;
                    var name = $(this).attr(kendo.attr('name'));
                    var currentView = views.find(DOT + ganttStyles.toolbar.currentView);
                    if (currentView.is(':visible')) {
                        currentView.parent().toggleClass(ganttStyles.toolbar.expanded);
                    }
                    if (list.editable && list.editable.trigger('validate')) {
                        return;
                    }
                    if (!that.trigger('navigate', { view: name })) {
                        that.view(name);
                    }
                    that.toolbar.find(DOT + ganttStyles.focused).removeClass(ganttStyles.focused);
                }).on('keydown' + NS, viewsSelector, function (e) {
                    var views = $(DOT + ganttStyles.toolbar.views).children(':not(.k-current-view)');
                    var focusedViewIndex = views.index(that._focusedView && that._focusedView[0] || views.closest(DOT + ganttStyles.selected)[0]);
                    if (e.keyCode === keys.RIGHT) {
                        $(that.toolbar.find(DOT + ganttStyles.focused)).removeClass(ganttStyles.focused);
                        that._focusedView = focusedViewIndex + 1 === views.length ? $(views[0]) : $(views[focusedViewIndex + 1]);
                        that._focusedView.focus().addClass(ganttStyles.focused);
                        e.preventDefault();
                    } else if (e.keyCode === keys.LEFT) {
                        $(that.toolbar.find(DOT + ganttStyles.focused)).removeClass(ganttStyles.focused);
                        that._focusedView = focusedViewIndex === 0 ? $(views[views.length - 1]) : $(views[focusedViewIndex - 1]);
                        that._focusedView.focus().addClass(ganttStyles.focused);
                        e.preventDefault();
                    } else if (e.keyCode === keys.DOWN && that.toolbar.find(DOT + ganttStyles.toolbar.currentView).parent().hasClass(ganttStyles.toolbar.expanded)) {
                        $(that.toolbar.find(DOT + ganttStyles.focused)).removeClass(ganttStyles.focused);
                        that._focusedView = focusedViewIndex + 1 === views.length ? $(views[0]) : $(views[focusedViewIndex + 1]);
                        that._focusedView.focus().addClass(ganttStyles.focused);
                        e.preventDefault();
                    } else if (e.keyCode === keys.UP && that.toolbar.find(DOT + ganttStyles.toolbar.currentView).parent().hasClass(ganttStyles.toolbar.expanded)) {
                        $(that.toolbar.find(DOT + ganttStyles.focused)).removeClass(ganttStyles.focused);
                        that._focusedView = focusedViewIndex === 0 ? $(views[views.length - 1]) : $(views[focusedViewIndex - 1]);
                        that._focusedView.focus().addClass(ganttStyles.focused);
                        e.preventDefault();
                    } else if ((e.keyCode === keys.ENTER || e.keyCode === keys.SPACEBAR) && that._focusedView) {
                        that.view(that._focusedView.text().toLowerCase());
                        e.preventDefault();
                    } else if ((e.keyCode === keys.SPACEBAR || e.keyCode === keys.ENTER || e.keyCode === keys.DOWN && e.altKey) && that.toolbar.find(DOT + ganttStyles.toolbar.currentView + ' > a').hasClass(ganttStyles.focused)) {
                        that.toolbar.find(DOT + ganttStyles.toolbar.currentView).parent().toggleClass(ganttStyles.toolbar.expanded);
                        e.preventDefault();
                    } else if (e.keyCode === keys.ESC && that.toolbar.find(DOT + ganttStyles.toolbar.currentView).parent().hasClass(ganttStyles.toolbar.expanded)) {
                        that.toolbar.find(DOT + ganttStyles.toolbar.currentView).parent().toggleClass(ganttStyles.toolbar.expanded).blur();
                        that._focusedView = null;
                        that.toolbar.find(DOT + ganttStyles.toolbar.currentView + ' > a').addClass(ganttStyles.focused).focus();
                        e.preventDefault();
                    } else if (e.keyCode >= 49 && e.keyCode <= 57) {
                        that.view(that.timeline._viewByIndex(e.keyCode - 49));
                    }
                }).on(CLICK + NS, pdfSelector, function (e) {
                    e.preventDefault();
                    that.saveAsPDF();
                }).on(CLICK + NS, toggleSelector, function (e) {
                    e.preventDefault();
                    if (treelist.is(':visible')) {
                        treelist.css({
                            'display': 'none',
                            'width': '0'
                        });
                        timeline.css({
                            'display': 'inline-block',
                            'width': '100%'
                        });
                        that.refresh();
                        timeline.find(contentSelector).scrollTop(that.scrollTop);
                    } else {
                        timeline.css({
                            'display': 'none',
                            'width': 0
                        });
                        treelist.css({
                            'display': 'inline-block',
                            'width': '100%',
                            'max-width': 'none'
                        }).find(contentSelector).scrollTop(that.scrollTop);
                    }
                    that._resize();
                });
                this.wrapper.on('focusout' + NS, function (e) {
                    if (!$(e.relatedTarget).closest(DOT + ganttStyles.toolbar.toolbar).length) {
                        that.toolbar.find(DOT + ganttStyles.focused).removeClass(ganttStyles.focused);
                    }
                    if (!$(e.relatedTarget).closest(DOT + ganttStyles.toolbar.views).length) {
                        that.toolbar.find(DOT + ganttStyles.toolbar.views).removeClass(ganttStyles.toolbar.expanded);
                    }
                }).find(DOT + ganttStyles.toolbar.toolbar + ' li').hover(function () {
                    $(this).addClass(hoveredClassName);
                }, function () {
                    $(this).removeClass(hoveredClassName);
                });
            },
            _actions: function () {
                var options = this.options;
                var editable = options.editable;
                var actions = options.toolbar;
                var html = '';
                if (!isArray(actions)) {
                    if (editable && editable.create !== false) {
                        actions = ['append'];
                    } else {
                        return html;
                    }
                }
                for (var i = 0, length = actions.length; i < length; i++) {
                    html += this._createButton(actions[i]);
                }
                return html;
            },
            _footer: function () {
                var editable = this.options.editable;
                if (!editable || editable.create === false) {
                    return;
                }
                var ganttStyles = Gantt.styles.toolbar;
                var messages = this.options.messages.actions;
                var button = $(kendo.template(BUTTON_TEMPLATE)(extend(true, { styles: ganttStyles }, defaultCommands.append, { text: messages.append })));
                var actionsWrap = $('<div class=\'' + ganttStyles.actions + '\'>').append(button);
                var footer = $('<div class=\'' + ganttStyles.footerWrapper + '\'>').append(actionsWrap);
                this.wrapper.append(footer);
                this.footer = footer;
            },
            _createButton: function (command) {
                var template = command.template || BUTTON_TEMPLATE;
                var messages = this.options.messages.actions;
                var commandName = typeof command === STRING ? command : command.name || command.text;
                var className = defaultCommands[commandName] ? defaultCommands[commandName].className : 'k-gantt-' + (commandName || '').replace(/\s/g, '');
                var options = {
                    iconClass: '',
                    action: '',
                    text: commandName,
                    className: className,
                    styles: Gantt.styles.toolbar
                };
                if (!commandName && !(isPlainObject(command) && command.template)) {
                    throw new Error('Custom commands should have name specified');
                }
                options = extend(true, options, defaultCommands[commandName], { text: messages[commandName] });
                if (isPlainObject(command)) {
                    if (command.className && inArray(options.className, command.className.split(' ')) < 0) {
                        command.className += ' ' + options.className;
                    }
                    options = extend(true, options, command);
                }
                return kendo.template(template)(options);
            },
            _adjustDimensions: function () {
                var element = this.element;
                var ganttStyles = Gantt.styles;
                var listSelector = DOT + ganttStyles.list;
                var timelineSelector = DOT + ganttStyles.timeline;
                var splitBarSelector = DOT + ganttStyles.splitBar;
                var toolbarHeight = outerHeight(this.toolbar);
                var footerHeight = this.footer ? outerHeight(this.footer) : 0;
                var totalHeight = element.height();
                var totalWidth = element.width();
                var splitBarWidth = outerWidth(element.find(splitBarSelector));
                var treeListWidth = outerWidth(element.find(listSelector));
                element.children([
                    listSelector,
                    timelineSelector,
                    splitBarSelector
                ].join(',')).height(totalHeight - (toolbarHeight + footerHeight)).end().children(timelineSelector).width(totalWidth - (splitBarWidth + treeListWidth));
                if (totalWidth < treeListWidth + splitBarWidth) {
                    element.find(listSelector).width(totalWidth - splitBarWidth);
                }
            },
            _scrollTo: function (value) {
                var view = this.timeline.view();
                var list = this.list;
                var attr = kendo.attr('uid');
                var id = typeof value === 'string' ? value : value.closest('tr' + selector()).attr(attr);
                var action;
                var scrollTarget;
                var scrollIntoView = function () {
                    if (scrollTarget.length !== 0) {
                        action();
                    }
                };
                if (view.content.is(':visible')) {
                    scrollTarget = view.content.find(selector(id));
                    action = function () {
                        view._scrollTo(scrollTarget);
                    };
                } else {
                    scrollTarget = list.content.find(selector(id));
                    action = function () {
                        scrollTarget.get(0).scrollIntoView();
                    };
                }
                scrollIntoView();
            },
            _dropDowns: function () {
                var that = this;
                var actionsSelector = DOT + Gantt.styles.toolbar.actions;
                var actionMessages = this.options.messages.actions;
                var timeline = this.timeline;
                var editable = this.options.editable;
                var handler = function (e) {
                    var type = e.type;
                    var orderId;
                    var dataSource = that.dataSource;
                    var task = dataSource._createNewModel();
                    var selected = that.dataItem(that.select());
                    var parent = dataSource.taskParent(selected);
                    var firstSlot = timeline.view()._timeSlots()[0];
                    var target = type === 'add' ? selected : parent;
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        return;
                    }
                    task.set('title', 'New task');
                    if (target) {
                        task.set('parentId', target.get('id'));
                        task.set('start', target.get('start'));
                        task.set('end', target.get('end'));
                    } else {
                        task.set('start', firstSlot.start);
                        task.set('end', firstSlot.end);
                    }
                    if (type !== 'add') {
                        orderId = selected.get('orderId');
                        orderId = type === 'insert-before' ? orderId : orderId + 1;
                    }
                    that._createTask(task, orderId);
                };
                if (!editable || editable.create === false) {
                    return;
                }
                this.footerDropDown = new TaskDropDown(this.footer.children(actionsSelector).eq(0), {
                    messages: { actions: actionMessages },
                    direction: 'up',
                    animation: { open: { effects: 'slideIn:up' } },
                    navigatable: that.options.navigatable
                });
                this.headerDropDown = new TaskDropDown(this.toolbar.children(actionsSelector).eq(0), {
                    messages: { actions: actionMessages },
                    navigatable: that.options.navigatable
                });
                this.footerDropDown.bind('command', handler);
                this.headerDropDown.bind('command', handler);
            },
            _list: function () {
                var that = this;
                var navigatable = that.options.navigatable;
                var ganttStyles = Gantt.styles;
                var listWrapper = this.wrapper.find(DOT + ganttStyles.list);
                var element = listWrapper.find('> div');
                var toggleButtons = this.wrapper.find(DOT + ganttStyles.toolbar.actions + ' > button');
                var options = {
                    columns: this.options.columns || [],
                    dataSource: this.dataSource,
                    selectable: this.options.selectable,
                    editable: this.options.editable,
                    resizable: this.options.resizable,
                    columnResizeHandleWidth: this.options.columnResizeHandleWidth,
                    listWidth: outerWidth(listWrapper),
                    resourcesField: this.resources.field,
                    rowHeight: this.options.rowHeight
                };
                var columns = options.columns;
                var column;
                var restoreFocus = function () {
                    if (navigatable) {
                        that._current(that._cachedCurrent);
                        focusTable(that.list.content.find('table'), true);
                    }
                    delete that._cachedCurrent;
                };
                for (var i = 0; i < columns.length; i++) {
                    column = columns[i];
                    if (column.field === this.resources.field && typeof column.editor !== 'function') {
                        column.editor = proxy(this._createResourceEditor, this);
                    }
                }
                this.list = new kendo.ui.GanttList(element, options);
                this.list.bind('render', function () {
                    that._navigatable();
                }, true).bind('edit', function (e) {
                    that._cachedCurrent = e.cell;
                    if (that.trigger('edit', {
                            task: e.model,
                            container: e.cell
                        })) {
                        e.preventDefault();
                    }
                }).bind('cancel', function (e) {
                    if (that.trigger('cancel', {
                            task: e.model,
                            container: e.cell
                        })) {
                        e.preventDefault();
                    }
                    restoreFocus();
                }).bind('update', function (e) {
                    that._updateTask(e.task, e.updateInfo);
                    restoreFocus();
                }).bind('change', function () {
                    that.trigger('change');
                    var selection = that.list.select();
                    if (selection.length) {
                        toggleButtons.removeAttr('data-action', 'add');
                        that.timeline.select('[data-uid=\'' + selection.attr('data-uid') + '\']');
                    } else {
                        toggleButtons.attr('data-action', 'add');
                        that.timeline.clearSelection();
                    }
                }).bind('columnResize', function (e) {
                    that.trigger('columnResize', {
                        column: e.column,
                        oldWidth: e.oldWidth,
                        newWidth: e.newWidth
                    });
                });
            },
            _timeline: function () {
                var that = this;
                var ganttStyles = Gantt.styles;
                var options = trimOptions(extend(true, { resourcesField: this.resources.field }, this.options));
                var element = this.wrapper.find(DOT + ganttStyles.timeline + ' > div');
                var currentViewSelector = DOT + ganttStyles.toolbar.currentView + ' > ' + DOT + ganttStyles.toolbar.link;
                this.timeline = new kendo.ui.GanttTimeline(element, options);
                this.timeline.bind('navigate', function (e) {
                    var viewName = e.view.replace(/\./g, '\\.').toLowerCase();
                    var text = that.toolbar.find(DOT + ganttStyles.toolbar.views + ' > li').removeClass(ganttStyles.selected).end().find(DOT + ganttStyles.toolbar.viewButton + '-' + viewName).addClass(ganttStyles.selected).find(DOT + ganttStyles.toolbar.link).text();
                    that.toolbar.find(currentViewSelector).text(text);
                    that.refresh();
                }).bind('moveStart', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        e.preventDefault();
                        return;
                    }
                    if (that.trigger('moveStart', { task: e.task })) {
                        e.preventDefault();
                    }
                }).bind('move', function (e) {
                    var task = e.task;
                    var start = e.start;
                    var end = new Date(start.getTime() + task.duration());
                    if (that.trigger('move', {
                            task: task,
                            start: start,
                            end: end
                        })) {
                        e.preventDefault();
                    }
                }).bind('moveEnd', function (e) {
                    var task = e.task;
                    var start = e.start;
                    var end = new Date(start.getTime() + task.duration());
                    if (!that.trigger('moveEnd', {
                            task: task,
                            start: start,
                            end: end
                        })) {
                        that._updateTask(that.dataSource.getByUid(task.uid), {
                            start: start,
                            end: end
                        });
                    }
                }).bind('resizeStart', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        e.preventDefault();
                        return;
                    }
                    if (that.trigger('resizeStart', { task: e.task })) {
                        e.preventDefault();
                    }
                }).bind('resize', function (e) {
                    if (that.trigger('resize', {
                            task: e.task,
                            start: e.start,
                            end: e.end
                        })) {
                        e.preventDefault();
                    }
                }).bind('resizeEnd', function (e) {
                    var task = e.task;
                    var updateInfo = {};
                    if (e.resizeStart) {
                        updateInfo.start = e.start;
                    } else {
                        updateInfo.end = e.end;
                    }
                    if (!that.trigger('resizeEnd', {
                            task: task,
                            start: e.start,
                            end: e.end
                        })) {
                        that._updateTask(that.dataSource.getByUid(task.uid), updateInfo);
                    }
                }).bind('percentResizeStart', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        e.preventDefault();
                    }
                }).bind('percentResizeEnd', function (e) {
                    that._updateTask(that.dataSource.getByUid(e.task.uid), { percentComplete: e.percentComplete });
                }).bind('dependencyDragStart', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        e.preventDefault();
                    }
                }).bind('dependencyDragEnd', function (e) {
                    var dependency = that.dependencies._createNewModel({
                        type: e.type,
                        predecessorId: e.predecessor.id,
                        successorId: e.successor.id
                    });
                    that._createDependency(dependency);
                }).bind('select', function (e) {
                    var editable = that.list.editable;
                    if (editable) {
                        editable.trigger('validate');
                    }
                    that.select('[data-uid=\'' + e.uid + '\']');
                }).bind('editTask', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        return;
                    }
                    that.editTask(e.uid);
                }).bind('clear', function () {
                    that.clearSelection();
                }).bind('removeTask', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        return;
                    }
                    that.removeTask(that.dataSource.getByUid(e.uid));
                }).bind('removeDependency', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        return;
                    }
                    that.removeDependency(that.dependencies.getByUid(e.uid));
                });
            },
            _dataSource: function () {
                var options = this.options;
                var dataSource = options.dataSource;
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                if (this.dataSource && this._refreshHandler) {
                    this.dataSource.unbind('change', this._refreshHandler).unbind('progress', this._progressHandler).unbind('error', this._errorHandler);
                } else {
                    this._refreshHandler = proxy(this.refresh, this);
                    this._progressHandler = proxy(this._requestStart, this);
                    this._errorHandler = proxy(this._error, this);
                }
                this.dataSource = kendo.data.GanttDataSource.create(dataSource).bind('change', this._refreshHandler).bind('progress', this._progressHandler).bind('error', this._errorHandler);
            },
            _dependencies: function () {
                var dependencies = this.options.dependencies || {};
                var dataSource = isArray(dependencies) ? { data: dependencies } : dependencies;
                if (this.dependencies && this._dependencyRefreshHandler) {
                    this.dependencies.unbind('change', this._dependencyRefreshHandler).unbind('error', this._dependencyErrorHandler);
                } else {
                    this._dependencyRefreshHandler = proxy(this.refreshDependencies, this);
                    this._dependencyErrorHandler = proxy(this._error, this);
                }
                this.dependencies = kendo.data.GanttDependencyDataSource.create(dataSource).bind('change', this._dependencyRefreshHandler).bind('error', this._dependencyErrorHandler);
            },
            _resources: function () {
                var resources = this.options.resources;
                var dataSource = resources.dataSource || {};
                this.resources = {
                    field: 'resources',
                    dataTextField: 'name',
                    dataColorField: 'color',
                    dataFormatField: 'format'
                };
                extend(this.resources, resources);
                this.resources.dataSource = kendo.data.DataSource.create(dataSource);
            },
            _assignments: function () {
                var assignments = this.options.assignments;
                var dataSource = assignments.dataSource || {};
                if (this.assignments) {
                    this.assignments.dataSource.unbind('change', this._assignmentsRefreshHandler);
                } else {
                    this._assignmentsRefreshHandler = proxy(this.refresh, this);
                }
                this.assignments = {
                    dataTaskIdField: 'taskId',
                    dataResourceIdField: 'resourceId',
                    dataValueField: 'value'
                };
                extend(this.assignments, assignments);
                this.assignments.dataSource = kendo.data.DataSource.create(dataSource);
                this.assignments.dataSource.bind('change', this._assignmentsRefreshHandler);
            },
            _createEditor: function () {
                var that = this;
                var editor = this._editor = new PopupEditor(this.wrapper, extend({}, this.options, {
                    target: this,
                    resources: {
                        field: this.resources.field,
                        editor: proxy(this._createResourceEditor, this)
                    },
                    createButton: proxy(this._createPopupButton, this)
                }));
                editor.bind('cancel', function (e) {
                    var task = that.dataSource.getByUid(e.model.uid);
                    if (that.trigger('cancel', {
                            container: e.container,
                            task: task
                        })) {
                        e.preventDefault();
                        return;
                    }
                    that.cancelTask();
                }).bind('edit', function (e) {
                    var task = that.dataSource.getByUid(e.model.uid);
                    if (that.trigger('edit', {
                            container: e.container,
                            task: task
                        })) {
                        e.preventDefault();
                    }
                }).bind('save', function (e) {
                    var task = that.dataSource.getByUid(e.model.uid);
                    that.saveTask(task, e.updateInfo);
                }).bind('remove', function (e) {
                    that.removeTask(e.model.uid);
                }).bind('close', that._onDialogClose);
            },
            _onDialogClose: function () {
            },
            _createResourceEditor: function (container, options) {
                var that = this;
                var model = options instanceof ObservableObject ? options : options.model;
                var id = model.get('id');
                var messages = this.options.messages;
                var resourcesField = this.resources.field;
                var unitsValidation = { step: 0.01 };
                var assignmentsModel = this.assignments.dataSource.options.schema.model;
                if (assignmentsModel && assignmentsModel.fields.Units && assignmentsModel.fields.Units.validation) {
                    extend(true, unitsValidation, assignmentsModel.fields.Units.validation);
                }
                var editor = this._resourceEditor = new ResourceEditor(container, {
                    resourcesField: resourcesField,
                    unitsValidation: unitsValidation,
                    data: this._wrapResourceData(id),
                    model: model,
                    messages: extend({}, messages.editor),
                    buttons: [
                        {
                            name: 'update',
                            text: messages.save,
                            className: Gantt.styles.primary
                        },
                        {
                            name: 'cancel',
                            text: messages.cancel
                        }
                    ],
                    createButton: proxy(this._createPopupButton, this),
                    save: function (e) {
                        that._updateAssignments(e.model.get('id'), e.model.get(resourcesField));
                    }
                });
                editor.open();
            },
            _createPopupButton: function (command) {
                var commandName = command.name || command.text;
                var options = {
                    className: Gantt.styles.popup.button + ' k-gantt-' + (commandName || '').replace(/\s/g, ''),
                    text: commandName,
                    attr: ''
                };
                if (!commandName && !(isPlainObject(command) && command.template)) {
                    throw new Error('Custom commands should have name specified');
                }
                if (isPlainObject(command)) {
                    if (command.className) {
                        command.className += ' ' + options.className;
                    }
                    options = extend(true, options, command);
                }
                return kendo.template(COMMAND_BUTTON_TEMPLATE)(options);
            },
            view: function (type) {
                return this.timeline.view(type);
            },
            range: function (range) {
                var dataSource = this.dataSource;
                var view = this.view();
                var timeline = this.timeline;
                if (range) {
                    view.options.range = {
                        start: range.start,
                        end: range.end
                    };
                    timeline._render(dataSource.taskTree());
                    timeline._renderDependencies(this.dependencies.view());
                }
                return {
                    start: view.start,
                    end: view.end
                };
            },
            date: function (date) {
                var view = this.view();
                if (date) {
                    view.options.date = date;
                    view._scrollToDate(date);
                }
                return view.options.date;
            },
            dataItem: function (value) {
                if (!value) {
                    return null;
                }
                var list = this.list;
                var element = list.content.find(value);
                return list._modelFromElement(element);
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                this.list._setDataSource(this.dataSource);
                if (this.options.autoBind) {
                    dataSource.fetch();
                }
            },
            setDependenciesDataSource: function (dependencies) {
                this.options.dependencies = dependencies;
                this._dependencies();
                if (this.options.autoBind) {
                    dependencies.fetch();
                }
            },
            items: function () {
                return this.wrapper.children('.k-task');
            },
            _updateAssignments: function (id, resources) {
                var dataSource = this.assignments.dataSource;
                var taskId = this.assignments.dataTaskIdField;
                var resourceId = this.assignments.dataResourceIdField;
                var hasMatch = false;
                var assignments = new Query(dataSource.view()).filter({
                    field: taskId,
                    operator: 'eq',
                    value: id
                }).toArray();
                var assignment;
                var resource;
                var value;
                while (assignments.length) {
                    assignment = assignments[0];
                    for (var i = 0, length = resources.length; i < length; i++) {
                        resource = resources[i];
                        if (assignment.get(resourceId) === resource.get('id')) {
                            value = resources[i].get('value');
                            this._updateAssignment(assignment, value);
                            resources.splice(i, 1);
                            hasMatch = true;
                            break;
                        }
                    }
                    if (!hasMatch) {
                        this._removeAssignment(assignment);
                    }
                    hasMatch = false;
                    assignments.shift();
                }
                for (var j = 0, newLength = resources.length; j < newLength; j++) {
                    resource = resources[j];
                    this._createAssignment(resource, id);
                }
                dataSource.sync();
            },
            cancelTask: function () {
                var editor = this._editor;
                var container = editor.container;
                if (container) {
                    editor.close();
                }
            },
            editTask: function (uid) {
                var task = typeof uid === 'string' ? this.dataSource.getByUid(uid) : uid;
                if (!task) {
                    return;
                }
                var taskCopy = this.dataSource._createNewModel(task.toJSON());
                taskCopy.uid = task.uid;
                this.cancelTask();
                this._editTask(taskCopy);
            },
            _editTask: function (task) {
                this._editor.editTask(task);
            },
            saveTask: function (task, updateInfo) {
                var editor = this._editor;
                var container = editor.container;
                var editable = editor.editable;
                if (container && editable && editable.end()) {
                    this._updateTask(task, updateInfo);
                }
            },
            _updateTask: function (task, updateInfo) {
                var resourcesField = this.resources.field;
                if (!this.trigger('save', {
                        task: task,
                        values: updateInfo
                    })) {
                    this._preventRefresh = true;
                    this.dataSource.update(task, updateInfo);
                    if (updateInfo[resourcesField]) {
                        this._updateAssignments(task.get('id'), updateInfo[resourcesField]);
                    }
                    this._syncDataSource();
                }
            },
            _updateAssignment: function (assignment, value) {
                var resourceValueField = this.assignments.dataValueField;
                assignment.set(resourceValueField, value);
            },
            removeTask: function (uid) {
                var that = this;
                var task = typeof uid === 'string' ? this.dataSource.getByUid(uid) : uid;
                if (!task) {
                    return;
                }
                this._taskConfirm(function (cancel) {
                    if (!cancel) {
                        that._removeTask(task);
                    }
                }, task);
            },
            _createTask: function (task, index) {
                if (!this.trigger('add', {
                        task: task,
                        dependency: null
                    })) {
                    var dataSource = this.dataSource;
                    this._preventRefresh = true;
                    if (index === undefined) {
                        dataSource.add(task);
                    } else {
                        dataSource.insert(index, task);
                    }
                    this._scrollToUid = task.uid;
                    this._syncDataSource();
                }
            },
            _createDependency: function (dependency) {
                if (!this.trigger('add', {
                        task: null,
                        dependency: dependency
                    })) {
                    this._preventDependencyRefresh = true;
                    this.dependencies.add(dependency);
                    this._preventDependencyRefresh = false;
                    this.dependencies.sync();
                }
            },
            _createAssignment: function (resource, id) {
                var assignments = this.assignments;
                var dataSource = assignments.dataSource;
                var taskId = assignments.dataTaskIdField;
                var resourceId = assignments.dataResourceIdField;
                var resourceValue = assignments.dataValueField;
                var assignment = dataSource._createNewModel();
                assignment[taskId] = id;
                assignment[resourceId] = resource.get('id');
                assignment[resourceValue] = resource.get('value');
                dataSource.add(assignment);
            },
            removeDependency: function (uid) {
                var that = this;
                var dependency = typeof uid === 'string' ? this.dependencies.getByUid(uid) : uid;
                if (!dependency) {
                    return;
                }
                this._dependencyConfirm(function (cancel) {
                    if (!cancel) {
                        that._removeDependency(dependency);
                    }
                }, dependency);
            },
            _removeTaskDependencies: function (task, dependencies) {
                this._preventDependencyRefresh = true;
                for (var i = 0, length = dependencies.length; i < length; i++) {
                    this.dependencies.remove(dependencies[i]);
                }
                this._preventDependencyRefresh = false;
                this.dependencies.sync();
            },
            _removeTaskAssignments: function (task) {
                var dataSource = this.assignments.dataSource;
                var assignments = dataSource.view();
                var filter = {
                    field: this.assignments.dataTaskIdField,
                    operator: 'eq',
                    value: task.get('id')
                };
                assignments = new Query(assignments).filter(filter).toArray();
                this._preventRefresh = true;
                for (var i = 0, length = assignments.length; i < length; i++) {
                    dataSource.remove(assignments[i]);
                }
                this._preventRefresh = false;
                dataSource.sync();
            },
            _removeTask: function (task) {
                var dependencies = this.dependencies.dependencies(task.id);
                if (!this.trigger('remove', {
                        task: task,
                        dependencies: dependencies
                    })) {
                    this._removeTaskDependencies(task, dependencies);
                    this._removeTaskAssignments(task);
                    this._preventRefresh = true;
                    if (this.dataSource.remove(task)) {
                        this._syncDataSource();
                    }
                    this._preventRefresh = false;
                }
            },
            _removeDependency: function (dependency) {
                if (!this.trigger('remove', {
                        task: null,
                        dependencies: [dependency]
                    })) {
                    if (this.dependencies.remove(dependency)) {
                        this.dependencies.sync();
                    }
                }
            },
            _removeAssignment: function (assignment) {
                this.assignments.dataSource.remove(assignment);
            },
            _taskConfirm: function (callback, task) {
                var messages = this.options.messages;
                this._confirm(callback, {
                    model: task,
                    text: messages.deleteTaskConfirmation,
                    title: messages.deleteTaskWindowTitle
                });
            },
            _dependencyConfirm: function (callback, dependency) {
                var messages = this.options.messages;
                this._confirm(callback, {
                    model: dependency,
                    text: messages.deleteDependencyConfirmation,
                    title: messages.deleteDependencyWindowTitle
                });
            },
            _confirm: function (callback, options) {
                var editable = this.options.editable;
                var messages;
                var buttons;
                if (editable === true || editable.confirmation !== false) {
                    messages = this.options.messages;
                    buttons = [
                        {
                            name: 'delete',
                            text: messages.destroy,
                            className: Gantt.styles.primary,
                            click: function () {
                                callback();
                            }
                        },
                        {
                            name: 'cancel',
                            text: messages.cancel,
                            click: function () {
                                callback(true);
                            }
                        }
                    ];
                    this.showDialog(extend(true, {}, options, { buttons: buttons }));
                } else {
                    callback();
                }
            },
            showDialog: function (options) {
                this._editor.showDialog(options);
            },
            refresh: function () {
                if (this._preventRefresh || this.list.editable) {
                    return;
                }
                this._progress(false);
                var dataSource = this.dataSource;
                var taskTree = dataSource.taskTree();
                var scrollToUid = this._scrollToUid;
                var current;
                var cachedUid;
                var cachedIndex = -1;
                if (this.current) {
                    cachedUid = this.current.closest('tr').attr(kendo.attr('uid'));
                    cachedIndex = this.current.index();
                }
                if (this.trigger('dataBinding')) {
                    return;
                }
                if (this.resources.dataSource.data().length !== 0) {
                    this._assignResources(taskTree);
                }
                if (this._editor) {
                    this._editor.close();
                }
                this.clearSelection();
                this.list._render(taskTree);
                this.timeline._render(taskTree);
                this.timeline._renderDependencies(this.dependencies.view());
                if (scrollToUid) {
                    this._scrollTo(scrollToUid);
                    this.select(selector(scrollToUid));
                }
                if ((scrollToUid || cachedUid) && cachedIndex >= 0) {
                    current = this.list.content.find('tr' + selector(scrollToUid || cachedUid) + ' > td:eq(' + cachedIndex + ')');
                    this._current(current);
                }
                this._scrollToUid = null;
                this.trigger('dataBound');
            },
            refreshDependencies: function () {
                if (this._preventDependencyRefresh) {
                    return;
                }
                if (this.trigger('dataBinding')) {
                    return;
                }
                this.timeline._renderDependencies(this.dependencies.view());
                this.trigger('dataBound');
            },
            _assignResources: function (taskTree) {
                var resources = this.resources;
                var assignments = this.assignments;
                var groupAssigments = function () {
                    var data = assignments.dataSource.view();
                    var group = { field: assignments.dataTaskIdField };
                    data = new Query(data).group(group).toArray();
                    return data;
                };
                var assigments = groupAssigments();
                var applyTaskResource = function (task, action) {
                    var taskId = task.get('id');
                    kendo.setter(resources.field)(task, new ObservableArray([]));
                    for (var i = 0, length = assigments.length; i < length; i++) {
                        if (assigments[i].value === taskId) {
                            action(task, assigments[i].items);
                        }
                    }
                };
                var wrapTask = function (task, items) {
                    for (var j = 0, length = items.length; j < length; j++) {
                        var item = items[j];
                        var resource = resources.dataSource.get(item.get(assignments.dataResourceIdField));
                        var resourceValue = item.get(assignments.dataValueField);
                        var resourcedId = item.get(assignments.dataResourceIdField);
                        var valueFormat = resource.get(resources.dataFormatField) || PERCENTAGE_FORMAT;
                        var formatedValue = kendo.toString(resourceValue, valueFormat);
                        task[resources.field].push(new ObservableObject({
                            id: resourcedId,
                            name: resource.get(resources.dataTextField),
                            color: resource.get(resources.dataColorField),
                            value: resourceValue,
                            formatedValue: formatedValue
                        }));
                    }
                };
                for (var i = 0, length = taskTree.length; i < length; i++) {
                    applyTaskResource(taskTree[i], wrapTask);
                }
            },
            _wrapResourceData: function (id) {
                var that = this;
                var result = [];
                var resource;
                var resources = this.resources.dataSource.view();
                var assignments = this.assignments.dataSource.view();
                var taskAssignments = new Query(assignments).filter({
                    field: that.assignments.dataTaskIdField,
                    operator: 'eq',
                    value: id
                }).toArray();
                var valuePerResource = function (id) {
                    var resourceValue = null;
                    new Query(taskAssignments).filter({
                        field: that.assignments.dataResourceIdField,
                        operator: 'eq',
                        value: id
                    }).select(function (assignment) {
                        resourceValue += assignment.get(that.assignments.dataValueField);
                    });
                    return resourceValue;
                };
                for (var i = 0, length = resources.length; i < length; i++) {
                    resource = resources[i];
                    result.push({
                        id: resource.get('id'),
                        name: resource.get(that.resources.dataTextField),
                        format: resource.get(that.resources.dataFormatField) || PERCENTAGE_FORMAT,
                        value: valuePerResource(resource.id)
                    });
                }
                return result;
            },
            _syncDataSource: function () {
                this._preventRefresh = false;
                this._requestStart();
                this.dataSource.sync();
            },
            _requestStart: function () {
                this._progress(true);
            },
            _error: function () {
                this._progress(false);
            },
            _progress: function (toggle) {
                kendo.ui.progress(this.element, toggle);
            },
            _resizable: function () {
                var that = this;
                var wrapper = this.wrapper;
                var ganttStyles = Gantt.styles;
                var contentSelector = DOT + ganttStyles.gridContent;
                var treeListWrapper = wrapper.find(DOT + ganttStyles.list);
                var timelineWrapper = wrapper.find(DOT + ganttStyles.timeline);
                var treeListWidth;
                var timelineWidth;
                var timelineScroll;
                this._resizeDraggable = wrapper.find(DOT + ganttStyles.splitBar).height(treeListWrapper.height()).hover(function () {
                    $(this).addClass(ganttStyles.splitBarHover);
                }, function () {
                    $(this).removeClass(ganttStyles.splitBarHover);
                }).end().kendoResizable({
                    orientation: 'horizontal',
                    handle: DOT + ganttStyles.splitBar,
                    'start': function () {
                        treeListWidth = treeListWrapper.width();
                        timelineWidth = timelineWrapper.width();
                        timelineScroll = timelineWrapper.find(contentSelector).scrollLeft();
                    },
                    'resize': function (e) {
                        var delta = e.x.initialDelta;
                        if (kendo.support.isRtl(wrapper)) {
                            delta *= -1;
                        }
                        if (treeListWidth + delta < 0 || timelineWidth - delta < 0) {
                            return;
                        }
                        treeListWrapper.width(treeListWidth + delta);
                        timelineWrapper.width(timelineWidth - delta);
                        timelineWrapper.find(contentSelector).scrollLeft(timelineScroll + delta);
                        that.timeline.view()._renderCurrentTime();
                    }
                }).data('kendoResizable');
            },
            _scrollable: function () {
                var that = this;
                var ganttStyles = Gantt.styles;
                var contentSelector = DOT + ganttStyles.gridContent;
                var headerSelector = DOT + ganttStyles.gridHeaderWrap;
                var timelineHeader = this.timeline.element.find(headerSelector);
                var timelineContent = this.timeline.element.find(contentSelector);
                var treeListHeader = this.list.element.find(headerSelector);
                var treeListContent = this.list.element.find(contentSelector);
                if (mobileOS) {
                    treeListContent.css('overflow-y', 'auto');
                }
                timelineContent.on('scroll', function () {
                    that.scrollTop = this.scrollTop;
                    timelineHeader.scrollLeft(this.scrollLeft);
                    treeListContent.scrollTop(this.scrollTop);
                });
                treeListContent.on('scroll', function () {
                    treeListHeader.scrollLeft(this.scrollLeft);
                }).on('DOMMouseScroll' + NS + ' mousewheel' + NS, function (e) {
                    var scrollTop = timelineContent.scrollTop();
                    var delta = kendo.wheelDeltaY(e);
                    if (delta) {
                        e.preventDefault();
                        $(e.currentTarget).one('wheel' + NS, false);
                        timelineContent.scrollTop(scrollTop + -delta);
                    }
                });
            },
            _navigatable: function () {
                var that = this;
                var navigatable = this.options.navigatable;
                var editable = this.options.editable;
                var headerTable = this.list.header.find('table');
                var contentTable = this.list.content.find('table');
                var ganttStyles = Gantt.styles;
                var isRtl = kendo.support.isRtl(this.wrapper);
                var timelineContent = this.timeline.element.find(DOT + ganttStyles.gridContent);
                var tables = headerTable.add(contentTable);
                var attr = selector();
                var cellIndex;
                var expandState = {
                    collapse: false,
                    expand: true
                };
                var scroll = function (reverse) {
                    var width = that.timeline.view()._timeSlots()[0].offsetWidth;
                    timelineContent.scrollLeft(timelineContent.scrollLeft() + (reverse ? -width : width));
                };
                var scrollVertical = function (reverse) {
                    var height = that.timeline.view()._rowHeight;
                    timelineContent.scrollTop(timelineContent.scrollTop() + (reverse ? -height : height));
                };
                var moveVertical = function (method) {
                    var parent = that.current.parent('tr' + selector());
                    var index = that.current.index();
                    var subling = parent[method]();
                    if (that.select().length !== 0) {
                        that.clearSelection();
                    }
                    if (subling.length !== 0) {
                        that._current(subling.children('td:eq(' + index + ')'));
                        that._scrollTo(that.current);
                    } else {
                        if (that.current.is('td') && method == 'prev') {
                            focusTable(headerTable);
                        } else if (that.current.is('th') && method == 'next') {
                            focusTable(contentTable);
                        }
                    }
                };
                var moveHorizontal = function (method) {
                    var subling = that.current[method]();
                    if (subling.length !== 0) {
                        that._current(subling);
                        cellIndex = that.current.index();
                    }
                };
                var toggleExpandedState = function (value) {
                    var model = that.dataItem(that.current);
                    if (model.summary && model.expanded !== value) {
                        model.set('expanded', value);
                    }
                };
                var deleteAction = function () {
                    var editable = that.options.editable;
                    if (!editable || editable.destroy === false || that.list.editable) {
                        return;
                    }
                    var selectedTask = that.select();
                    var uid = kendo.attr('uid');
                    if (selectedTask.length) {
                        that.removeTask(selectedTask.attr(uid));
                    }
                };
                $(this.wrapper).on('mousedown' + NS, 'tr' + attr + ', div' + attr + ':not(' + DOT + ganttStyles.line + ')', function (e) {
                    var currentTarget = $(e.currentTarget);
                    var isInput = $(e.target).is(':button,a,:input,a>.k-icon,textarea,span.k-icon,span.k-link,.k-input,.k-multiselect-wrap');
                    var current;
                    if (e.ctrlKey) {
                        return;
                    }
                    if (navigatable) {
                        if (currentTarget.is('tr')) {
                            current = $(e.target).closest('td');
                        } else {
                            current = that.list.content.find('tr' + selector(currentTarget.attr(kendo.attr('uid'))) + ' > td:first');
                        }
                        that._current(current);
                    }
                    if ((navigatable || editable) && !isInput) {
                        that._focusTimeout = setTimeout(function () {
                            focusTable(that.list.content.find('table'), true);
                        }, 2);
                    }
                }).on('keydown' + NS, function (e) {
                    var key = e.keyCode;
                    var that = this;
                    var focusableItems = $(that._getToolbarItems());
                    var idx = focusableItems.index(that.toolbar.find(DOT + ganttStyles.focused)[0]);
                    if (idx === -1 && $(e.target).closest(DOT + ganttStyles.toolbar.views).length) {
                        idx = focusableItems.index(that.toolbar.find('.k-gantt-views > .k-state-selected:visible > a, .k-current-view:visible > a')[0]);
                    }
                    var itemToFocus = e.shiftKey ? focusableItems[idx - 1] : focusableItems[idx + 1];
                    if (key === keys.F10) {
                        that.toolbar.find('.k-button:visible:first').addClass(ganttStyles.focused).focus();
                        e.preventDefault();
                    } else if (key == keys.TAB && $(e.target).closest(DOT + ganttStyles.toolbar.toolbar).length) {
                        that.toolbar.find(DOT + ganttStyles.focused).removeClass(ganttStyles.focused).blur();
                        if (itemToFocus) {
                            $(itemToFocus).addClass(ganttStyles.focused).focus();
                            e.preventDefault();
                            return;
                        }
                        if (this.list.element.is(':visible')) {
                            this.list.element.find('table[role=treegrid]').focus();
                        } else {
                            this.element.find(DOT + ganttStyles.tasks)[0].focus();
                        }
                        e.preventDefault();
                    }
                }.bind(this));
                if (navigatable !== true) {
                    contentTable.on('keydown' + NS, function (e) {
                        if (e.keyCode == keys.DELETE) {
                            deleteAction();
                        }
                    });
                    return;
                }
                tables.on('focus' + NS, function () {
                    var selector = this === contentTable.get(0) ? 'td' : 'th';
                    var selection = that.select();
                    var current = that.current || $(selection.length ? selection : this).find(selector + ':eq(' + (cellIndex || 0) + ')');
                    that._current(current);
                    $(that.toolbar.find(DOT + ganttStyles.focused)).removeClass(ganttStyles.focused);
                    $(that.toolbar.find(DOT + ganttStyles.toolbar.currentView)).parent().removeClass(ganttStyles.toolbar.expanded);
                }).on('blur' + NS, function () {
                    that._current();
                    if (this == headerTable) {
                        $(this).attr(TABINDEX, -1);
                    }
                }).on('keydown' + NS, function (e) {
                    var key = e.keyCode;
                    var isCell;
                    if (!that.current) {
                        return;
                    }
                    isCell = that.current.is('td');
                    switch (key) {
                    case keys.RIGHT:
                        e.preventDefault();
                        if (e.altKey) {
                            scroll();
                        } else if (e.ctrlKey) {
                            toggleExpandedState(isRtl ? expandState.collapse : expandState.expand);
                        } else {
                            moveHorizontal(isRtl ? 'prev' : 'next');
                        }
                        break;
                    case keys.LEFT:
                        e.preventDefault();
                        if (e.altKey) {
                            scroll(true);
                        } else if (e.ctrlKey) {
                            toggleExpandedState(isRtl ? expandState.expand : expandState.collapse);
                        } else {
                            moveHorizontal(isRtl ? 'next' : 'prev');
                        }
                        break;
                    case keys.UP:
                        e.preventDefault();
                        if (e.altKey) {
                            scrollVertical(true);
                        } else {
                            moveVertical('prev');
                        }
                        break;
                    case keys.DOWN:
                        e.preventDefault();
                        if (e.altKey) {
                            scrollVertical();
                        } else {
                            moveVertical('next');
                        }
                        break;
                    case keys.SPACEBAR:
                        e.preventDefault();
                        if (isCell) {
                            that.select(that.current.closest('tr'));
                        }
                        break;
                    case keys.ENTER:
                        e.preventDefault();
                        if (isCell) {
                            if (that.options.editable && that.options.editable.update !== false) {
                                that._cachedCurrent = that.current;
                                that.list._startEditHandler(that.current);
                                $(this).one('keyup', function (e) {
                                    e.stopPropagation();
                                });
                            }
                        } else {
                            that.current.children('a.k-link').click();
                        }
                        break;
                    case keys.ESC:
                        break;
                    case keys.DELETE:
                        if (isCell) {
                            deleteAction();
                        }
                        break;
                    default:
                        if (key >= 49 && key <= 57 && e.target.tagName.toLowerCase() !== 'input') {
                            that.view(that.timeline._viewByIndex(key - 49));
                        }
                        break;
                    }
                });
            },
            _getToolbarItems: function () {
                return this.toolbar.find('.k-gantt-toggle:visible').toArray().concat(this.toolbar.find('.k-gantt-actions > .k-button:visible').toArray(), this.toolbar.find('.k-gantt-views > .k-state-selected:visible > a, .k-current-view:visible > a').toArray());
            },
            _current: function (element) {
                var ganttStyles = Gantt.styles;
                var activeElement;
                if (this.current && this.current.length) {
                    this.current.removeClass(ganttStyles.focused).removeAttr('id');
                }
                if (element && element.length) {
                    this.current = element.addClass(ganttStyles.focused).attr('id', ACTIVE_CELL);
                    activeElement = $(kendo._activeElement());
                    if (activeElement.is('table') && this.wrapper.find(activeElement).length > 0) {
                        activeElement.removeAttr(ARIA_DESCENDANT).attr(ARIA_DESCENDANT, ACTIVE_CELL);
                    }
                } else {
                    this.current = null;
                }
            },
            _dataBind: function () {
                var that = this;
                if (that.options.autoBind) {
                    this._preventRefresh = true;
                    this._preventDependencyRefresh = true;
                    var promises = $.map([
                        this.dataSource,
                        this.dependencies,
                        this.resources.dataSource,
                        this.assignments.dataSource
                    ], function (dataSource) {
                        return dataSource.fetch();
                    });
                    $.when.apply(null, promises).done(function () {
                        that._preventRefresh = false;
                        that._preventDependencyRefresh = false;
                        that.refresh();
                    });
                }
            },
            _resize: function () {
                this._adjustDimensions();
                this.timeline.view()._adjustHeight();
                this.timeline.view()._renderCurrentTime();
                this.list._adjustHeight();
            }
        });
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(Gantt.fn);
            Gantt.fn._drawPDF = function () {
                var ganttStyles = Gantt.styles;
                var listClass = '.' + ganttStyles.list;
                var listWidth = this.wrapper.find(listClass).width();
                var content = this.wrapper.clone();
                content.find(listClass).css('width', listWidth);
                return this._drawPDFShadow({ content: content }, { avoidLinks: this.options.pdf.avoidLinks });
            };
        }
        kendo.ui.plugin(Gantt);
        extend(true, Gantt, { styles: ganttStyles });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.treelist', [
        'kendo.dom',
        'kendo.data',
        'kendo.columnsorter',
        'kendo.editable',
        'kendo.window',
        'kendo.filtermenu',
        'kendo.selectable',
        'kendo.resizable',
        'kendo.treeview.draganddrop',
        'kendo.pager'
    ], f);
}(function () {
    var __meta__ = {
        id: 'treelist',
        name: 'TreeList',
        category: 'web',
        description: 'The TreeList widget displays self-referencing data and offers rich support for interacting with data, sorting, filtering, and selection.',
        depends: [
            'dom',
            'data',
            'pager'
        ],
        features: [
            {
                id: 'treelist-sorting',
                name: 'Sorting',
                description: 'Support for column sorting',
                depends: ['columnsorter']
            },
            {
                id: 'treelist-filtering',
                name: 'Filtering',
                description: 'Support for record filtering',
                depends: ['filtermenu']
            },
            {
                id: 'treelist-editing',
                name: 'Editing',
                description: 'Support for record editing',
                depends: [
                    'editable',
                    'window'
                ]
            },
            {
                id: 'treelist-selection',
                name: 'Selection',
                description: 'Support for row selection',
                depends: ['selectable']
            },
            {
                id: 'treelist-column-resize',
                name: 'Column resizing',
                description: 'Support for column resizing',
                depends: ['resizable']
            },
            {
                id: 'treelist-dragging',
                name: 'Drag & Drop',
                description: 'Support for drag & drop of rows',
                depends: ['treeview.draganddrop']
            },
            {
                id: 'treelist-excel-export',
                name: 'Excel export',
                description: 'Export data as Excel spreadsheet',
                depends: ['excel']
            },
            {
                id: 'treelist-pdf-export',
                name: 'PDF export',
                description: 'Export data as PDF',
                depends: [
                    'pdf',
                    'drawing'
                ]
            },
            {
                id: 'treelist-paging',
                name: 'Paging',
                description: 'Support for treelist paging',
                depends: ['pager']
            }
        ]
    };
    (function ($, undefined) {
        var data = kendo.data;
        var kendoDom = kendo.dom;
        var kendoDomElement = kendoDom.element;
        var kendoTextElement = kendoDom.text;
        var kendoHtmlElement = kendoDom.html;
        var outerWidth = kendo._outerWidth;
        var keys = kendo.keys;
        var outerHeight = kendo._outerHeight;
        var ui = kendo.ui;
        var DataBoundWidget = ui.DataBoundWidget;
        var DataSource = data.DataSource;
        var ObservableArray = data.ObservableArray;
        var Query = data.Query;
        var Model = data.Model;
        var browser = kendo.support.browser;
        var kendoTemplate = kendo.template;
        var activeElement = kendo._activeElement;
        var isArray = $.isArray;
        var extend = $.extend;
        var proxy = $.proxy;
        var map = $.map;
        var grep = $.grep;
        var inArray = $.inArray;
        var isPlainObject = $.isPlainObject;
        var push = Array.prototype.push;
        var STRING = 'string';
        var CHANGE = 'change';
        var ITEM_CHANGE = 'itemChange';
        var ERROR = 'error';
        var PROGRESS = 'progress';
        var DOT = '.';
        var NS = '.kendoTreeList';
        var CLICK = 'click';
        var MOUSEDOWN = 'mousedown';
        var BEFORE_EDIT = 'beforeEdit';
        var EDIT = 'edit';
        var PAGE = 'page';
        var PAGE_CHANGE = 'pageChange';
        var SAVE = 'save';
        var SAVE_CHANGES = 'saveChanges';
        var EXPAND = 'expand';
        var COLLAPSE = 'collapse';
        var CELL_CLOSE = 'cellClose';
        var REMOVE = 'remove';
        var DATA_CELL = 'td:not(.k-group-cell):not(.k-hierarchy-cell):visible';
        var DATABINDING = 'dataBinding';
        var DATABOUND = 'dataBound';
        var CANCEL = 'cancel';
        var TABINDEX = 'tabIndex';
        var FILTERMENUINIT = 'filterMenuInit';
        var FILTERMENUOPEN = 'filterMenuOpen';
        var COLUMNHIDE = 'columnHide';
        var COLUMNSHOW = 'columnShow';
        var HEADERCELLS = 'th.k-header';
        var COLUMNREORDER = 'columnReorder';
        var COLUMNRESIZE = 'columnResize';
        var COLUMNMENUINIT = 'columnMenuInit';
        var COLUMNMENUOPEN = 'columnMenuOpen';
        var COLUMNLOCK = 'columnLock';
        var COLUMNUNLOCK = 'columnUnlock';
        var PARENTIDFIELD = 'parentId';
        var DRAGSTART = 'dragstart';
        var DRAG = 'drag';
        var DROP = 'drop';
        var DRAGEND = 'dragend';
        var NAVROW = 'tr:visible';
        var NAVCELL = 'td:visible';
        var NAVHEADER = 'th:visible';
        var NORECORDSCLASS = 'k-grid-norecords';
        var ITEMROW = 'tr:not(.k-footer-template):visible';
        var FIRSTNAVITEM = NAVROW + ' > td:first:visible';
        var LASTITEMROW = ITEMROW + ':last';
        var isRtl = false;
        var HEIGHT = 'height';
        var INCELL = 'incell';
        var INLINE = 'inline';
        var POPUP = 'popup';
        var TABLE = 'table';
        var classNames = {
            wrapper: 'k-treelist k-grid k-widget k-display-block',
            header: 'k-header',
            button: 'k-button',
            alt: 'k-alt',
            editCell: 'k-edit-cell',
            editRow: 'k-grid-edit-row',
            dirtyCell: 'k-dirty-cell',
            group: 'k-treelist-group',
            gridToolbar: 'k-grid-toolbar',
            gridHeader: 'k-grid-header',
            gridHeaderWrap: 'k-grid-header-wrap',
            gridContent: 'k-grid-content',
            gridContentWrap: 'k-grid-content',
            gridFilter: 'k-grid-filter',
            footerTemplate: 'k-footer-template',
            focused: 'k-state-focused',
            loading: 'k-i-loading',
            refresh: 'k-i-reload',
            retry: 'k-request-retry',
            selected: 'k-state-selected',
            status: 'k-status',
            link: 'k-link',
            withIcon: 'k-with-icon',
            filterable: 'k-filterable',
            icon: 'k-icon',
            iconFilter: 'k-i-filter',
            iconCollapse: 'k-i-collapse',
            iconExpand: 'k-i-expand',
            iconHidden: 'k-i-none',
            iconPlaceHolder: 'k-icon k-i-none',
            input: 'k-input',
            dropPositions: 'k-i-insert-up k-i-insert-down k-i-plus k-i-insert-middle',
            dropTop: 'k-i-insert-up',
            dropBottom: 'k-i-insert-down',
            dropAdd: 'k-i-plus',
            dropMiddle: 'k-i-insert-middle',
            dropDenied: 'k-i-cancel',
            dragStatus: 'k-drag-status',
            dragClue: 'k-drag-clue',
            dragClueText: 'k-clue-text'
        };
        var defaultCommands = {
            create: {
                imageClass: 'k-i-plus',
                className: 'k-grid-add',
                methodName: 'addRow'
            },
            createchild: {
                imageClass: 'k-i-plus',
                className: 'k-grid-add',
                methodName: 'addRow'
            },
            destroy: {
                imageClass: 'k-i-close',
                className: 'k-grid-delete',
                methodName: 'removeRow'
            },
            edit: {
                imageClass: 'k-i-edit',
                className: 'k-grid-edit',
                methodName: 'editRow'
            },
            update: {
                imageClass: 'k-i-check',
                className: 'k-primary k-grid-update',
                methodName: 'saveRow'
            },
            canceledit: {
                imageClass: 'k-i-cancel',
                className: 'k-grid-cancel',
                methodName: '_cancelEdit'
            },
            cancel: {
                imageClass: 'k-icon k-i-cancel',
                text: 'Cancel changes',
                className: 'k-grid-cancel-changes',
                methodName: 'cancelChanges'
            },
            save: {
                imageClass: 'k-icon k-i-check',
                text: 'Save changes',
                className: 'k-grid-save-changes',
                methodName: 'saveChanges'
            },
            excel: {
                imageClass: 'k-i-file-excel',
                className: 'k-grid-excel',
                methodName: 'saveAsExcel'
            },
            pdf: {
                imageClass: 'k-i-file-pdf',
                className: 'k-grid-pdf',
                methodName: 'saveAsPDF'
            }
        };
        var TreeView = kendo.Class.extend({
            init: function (data, options) {
                var that = this;
                that.data = data || [];
                that.options = extend(that.options, options);
            },
            options: {
                defaultParentId: null,
                idField: 'id',
                parentIdField: PARENTIDFIELD
            },
            childrenMap: function () {
                var that = this;
                var childrenMap = {};
                var dataLength = that.data.length;
                var dataItem;
                var dataItemId;
                var dataItemParentId;
                var idField = that.options.idField;
                var parentIdField = that.options.parentIdField;
                if (that._childrenMap) {
                    return that._childrenMap;
                }
                for (var i = 0; i < dataLength; i++) {
                    dataItem = this.data[i];
                    dataItemId = dataItem[idField];
                    dataItemParentId = dataItem[parentIdField];
                    childrenMap[dataItemId] = childrenMap[dataItemId] || [];
                    childrenMap[dataItemParentId] = childrenMap[dataItemParentId] || [];
                    childrenMap[dataItemParentId].push(dataItem);
                }
                that._childrenMap = childrenMap;
                return childrenMap;
            },
            idsMap: function () {
                var that = this;
                var idsMap = {};
                var data = that.data;
                var dataLength = data.length;
                var dataItem;
                var idField = that.options.idField;
                if (that._idMap) {
                    return that._idMap;
                }
                for (var i = 0; i < dataLength; i++) {
                    dataItem = data[i];
                    idsMap[dataItem[idField]] = dataItem;
                }
                that.idsMap = idsMap;
                return idsMap;
            },
            dataMaps: function () {
                var that = this;
                var childrenMap = {};
                var data = that.data;
                var dataLength = data.length;
                var idsMap = {};
                var dataItem;
                var dataItemId;
                var dataItemParentId;
                var idField = that.options.idField;
                var parentIdField = that.options.parentIdField;
                if (that._dataMaps) {
                    return that._dataMaps;
                }
                for (var i = 0; i < dataLength; i++) {
                    dataItem = data[i];
                    dataItemId = dataItem[idField];
                    dataItemParentId = dataItem[parentIdField];
                    idsMap[dataItemId] = dataItem;
                    childrenMap[dataItemId] = childrenMap[dataItemId] || [];
                    childrenMap[dataItemParentId] = childrenMap[dataItemParentId] || [];
                    childrenMap[dataItemParentId].push(dataItem);
                }
                that._dataMaps = {
                    children: childrenMap,
                    ids: idsMap
                };
                return that._dataMaps;
            },
            rootNodes: function () {
                var that = this;
                var data = that.data;
                var defaultParentId = that.options.defaultParentId;
                var dataLength = data.length;
                var rootNodes = [];
                var dataItem;
                var parentIdField = that.options.parentIdField;
                for (var i = 0; i < dataLength; i++) {
                    dataItem = data[i];
                    if (dataItem[parentIdField] === defaultParentId) {
                        rootNodes.push(dataItem);
                    }
                }
                return rootNodes;
            },
            removeCollapsedSubtreesFromRootNodes: function (options) {
                options = options || {};
                var that = this;
                var rootNodes = that.rootNodes();
                var result = [];
                var prunedTree;
                that._childrenMap = options.childrenMap = options.childrenMap || that.childrenMap();
                options.maxDepth = options.maxDepth || Infinity;
                for (var i = 0; i < rootNodes.length; i++) {
                    prunedTree = that.removeCollapsedSubtrees(rootNodes[i], options);
                    result = result.concat(prunedTree);
                }
                return result;
            },
            removeCollapsedSubtrees: function (rootNode, options) {
                options = options || {};
                var that = this;
                var result = [];
                var childIdx;
                var prunedTree;
                var childrenMap = options.childrenMap || {};
                var maxDepth = options.maxDepth || Infinity;
                var idField = that.options.idField;
                var children = childrenMap[rootNode[idField]] || [];
                var expanded = isUndefined(rootNode.expanded) ? options.expanded : rootNode.expanded;
                result.push(rootNode);
                if (children && expanded) {
                    for (childIdx = 0; childIdx < children.length; childIdx++) {
                        if (result.length >= maxDepth) {
                            break;
                        }
                        prunedTree = that.removeCollapsedSubtrees(children[childIdx], options);
                        result = result.concat(prunedTree);
                    }
                }
                return result;
            }
        });
        var TreeQuery = function (data) {
            this.data = data || [];
        };
        TreeQuery.prototype = new Query();
        TreeQuery.prototype.constructor = TreeQuery;
        TreeQuery.process = function (data, options, inPlace) {
            options = options || {};
            var query = new TreeQuery(data);
            var group = options.group;
            var sort = Query.normalizeGroup(group || []).concat(Query.normalizeSort(options.sort || []));
            var filterCallback = options.filterCallback;
            var filter = options.filter;
            var skip = options.skip;
            var take = options.take;
            var total;
            var childrenMap;
            var filteredChildrenMap;
            var view;
            var prunedData;
            if (sort && inPlace) {
                query = query.sort(sort, undefined, undefined, inPlace);
            }
            if (filter) {
                query = query.filter(filter);
                if (filterCallback) {
                    query = filterCallback(query);
                }
                total = query.toArray().length;
            }
            if (sort && !inPlace) {
                query = query.sort(sort);
                if (group) {
                    data = query.toArray();
                }
            }
            if (options.processFromRootNodes) {
                view = new TreeView(query.toArray(), options);
                if (filter) {
                    filteredChildrenMap = view.childrenMap();
                }
                prunedData = view.removeCollapsedSubtreesFromRootNodes({
                    childrenMap: filter || sort && sort.length ? undefined : options.childrenMap,
                    expanded: options.expanded,
                    maxDepth: skip + take || Infinity
                });
                childrenMap = view.childrenMap();
                query = new TreeQuery(prunedData);
            }
            if (skip !== undefined && take !== undefined) {
                query = query.range(skip, take);
            }
            if (group) {
                query = query.group(group, data);
            }
            return {
                total: total,
                data: query.toArray(),
                childrenMap: childrenMap,
                filteredChildrenMap: filteredChildrenMap
            };
        };
        var TreeListModel = Model.define({
            id: 'id',
            parentId: PARENTIDFIELD,
            fields: {
                id: { type: 'number' },
                parentId: {
                    type: 'number',
                    nullable: true
                }
            },
            init: function (value) {
                Model.fn.init.call(this, value);
                this._loaded = false;
                if (!this.parentIdField) {
                    this.parentIdField = PARENTIDFIELD;
                }
                this.parentId = this.get(this.parentIdField);
            },
            accept: function (data) {
                Model.fn.accept.call(this, data);
                this.parentId = this.get(this.parentIdField);
            },
            set: function (field, value, initiator) {
                if (field == PARENTIDFIELD && this.parentIdField != PARENTIDFIELD) {
                    this[this.parentIdField] = value;
                }
                Model.fn.set.call(this, field, value, initiator);
                if (field == this.parentIdField) {
                    this.parentId = this.get(this.parentIdField);
                }
            },
            loaded: function (value) {
                if (value !== undefined) {
                    this._loaded = value;
                } else {
                    return this._loaded;
                }
            },
            shouldSerialize: function (field) {
                return Model.fn.shouldSerialize.call(this, field) && field !== '_loaded' && field != '_error' && field != '_edit' && !(this.parentIdField !== 'parentId' && field === 'parentId');
            }
        });
        TreeListModel.parentIdField = PARENTIDFIELD;
        TreeListModel.define = function (base, options) {
            if (options === undefined) {
                options = base;
                base = TreeListModel;
            }
            var parentId = options.parentId || PARENTIDFIELD;
            options.parentIdField = parentId;
            var model = Model.define(base, options);
            if (parentId) {
                model.parentIdField = parentId;
            }
            return model;
        };
        function is(field) {
            return function (object) {
                return object[field];
            };
        }
        function not(func) {
            return function (object) {
                return !func(object);
            };
        }
        var TreeListDataSource = DataSource.extend({
            init: function (options) {
                options = options || {};
                var that = this;
                that._dataMaps = that._getDataMaps();
                options.schema = extend(true, {}, {
                    modelBase: TreeListModel,
                    model: TreeListModel
                }, options.schema);
                DataSource.fn.init.call(this, options);
            },
            _addRange: function () {
            },
            _createNewModel: function (data) {
                var that = this;
                var model = {};
                var fromModel = data instanceof Model;
                var parentIdField = this._modelParentIdField();
                if (fromModel) {
                    model = data;
                }
                model = DataSource.fn._createNewModel.call(this, model);
                if (!fromModel) {
                    if (data.parentId) {
                        data[model.parentIdField] = data.parentId;
                    } else if (that._isPageable() && data[parentIdField]) {
                        data[model.parentIdField] = data[parentIdField];
                    }
                    model.accept(data);
                }
                return model;
            },
            _shouldWrap: function () {
                return true;
            },
            _push: function (result, operation) {
                var data = DataSource.fn._readData.call(this, result);
                if (!data) {
                    data = result;
                }
                this[operation](data);
            },
            _getData: function () {
                return this._data || [];
            },
            _readData: function (newData) {
                var that = this;
                var data = that._isPageable() ? that._getData().toJSON() : that.data();
                newData = DataSource.fn._readData.call(this, newData);
                this._replaceData((data.toJSON ? data.toJSON() : data).concat(newData), data);
                if (newData instanceof ObservableArray) {
                    return newData;
                }
                return data;
            },
            _replaceData: function (source, target) {
                var sourceLength = source.length;
                for (var i = 0; i < sourceLength; i++) {
                    target[i] = source[i];
                }
                target.length = sourceLength;
            },
            _readAggregates: function (data) {
                var result = extend(this._aggregateResult, this.reader.aggregates(data));
                if ('' in result) {
                    result[this._defaultParentId()] = result[''];
                    delete result[''];
                }
                return result;
            },
            read: function (data) {
                var that = this;
                if (that._isPageable()) {
                    that._dataMaps = {};
                    if (!that._modelOptions().expanded) {
                        that._skip = 0;
                        that._page = 1;
                        that._collapsedTotal = undefined;
                    }
                }
                return DataSource.fn.read.call(that, data);
            },
            remove: function (root) {
                this._removeChildData(root);
                this._removeFromDataMaps(root);
                DataSource.fn.remove.call(this, root);
            },
            _removeChildData: function (model, removePristine) {
                var that = this;
                var pageable = that._isPageable();
                var data = pageable ? this._getData() : this.data();
                var childrenMap = pageable ? that._getChildrenMap() || that.childrenMap(data) : that._childrenMap(data);
                var items = this._subtree(childrenMap, model.id);
                var shouldRemovePristine = isUndefined(removePristine) ? false : removePristine;
                var removedItems = this._removeItems(items, shouldRemovePristine);
                that._removeFromDataMaps(removedItems);
            },
            pushDestroy: function (items) {
                var that = this;
                if (!isArray(items)) {
                    items = [items];
                }
                for (var i = 0; i < items.length; i++) {
                    that._removeChildData(items[i], true);
                    that._removeFromDataMaps(items[i]);
                }
                DataSource.fn.pushDestroy.call(that, items);
            },
            insert: function (index, model) {
                var that = this;
                var newModel = that._createNewModel(model);
                that._insertInDataMaps(newModel);
                return DataSource.fn.insert.call(that, index, newModel);
            },
            _filterCallback: function (query) {
                var that = this;
                var i, item;
                var map = {};
                var result = [];
                var data = query.toArray();
                var idField = that._modelIdField();
                var parentIdField = that._modelParentIdField();
                var pageable = that._isPageable();
                var parentSubtree = [];
                var parent;
                for (i = 0; i < data.length; i++) {
                    item = data[i];
                    if (pageable) {
                        parentSubtree = [];
                        if (!map[item[idField]]) {
                            map[item[idField]] = true;
                            parentSubtree.push(item);
                        }
                        parent = that._parentNode(item);
                        while (parent) {
                            if (!map[parent[idField]]) {
                                map[parent[idField]] = true;
                                parentSubtree.unshift(parent);
                                parent = that._parentNode(parent);
                            } else {
                                break;
                            }
                        }
                        if (parentSubtree.length) {
                            result = result.concat(parentSubtree);
                        }
                    } else {
                        while (item) {
                            if (!map[item[idField]]) {
                                map[item[idField]] = true;
                                result.push(item);
                            }
                            if (!map[item[parentIdField]]) {
                                map[item[parentIdField]] = true;
                                item = this.parentNode(item);
                                if (item) {
                                    result.push(item);
                                }
                            } else {
                                break;
                            }
                        }
                    }
                }
                return new Query(result);
            },
            _subtree: function (map, id) {
                var that = this;
                var result = map[id] || [];
                var defaultParentId = that._defaultParentId();
                var idField = that._modelIdField();
                for (var i = 0, len = result.length; i < len; i++) {
                    if (result[i][idField] !== defaultParentId) {
                        result = result.concat(that._subtree(map, result[i][idField]));
                    }
                }
                return result;
            },
            _childrenMap: function (data) {
                var map = {};
                var i, item, id, parentId;
                data = this._observeView(data);
                for (i = 0; i < data.length; i++) {
                    item = data[i];
                    id = item.id;
                    parentId = item.parentId;
                    map[id] = map[id] || [];
                    map[parentId] = map[parentId] || [];
                    map[parentId].push(item);
                }
                return map;
            },
            childrenMap: function (data) {
                var view = this._createTreeView(data);
                var map = view.childrenMap();
                return map;
            },
            _getChildrenMap: function () {
                var that = this;
                var dataMaps = that._getDataMaps();
                return dataMaps.children;
            },
            _initIdsMap: function (data) {
                var that = this;
                var dataMaps = that._getDataMaps();
                if (isUndefined(dataMaps.ids)) {
                    dataMaps.ids = that._idsMap(data);
                }
                return dataMaps.ids;
            },
            _idsMap: function (data) {
                var view = this._createTreeView(data);
                var map = view.idsMap();
                return map;
            },
            _getIdsMap: function () {
                var that = this;
                var dataMaps = that._getDataMaps();
                return dataMaps.ids || {};
            },
            _getFilteredChildrenMap: function () {
                var that = this;
                var dataMaps = that._getDataMaps();
                return dataMaps.filteredChildren;
            },
            _setFilteredChildrenMap: function (map) {
                var that = this;
                var dataMaps = that._getDataMaps();
                dataMaps.filteredChildren = map;
            },
            _initDataMaps: function (data) {
                var that = this;
                var view = that._createTreeView(data);
                that._dataMaps = view.dataMaps();
                return that._dataMaps;
            },
            _initChildrenMapForParent: function (parent) {
                var that = this;
                var data = that._getData();
                var childrenMap = that._getChildrenMap();
                var idField = that._modelIdField();
                var parentIdField = that._modelParentIdField();
                var parentId = (parent || {})[idField];
                if (childrenMap && parent) {
                    childrenMap[parentId] = [];
                    for (var i = 0; i < data.length; i++) {
                        if (data[i][parentIdField] === parentId) {
                            childrenMap[parentId].push(data[i]);
                        }
                    }
                }
            },
            _getDataMaps: function () {
                var that = this;
                that._dataMaps = that._dataMaps || {};
                return that._dataMaps;
            },
            _createTreeView: function (data, options) {
                var view = new TreeView(data, extend(options, this._defaultTreeModelOptions()));
                return view;
            },
            _defaultTreeModelOptions: function () {
                var that = this;
                var modelOptions = that._modelOptions();
                return {
                    defaultParentId: that._defaultParentId(),
                    idField: that._modelIdField(),
                    parentIdField: that._modelParentIdField(),
                    expanded: modelOptions.expanded
                };
            },
            _defaultDataItemType: function () {
                return this.reader.model || kendo.data.ObservableObject;
            },
            _calculateAggregates: function (data, options) {
                options = options || {};
                var that = this;
                var result = {};
                var item, subtree, i;
                var filter = options.filter;
                var skip = options.skip;
                var take = options.take;
                var maxDepth = !isUndefined(skip) && !isUndefined(take) ? skip + take : Infinity;
                var pageable = that._isPageable();
                var filteredChildrenMap = options.filteredChildrenMap;
                var childrenMap = options.childrenMap;
                var pageableChildrenMap;
                if (pageable) {
                    if (isUndefined(options.aggregate)) {
                        return result;
                    }
                    if (filteredChildrenMap) {
                        pageableChildrenMap = filteredChildrenMap;
                    } else if (childrenMap) {
                        pageableChildrenMap = childrenMap;
                    } else {
                        pageableChildrenMap = that.childrenMap(that._getData());
                    }
                }
                if (!pageable && filter) {
                    data = Query.process(data, {
                        filter: filter,
                        filterCallback: proxy(this._filterCallback, this)
                    }).data;
                }
                var map = pageable ? pageableChildrenMap : that._childrenMap(data);
                result[this._defaultParentId()] = new Query(this._subtree(map, this._defaultParentId())).aggregate(options.aggregate);
                for (i = 0; i < data.length; i++) {
                    if (i >= maxDepth) {
                        break;
                    }
                    item = data[i];
                    subtree = this._subtree(map, item.id);
                    result[item.id] = new Query(subtree).aggregate(options.aggregate);
                }
                return result;
            },
            _queryProcess: function (data, options) {
                var that = this;
                var result = {};
                options = options || {};
                options.filterCallback = proxy(this._filterCallback, this);
                if (that._isPageable()) {
                    return that._processPageableQuery(data, options);
                } else {
                    var defaultParentId = this._defaultParentId();
                    result = Query.process(data, options);
                    var map = this._childrenMap(result.data);
                    var hasLoadedChildren, i, item, children;
                    data = map[defaultParentId] || [];
                    for (i = 0; i < data.length; i++) {
                        item = data[i];
                        if (item.id === defaultParentId) {
                            continue;
                        }
                        children = map[item.id];
                        hasLoadedChildren = !!(children && children.length);
                        if (!item.loaded()) {
                            item.loaded(hasLoadedChildren || !item.hasChildren);
                        }
                        if (item.loaded() || item.hasChildren !== true) {
                            item.hasChildren = hasLoadedChildren;
                        }
                        if (hasLoadedChildren) {
                            data = data.slice(0, i + 1).concat(children, data.slice(i + 1));
                        }
                    }
                    result.data = data;
                }
                return result;
            },
            _processPageableQuery: function (data, options) {
                var that = this;
                var dataMaps = that._getDataMaps();
                var result;
                var filteredChildrenMap;
                if (that._getData() !== data || !dataMaps.children || !dataMaps.ids) {
                    dataMaps = that._initDataMaps(that._getData());
                }
                options.childrenMap = dataMaps.children || {};
                options.idsMap = dataMaps.ids || {};
                result = that._processTreeQuery(data, options);
                that._replaceWithObservedData(result.data, data);
                that._processDataItemsState(result.data, result.childrenMap);
                that._replaceItemsInDataMaps(result.data);
                result.dataToAggregate = that._dataToAggregate(result.data, options);
                if (options.filter) {
                    filteredChildrenMap = result.filteredChildrenMap;
                    that._replaceInMapWithObservedData(filteredChildrenMap, data);
                    that._setFilteredChildrenMap(filteredChildrenMap);
                    options.filteredChildrenMap = filteredChildrenMap;
                }
                return result;
            },
            _dataToAggregate: function (data) {
                var that = this;
                var firstDataItem = data[0] || {};
                var firstItemParents = that._parentNodes(firstDataItem);
                var dataToAggregate = firstItemParents.concat(data);
                return dataToAggregate;
            },
            _replaceItemsInDataMaps: function (observableArray) {
                var that = this;
                var view = isArray(observableArray) ? observableArray : [observableArray];
                var itemType = that._defaultDataItemType();
                var defaultParentId = that._defaultParentId();
                var idField = that._modelIdField();
                var parentIdField = that._modelParentIdField();
                var dataMaps = that._getDataMaps();
                var item;
                var parents;
                var directParent;
                for (var viewIndex = 0; viewIndex < view.length; viewIndex++) {
                    item = view[viewIndex];
                    if (!(item instanceof itemType)) {
                        continue;
                    }
                    that._insertInIdsMap(item);
                    parents = that._parentNodes(item);
                    directParent = parents && parents.length ? parents[parents.length - 1] : undefined;
                    if (item[parentIdField] === defaultParentId) {
                        that._replaceInMap(dataMaps.children, defaultParentId, item, itemType);
                    } else if (directParent) {
                        that._replaceInMap(dataMaps.children, directParent[idField], item, itemType);
                    }
                }
            },
            _replaceInMap: function (map, id, replacement, itemType) {
                var idField = this._modelIdField();
                map[id] = map[id] || [];
                itemType = itemType || this._defaultDataItemType();
                var itemInArray = map[id].filter(function (element) {
                    return replacement[idField] === element[idField];
                })[0];
                var itemIndex = itemInArray ? map[id].indexOf(itemInArray) : -1;
                if (itemIndex !== -1 && !(itemInArray instanceof itemType)) {
                    map[id][itemIndex] = replacement;
                }
            },
            _replaceWithObservedData: function (dataToReplace, replacementArray) {
                var that = this;
                var idsMap = that._getDataMaps().ids || {};
                var idField = that._modelIdField();
                var itemType = that._defaultDataItemType();
                var itemToReplace;
                var itemToReplaceId;
                var dataItem;
                var dataItemIndex;
                var observableItem;
                for (var i = 0; i < dataToReplace.length; i++) {
                    itemToReplace = dataToReplace[i];
                    itemToReplaceId = itemToReplace[idField];
                    if (!(itemToReplace instanceof itemType)) {
                        if (!(idsMap[itemToReplaceId] instanceof itemType)) {
                            dataItem = that._getById(itemToReplaceId);
                            dataItemIndex = replacementArray.indexOf(dataItem);
                            if (dataItem && dataItemIndex !== -1) {
                                observableItem = replacementArray.at(dataItemIndex);
                                dataToReplace[i] = observableItem;
                            }
                        } else {
                            dataToReplace[i] = idsMap[itemToReplaceId];
                        }
                    }
                }
            },
            _replaceInMapWithObservedData: function (map, replacementArray) {
                var that = this;
                for (var key in map) {
                    that._replaceWithObservedData(map[key], replacementArray);
                }
            },
            _insertInDataMaps: function (item) {
                var that = this;
                if (that._isPageable()) {
                    that._insertInIdsMap(item);
                    that._insertInChildrenMap(item);
                }
            },
            _insertInIdsMap: function (item) {
                var that = this;
                var idsMap = that._getIdsMap();
                var idField = that._modelIdField();
                if (!isUndefined(item[idField])) {
                    idsMap[item[idField]] = item;
                }
            },
            _insertInChildrenMap: function (item, index) {
                var that = this;
                var childrenMap = that._getChildrenMap() || {};
                var idField = that._modelIdField();
                var parentIdField = that._modelParentIdField();
                var itemId = item[idField];
                var parentId = item[parentIdField];
                index = index || 0;
                childrenMap[itemId] = childrenMap[itemId] || [];
                childrenMap[parentId] = childrenMap[parentId] || [];
                childrenMap[parentId].splice(index, 0, item);
            },
            _removeFromDataMaps: function (items) {
                var that = this;
                items = isArray(items) ? items : [items];
                if (that._isPageable()) {
                    for (var i = 0; i < items.length; i++) {
                        that._removeFromIdsMap(items[i]);
                        that._removeFromChildrenMap(items[i]);
                    }
                }
            },
            _removeFromIdsMap: function (item) {
                var that = this;
                var idsMap = that._getIdsMap();
                var idField = that._modelIdField();
                if (!isUndefined(item[idField])) {
                    idsMap[item[idField]] = undefined;
                }
            },
            _removeFromChildrenMap: function (item) {
                var that = this;
                var childrenMap = that._getChildrenMap() || {};
                var parentIdField = that._modelParentIdField();
                var parentId = item[parentIdField];
                childrenMap[parentId] = childrenMap[parentId] || [];
                var itemIndex = that._indexInChildrenMap(item);
                if (itemIndex !== -1) {
                    childrenMap[parentId].splice(itemIndex, 1);
                }
            },
            _indexInChildrenMap: function (item) {
                var that = this;
                return that._itemIndexInMap(item, that._getChildrenMap());
            },
            _itemIndexInMap: function (item, dataMap) {
                var that = this;
                var map = dataMap || {};
                var parentIdField = that._modelParentIdField();
                var parentId = item[parentIdField];
                map[parentId] = map[parentId] || [];
                var itemInArray = map[parentId].filter(function (element) {
                    return item.uid === element.uid;
                })[0];
                var itemIndex = itemInArray ? map[parentId].indexOf(itemInArray) : -1;
                return itemIndex;
            },
            _getById: function (id) {
                var that = this;
                var idField = that._modelIdField();
                var data = that._getData();
                for (var i = 0; i < data.length; i++) {
                    if (data[i][idField] === id) {
                        return data[i];
                    }
                }
            },
            _isLastItemInView: function (dataItem) {
                var view = this.view();
                return view.length && view[view.length - 1] === dataItem;
            },
            _defaultPageableQueryOptions: function () {
                var that = this;
                var dataMaps = that._getDataMaps();
                var options = {
                    skip: that.skip(),
                    take: that.take(),
                    page: that.page(),
                    pageSize: that.pageSize(),
                    sort: that.sort(),
                    filter: that.filter(),
                    group: that.group(),
                    aggregate: that.aggregate(),
                    filterCallback: proxy(that._filterCallback, that),
                    childrenMap: dataMaps.children,
                    idsMap: dataMaps.ids
                };
                return options;
            },
            _isPageable: function () {
                var pageSize = this.pageSize();
                return !isUndefined(pageSize) && pageSize > 0 && !this.options.serverPaging;
            },
            _updateTotalForAction: function (action, items) {
                var that = this;
                DataSource.fn._updateTotalForAction.call(that, action, items);
                if (that._isPageable()) {
                    that._updateCollapsedTotalForAction(action, items);
                }
            },
            _updateCollapsedTotalForAction: function (action, items) {
                var that = this;
                var total = parseInt(that._collapsedTotal, 10);
                if (!isNumber(that._collapsedTotal)) {
                    that._calculateCollapsedTotal();
                    return;
                }
                if (action === 'add') {
                    total += items.length;
                } else if (action === 'remove') {
                    total -= items.length;
                } else if (action !== 'itemchange' && action !== 'sync' && !that.options.serverPaging) {
                    total = that._calculateCollapsedTotal();
                } else if (action === 'sync') {
                    total = that._calculateCollapsedTotal();
                }
                that._collapsedTotal = total;
            },
            _setFilterTotal: function (filterTotal, setDefaultValue) {
                var that = this;
                DataSource.fn._setFilterTotal.call(that, filterTotal, setDefaultValue);
                that._setFilterCollapsedTotal(filterTotal);
            },
            _setFilterCollapsedTotal: function (filterTotal) {
                var that = this;
                if (!that.options.serverFiltering) {
                    if (filterTotal !== undefined) {
                        that._collapsedTotal = filterTotal;
                    } else {
                        if (that._getFilteredChildrenMap()) {
                            that._calculateCollapsedTotal();
                        }
                        that._setFilteredChildrenMap(undefined);
                    }
                }
            },
            collapsedTotal: function () {
                var that = this;
                if (!isUndefined(that._collapsedTotal)) {
                    return that._collapsedTotal;
                }
                return that._calculateCollapsedTotal();
            },
            _calculateCollapsedTotal: function () {
                var that = this;
                var data = that._dataWithoutCollapsedSubtrees();
                if (data.length) {
                    that._collapsedTotal = data.length;
                }
                return that._collapsedTotal;
            },
            _dataWithoutCollapsedSubtrees: function () {
                return this._removeCollapsedSubtrees(this._getData());
            },
            _removeCollapsedSubtrees: function (data) {
                var that = this;
                var view = that._createTreeView(data);
                var result = view.removeCollapsedSubtreesFromRootNodes({
                    expanded: that._modelOptions().expanded,
                    childrenMap: that._getChildrenMap()
                });
                return result;
            },
            _processTreeQuery: function (data, options) {
                var result = TreeQuery.process(data, extend(options, this._defaultTreeModelOptions(), { processFromRootNodes: true }));
                return result;
            },
            _processDataItemsState: function (data, childrenMap) {
                var dataLength = data.length;
                var i;
                for (i = 0; i < dataLength; i++) {
                    this._processDataItemState(data[i], childrenMap);
                }
            },
            _processDataItemState: function (dataItem, childrenMap) {
                var defaultParentId = this._defaultParentId();
                if (dataItem.id === defaultParentId) {
                    return;
                }
                var children = childrenMap[dataItem.id] || [];
                var hasLoadedChildren = !!(children && children.length);
                if (!dataItem.loaded) {
                    return;
                }
                if (!dataItem.loaded()) {
                    dataItem.loaded(hasLoadedChildren || !dataItem.hasChildren);
                }
                if (dataItem.loaded() || dataItem.hasChildren !== true) {
                    dataItem.hasChildren = hasLoadedChildren;
                }
            },
            _queueRequest: function (options, callback) {
                callback.call(this);
            },
            _modelLoaded: function (id) {
                var model = this.get(id);
                model.loaded(true);
                model.hasChildren = this.childNodes(model).length > 0;
            },
            _modelError: function (id, e) {
                this.get(id)._error = e;
            },
            success: function (data, requestParams) {
                if (!requestParams || typeof requestParams.id == 'undefined') {
                    this._data = this._observe([]);
                }
                DataSource.fn.success.call(this, data, requestParams);
                this._total = this._data.length;
            },
            load: function (model) {
                var method = '_query';
                var remote = this.options.serverSorting || this.options.serverPaging || this.options.serverFiltering || this.options.serverGrouping || this.options.serverAggregates;
                var defaultPromise = $.Deferred().resolve().promise();
                if (model.loaded()) {
                    if (remote) {
                        return defaultPromise;
                    }
                } else if (model.hasChildren) {
                    method = 'read';
                    this._removeChildData(model);
                }
                return this[method]({ id: model.id }).done(proxy(this._modelLoaded, this, model.id)).fail(proxy(this._modelError, this, model.id));
            },
            contains: function (root, child) {
                var that = this;
                var idField = that._modelIdField();
                var parentIdField = that._modelParentIdField();
                var rootId = root[idField];
                var pageable = that._isPageable();
                while (child) {
                    if (child[parentIdField] === rootId) {
                        return true;
                    }
                    child = pageable ? that._parentNode(child) : that.parentNode(child);
                }
                return false;
            },
            _byParentId: function (id, defaultId) {
                var result = [];
                var view = this.view();
                var current;
                if (id === defaultId) {
                    return [];
                }
                for (var i = 0; i < view.length; i++) {
                    current = view.at(i);
                    if (current.parentId == id) {
                        result.push(current);
                    }
                }
                return result;
            },
            _defaultParentId: function () {
                return this.reader.model.fn.defaults[this.reader.model.parentIdField];
            },
            _modelOptions: function () {
                var modelOptions = (this.options.schema || {}).model || {};
                return modelOptions;
            },
            _modelIdField: function () {
                var modelOptions = this._modelOptions();
                return modelOptions.id || 'id';
            },
            _modelParentIdField: function () {
                var modelOptions = this._modelOptions();
                return modelOptions.parentId || PARENTIDFIELD;
            },
            childNodes: function (model) {
                return this._byParentId(model.id, this._defaultParentId());
            },
            rootNodes: function () {
                return this._byParentId(this._defaultParentId());
            },
            _rootNode: function (child) {
                return this._parentNodes(child)[0];
            },
            _pageableRootNodes: function (options) {
                options = options || {};
                var that = this;
                var defaultParentId = that._defaultParentId();
                var parentIdField = that._modelParentIdField();
                var result = [];
                var nodesWithoutParentInView = that._nodesWithoutParentInView(options);
                var node;
                var root;
                for (var i = 0; i < nodesWithoutParentInView.length; i++) {
                    node = nodesWithoutParentInView[i];
                    if (node[parentIdField] === defaultParentId) {
                        result.push(node);
                    } else {
                        root = that._rootNode(node);
                        if (root && result.indexOf(root) === -1) {
                            result.push(root);
                        }
                    }
                }
                return result;
            },
            parentNode: function (model) {
                return this.get(model.parentId);
            },
            _parentNode: function (child) {
                var that = this;
                var parentIdField = that._modelParentIdField();
                var idsMap = that._initIdsMap(that._getData());
                var parentId = child[parentIdField];
                var parent = idsMap[parentId] || that._getById(parentId);
                return parent;
            },
            _parentNodes: function (child) {
                var that = this;
                var parent = that._parentNode(child);
                var parents = [];
                while (parent) {
                    parents.unshift(parent);
                    parent = that._parentNode(parent);
                }
                return parents;
            },
            _parentNodesNotInView: function () {
                var that = this;
                var view = that.view();
                var result = [];
                var defaultParentId = that._defaultParentId();
                var idField = that._modelIdField();
                var parentIdField = that._modelParentIdField();
                var parentInView;
                var parents = [];
                var directParent;
                var dataItem;
                var dataItemId;
                var dataItemParentId;
                for (var i = 0; i < view.length; i++) {
                    dataItem = view[i];
                    dataItemId = dataItem[idField];
                    dataItemParentId = dataItem[parentIdField];
                    parentInView = that._parentInView(dataItemParentId);
                    if (!parentInView && dataItemParentId !== defaultParentId) {
                        parents = that._parentNodes(dataItem);
                        directParent = parents && parents.length ? parents[parents.length - 1] : that._getById(dataItemParentId);
                        if (directParent && result.indexOf(directParent) === -1) {
                            result.push(directParent);
                        }
                    }
                }
                return result;
            },
            _nodesWithoutParentInView: function (options) {
                options = options || {};
                var that = this;
                var view = that.view();
                var childrenMap = options.childrenMap || that.childrenMap(that._getData());
                var idField = that._modelIdField();
                var parentIdField = that._modelParentIdField();
                var dataItem;
                var parentInView;
                var children = [];
                var result = [];
                for (var i = 0; i < view.length; i++) {
                    dataItem = view[i];
                    children = childrenMap[dataItem[idField]];
                    parentInView = that._parentInView(dataItem[parentIdField]);
                    if (!parentInView) {
                        result.push(dataItem);
                    }
                }
                return result;
            },
            _parentInView: function (parentId) {
                var view = this.view();
                for (var i = 0; i < view.length; i++) {
                    if (view[i].id === parentId) {
                        return view[i];
                    }
                }
            },
            level: function (model) {
                var result = -1;
                if (!(model instanceof TreeListModel)) {
                    model = this.get(model);
                }
                do {
                    model = this.parentNode(model);
                    result++;
                } while (model);
                return result;
            },
            _pageableModelLevel: function (model) {
                var that = this;
                if (!model || !that._isPageable()) {
                    return 0;
                }
                var parents = that._parentNodes(model);
                return parents.length;
            },
            filter: function (value) {
                var baseFilter = DataSource.fn.filter;
                if (value === undefined) {
                    return baseFilter.call(this, value);
                }
                baseFilter.call(this, value);
            },
            _pageableQueryOptions: function (options) {
                var dataMaps = this._getDataMaps();
                options.childrenMap = dataMaps.children;
                options.idsMap = dataMaps.ids;
                return options;
            },
            _flatData: function (data, skip) {
                skip = this._isPageable() ? true : skip;
                return DataSource.fn._flatData.call(this, data, skip);
            },
            data: function (data) {
                var that = this;
                var result = DataSource.fn.data.call(that, data);
                if (that._isPageable()) {
                    that._initDataMaps(that._getData());
                    that._calculateCollapsedTotal();
                }
                return result;
            },
            cancelChanges: function (model) {
                var that = this;
                DataSource.fn.cancelChanges.call(that, model);
                that._restorePageSizeAfterAddChild();
            },
            _modelCanceled: function (model) {
                var that = this;
                if (that._isPageable()) {
                    that._removeFromDataMaps(model);
                }
            },
            _changesCanceled: function () {
                var that = this;
                if (that._isPageable()) {
                    that._initDataMaps(that._getData());
                }
            },
            _setAddChildPageSize: function () {
                var that = this;
                var queryOptions = {};
                if (that._isPageable()) {
                    that._addChildPageSize = that.pageSize() + 1;
                    queryOptions = that._defaultPageableQueryOptions();
                    queryOptions.take = that._addChildPageSize;
                    queryOptions.pageSize = that._addChildPageSize;
                    that._query(queryOptions);
                }
            },
            _restorePageSizeAfterAddChild: function () {
                var that = this;
                var queryOptions = {};
                if (that._isPageable()) {
                    if (!isUndefined(that._addChildPageSize)) {
                        queryOptions = that._defaultPageableQueryOptions();
                        queryOptions.take = that._addChildPageSize - 1;
                        queryOptions.pageSize = that._addChildPageSize - 1;
                        that._query(queryOptions);
                    }
                }
                that._addChildPageSize = undefined;
            },
            sync: function () {
                var that = this;
                return DataSource.fn.sync.call(that).then(function () {
                    that._restorePageSizeAfterAddChild();
                });
            },
            _syncEnd: function () {
                var that = this;
                if (that._isPageable()) {
                    that._initDataMaps(that._getData());
                }
            }
        });
        TreeListDataSource.create = function (options) {
            if ($.isArray(options)) {
                options = { data: options };
            } else if (options instanceof ObservableArray) {
                options = { data: options.toJSON() };
            }
            return options instanceof TreeListDataSource ? options : new TreeListDataSource(options);
        };
        function isCellVisible() {
            return this.style.display !== 'none';
        }
        function sortCells(cells) {
            var indexAttr = kendo.attr('index');
            return cells.sort(function (a, b) {
                a = $(a);
                b = $(b);
                var indexA = a.attr(indexAttr);
                var indexB = b.attr(indexAttr);
                if (indexA === undefined) {
                    indexA = $(a).index();
                }
                if (indexB === undefined) {
                    indexB = $(b).index();
                }
                indexA = parseInt(indexA, 10);
                indexB = parseInt(indexB, 10);
                return indexA > indexB ? 1 : indexA < indexB ? -1 : 0;
            });
        }
        function leafDataCells(container) {
            var rows = container.find('>tr:not(.k-filter-row)');
            var filter = function () {
                var el = $(this);
                return !el.hasClass('k-group-cell') && !el.hasClass('k-hierarchy-cell');
            };
            var cells = $();
            if (rows.length > 1) {
                cells = rows.find('th').filter(filter).filter(function () {
                    return this.rowSpan > 1;
                });
            }
            cells = cells.add(rows.last().find('th').filter(filter));
            return sortCells(cells);
        }
        function createPlaceholders(options) {
            var spans = [];
            var className = options.className;
            for (var i = 0, level = options.level; i < level; i++) {
                spans.push(kendoDomElement('span', { className: className }));
            }
            return spans;
        }
        function columnsWidth(cols) {
            var colWidth, width = 0;
            for (var idx = 0, length = cols.length; idx < length; idx++) {
                colWidth = cols[idx].style.width;
                if (colWidth && colWidth.indexOf('%') == -1) {
                    width += parseInt(colWidth, 10);
                }
            }
            return width;
        }
        function syncTableHeight(table1, table2) {
            table1 = table1[0];
            table2 = table2[0];
            if (table1.rows.length && table2.rows.length && table1.rows.length !== table2.rows.length) {
                var lockedHeigth = table1.offsetHeight;
                var tableHeigth = table2.offsetHeight;
                var row;
                var diff;
                if (lockedHeigth > tableHeigth) {
                    row = table2.rows[table2.rows.length - 1];
                    diff = lockedHeigth - tableHeigth;
                } else {
                    row = table1.rows[table1.rows.length - 1];
                    diff = tableHeigth - lockedHeigth;
                }
                row.style.height = row.offsetHeight + diff + 'px';
            }
        }
        var TreeListPager = ui.Pager.extend({
            options: { name: 'TreeListPager' },
            totalPages: function () {
                var that = this;
                var dataSource = that.dataSource;
                if (dataSource && dataSource._filter) {
                    return ui.Pager.fn.totalPages.call(that);
                }
                return Math.ceil((that._collapsedTotal() || 0) / (that.pageSize() || 1));
            },
            _createDataSource: function (options) {
                this.dataSource = kendo.data.TreeListDataSource.create(options.dataSource);
            },
            _collapsedTotal: function () {
                var dataSource = this.dataSource;
                return dataSource ? dataSource.collapsedTotal() || 0 : 0;
            }
        });
        var Editor = kendo.Observable.extend({
            init: function (element, options) {
                kendo.Observable.fn.init.call(this);
                options = this.options = extend(true, {}, this.options, options);
                this.element = element;
                this.bind(this.events, options);
                this.model = this.options.model;
                this.fields = this._fields(this.options.columns);
                this._initContainer();
                this.createEditable();
            },
            events: [],
            _initContainer: function () {
                this.wrapper = this.element;
            },
            createEditable: function () {
                var options = this.options;
                this.editable = new ui.Editable(this.wrapper, {
                    fields: this.fields,
                    target: options.target,
                    clearContainer: options.clearContainer,
                    model: this.model,
                    change: options.change
                });
            },
            _isEditable: function (column) {
                return isColumnEditable(column, this.model);
            },
            _fields: function (columns) {
                var fields = [];
                var idx, length, column;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    column = columns[idx];
                    if (this._isEditable(column)) {
                        fields.push({
                            field: column.field,
                            format: column.format,
                            editor: column.editor
                        });
                    }
                }
                return fields;
            },
            end: function () {
                return this.editable.end();
            },
            close: function () {
                this.destroy();
            },
            destroy: function () {
                this.editable.destroy();
                this.editable.element.find('[' + kendo.attr('container-for') + ']').empty().end().removeAttr(kendo.attr('role'));
                this.model = this.wrapper = this.element = this.columns = this.editable = null;
            }
        });
        var PopupEditor = Editor.extend({
            init: function (element, options) {
                Editor.fn.init.call(this, element, options);
                this._attachHandlers();
                kendo.cycleForm(this.wrapper);
                this.open();
            },
            events: [
                CANCEL,
                SAVE
            ],
            options: {
                window: {
                    modal: true,
                    resizable: false,
                    draggable: true,
                    title: 'Edit',
                    visible: false
                }
            },
            _initContainer: function () {
                var options = this.options;
                var formContent = [];
                this.wrapper = $('<div class="k-popup-edit-form"/>').attr(kendo.attr('uid'), this.model.uid).append('<div class="k-edit-form-container"/>');
                if (options.template) {
                    this._appendTemplate(formContent);
                    this.fields = [];
                } else {
                    this._appendFields(formContent);
                }
                this._appendButtons(formContent);
                new kendoDom.Tree(this.wrapper.children()[0]).render(formContent);
                this.wrapper.appendTo(options.appendTo);
                this.window = new ui.Window(this.wrapper, options.window);
            },
            _appendTemplate: function (form) {
                var template = this.options.template;
                if (typeof template === STRING) {
                    template = window.unescape(template);
                }
                template = kendo.template(template)(this.model);
                form.push(kendoHtmlElement(template));
            },
            _appendFields: function (form) {
                var idx, length, column;
                var columns = this.options.columns;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    column = columns[idx];
                    if (column.command) {
                        continue;
                    }
                    form.push(kendoHtmlElement('<div class="k-edit-label"><label for="' + column.field + '">' + (column.title || column.field || '') + '</label></div>'));
                    if (this._isEditable(column)) {
                        form.push(kendoHtmlElement('<div ' + kendo.attr('container-for') + '="' + column.field + '" class="k-edit-field"></div>'));
                    } else {
                        form.push(kendoDomElement('div', { 'class': 'k-edit-field' }, [this.options.fieldRenderer(column, this.model)]));
                    }
                }
            },
            _appendButtons: function (form) {
                form.push(kendoDomElement('div', { 'class': 'k-edit-buttons k-state-default' }, this.options.commandRenderer()));
            },
            _attachHandlers: function () {
                var closeHandler = this._cancelProxy = proxy(this._cancel, this);
                this.wrapper.on(CLICK + NS, '.k-grid-cancel', this._cancelProxy);
                this._saveProxy = proxy(this._save, this);
                this.wrapper.on(CLICK + NS, '.k-grid-update', this._saveProxy);
                this.window.bind('close', function (e) {
                    if (e.userTriggered) {
                        closeHandler(e);
                    }
                });
            },
            _detachHandlers: function () {
                this._cancelProxy = null;
                this._saveProxy = null;
                this.wrapper.off(NS);
            },
            _cancel: function (e) {
                this.trigger(CANCEL, e);
            },
            _save: function () {
                this.trigger(SAVE);
            },
            open: function () {
                this.window.center().open();
            },
            close: function () {
                this.window.bind('deactivate', proxy(this.destroy, this)).close();
            },
            destroy: function () {
                this.window.destroy();
                this.window = null;
                this._detachHandlers();
                Editor.fn.destroy.call(this);
            }
        });
        var IncellEditor = Editor.extend({
            destroy: function () {
                var that = this;
                that.editable.destroy();
                that.editable.element.off().empty().removeAttr(kendo.attr('role'));
                that.model = that.wrapper = that.element = that.columns = that.editable = null;
            }
        });
        var TreeList = DataBoundWidget.extend({
            init: function (element, options) {
                DataBoundWidget.fn.init.call(this, element, options);
                isRtl = kendo.support.isRtl(element);
                this._dataSource(this.options.dataSource);
                this._aria();
                this._columns();
                this._layout();
                this._navigatable();
                this._selectable();
                this._sortable();
                this._resizable();
                this._filterable();
                this._attachEvents();
                this._toolbar();
                this._scrollable();
                this._reorderable();
                this._columnMenu();
                this._minScreenSupport();
                this._draggable();
                this._pageable();
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
                if (this._hasLockedColumns) {
                    var widget = this;
                    this.wrapper.addClass('k-grid-lockedcolumns');
                    this._resizeHandler = function () {
                        widget.resize();
                    };
                    $(window).on('resize' + NS, this._resizeHandler);
                }
                kendo.notify(this);
            },
            _draggable: function () {
                var that = this;
                var editable = this.options.editable;
                var dataSource = that.dataSource;
                var idField = dataSource._modelIdField();
                var parentIdField = dataSource._modelParentIdField();
                var pageable = that._isPageable();
                if (!editable || !editable.move) {
                    return;
                }
                this._dragging = new kendo.ui.HierarchicalDragAndDrop(this.wrapper, {
                    $angular: this.$angular,
                    autoScroll: true,
                    filter: 'tbody>tr',
                    itemSelector: 'tr',
                    allowedContainers: this.wrapper,
                    hintText: function (row) {
                        var text = function () {
                            return $(this).text();
                        };
                        var separator = '<span class=\'k-header k-drag-separator\' />';
                        return row.children('td').map(text).toArray().join(separator);
                    },
                    contains: proxy(function (source, destination) {
                        var dest = this.dataItem(destination);
                        var src = this.dataItem(source);
                        return src == dest || this.dataSource.contains(src, dest);
                    }, this),
                    itemFromTarget: function (target) {
                        var tr = target.closest('tr');
                        return {
                            item: tr,
                            content: tr
                        };
                    },
                    dragstart: proxy(function (source) {
                        this.wrapper.addClass('k-treelist-dragging');
                        var model = this.dataItem(source);
                        return this.trigger(DRAGSTART, { source: model });
                    }, this),
                    drag: proxy(function (e) {
                        e.source = this.dataItem(e.source);
                        this.trigger(DRAG, e);
                    }, this),
                    drop: proxy(function (e) {
                        e.source = this.dataItem(e.source);
                        e.destination = this.dataItem(e.destination);
                        this.wrapper.removeClass('k-treelist-dragging');
                        return this.trigger(DROP, e);
                    }, this),
                    dragend: proxy(function (e) {
                        var dest = this.dataItem(e.destination);
                        var src = this.dataItem(e.source);
                        var originalSrcParentId = src[parentIdField];
                        var originalSrcIndex = dataSource._indexInChildrenMap(src);
                        if (pageable) {
                            dataSource._removeFromChildrenMap(src);
                            src[parentIdField] = dest ? dest[idField] : null;
                            dataSource._initChildrenMapForParent(dest);
                            src[parentIdField] = originalSrcParentId;
                        }
                        var isPrevented = src.set('parentId', dest ? dest.id : null);
                        if (pageable && isPrevented) {
                            dataSource._removeFromChildrenMap(src);
                            src[parentIdField] = originalSrcParentId;
                            dataSource._removeFromChildrenMap(src);
                            dataSource._insertInChildrenMap(src, originalSrcIndex);
                        }
                        e.source = src;
                        e.destination = dest;
                        this.trigger(DRAGEND, e);
                    }, this),
                    reorderable: false,
                    dropHintContainer: function (item) {
                        return item.children('td:eq(1)');
                    },
                    dropPositionFrom: function (dropHint) {
                        return dropHint.prevAll('.k-i-none').length > 0 ? 'after' : 'before';
                    }
                });
            },
            itemFor: function (model) {
                if (typeof model == 'number') {
                    model = this.dataSource.get(model);
                }
                return this.tbody.find('[' + kendo.attr('uid') + '=' + model.uid + ']');
            },
            _itemFor: function (model) {
                var that = this;
                var table = that.lockedContent ? that.lockedTable : that.table;
                if (typeof model == 'number') {
                    model = this.dataSource.get(model);
                }
                return table.find('[' + kendo.attr('uid') + '=' + model.uid + ']');
            },
            _scrollable: function () {
                if (this.options.scrollable) {
                    var scrollables = this.thead.closest('.k-grid-header-wrap');
                    var lockedContent = $(this.lockedContent).bind('DOMMouseScroll' + NS + ' mousewheel' + NS, proxy(this._wheelScroll, this));
                    this.content.bind('scroll' + NS, function () {
                        scrollables.scrollLeft(this.scrollLeft);
                        lockedContent.scrollTop(this.scrollTop);
                    });
                    var touchScroller = kendo.touchScroller(this.content);
                    if (touchScroller && touchScroller.movable) {
                        this._touchScroller = touchScroller;
                        touchScroller.movable.bind('change', function (e) {
                            scrollables.scrollLeft(-e.sender.x);
                            if (lockedContent) {
                                lockedContent.scrollTop(-e.sender.y);
                            }
                        });
                    }
                }
            },
            _wheelScroll: function (e) {
                if (e.ctrlKey) {
                    return;
                }
                var delta = kendo.wheelDeltaY(e);
                var lockedDiv = $(e.currentTarget);
                if (delta) {
                    if (lockedDiv[0].scrollHeight > lockedDiv[0].clientHeight && (lockedDiv[0].scrollTop < lockedDiv[0].scrollHeight - lockedDiv[0].clientHeight && delta < 0 || lockedDiv[0].scrollTop > 0 && delta > 0)) {
                        e.preventDefault();
                    }
                    lockedDiv.one('wheel' + NS, false);
                    this.content.scrollTop(this.content.scrollTop() + -delta);
                }
            },
            _progress: function () {
                var messages = this.options.messages;
                if (!this.tbody.find('tr').length) {
                    this._showStatus(kendo.template('<span class=\'#= className #\' /> #: messages.loading #')({
                        className: classNames.icon + ' ' + classNames.loading,
                        messages: messages
                    }));
                }
            },
            _error: function (e) {
                if (!this.dataSource.rootNodes().length) {
                    this._render({ error: e });
                }
            },
            refresh: function (e) {
                e = e || {};
                if (e.action == 'itemchange' && this.editor) {
                    return;
                }
                if (this.trigger(DATABINDING)) {
                    return;
                }
                var current = $(this.current());
                var isCurrentInHeader = false;
                var currentIndex;
                this._cancelEditor();
                this._render();
                this._adjustHeight();
                if (this.options.navigatable) {
                    if (this._isActiveInTable() || this.editor) {
                        isCurrentInHeader = current.is('th');
                        currentIndex = Math.max(this.cellIndex(current), 0);
                    }
                    this._restoreCurrent(currentIndex, isCurrentInHeader);
                }
                this.trigger(DATABOUND);
            },
            _angularFooters: function (command) {
                var i, footer, aggregates;
                var allAggregates = this.dataSource.aggregates();
                var footerRows = this._footerItems();
                for (i = 0; i < footerRows.length; i++) {
                    footer = footerRows.eq(i);
                    aggregates = allAggregates[footer.attr('data-parentId')];
                    this._angularFooter(command, footer.find('td').get(), aggregates);
                }
            },
            _angularFooter: function (command, cells, aggregates) {
                var columns = this.columns;
                this.angular(command, function () {
                    return {
                        elements: cells,
                        data: map(columns, function (col) {
                            return {
                                column: col,
                                aggregate: aggregates && aggregates[col.field]
                            };
                        })
                    };
                });
            },
            items: function () {
                if (this._hasLockedColumns) {
                    return this._items(this.tbody).add(this._items(this.lockedTable));
                } else {
                    return this._items(this.tbody);
                }
            },
            _items: function (container) {
                return container.find('tr[data-uid]').filter(function () {
                    return !$(this).hasClass(classNames.footerTemplate);
                });
            },
            _footerItems: function () {
                var container = this.tbody;
                if (this._hasLockedColumns) {
                    container = container.add(this.lockedTable);
                }
                return container.find('tr').filter(function () {
                    return $(this).hasClass(classNames.footerTemplate);
                });
            },
            dataItems: function () {
                var dataItems = kendo.ui.DataBoundWidget.fn.dataItems.call(this);
                if (this._hasLockedColumns) {
                    var n = dataItems.length, tmp = new Array(2 * n);
                    for (var i = n; --i >= 0;) {
                        tmp[i] = tmp[i + n] = dataItems[i];
                    }
                    dataItems = tmp;
                }
                return dataItems;
            },
            _showNoRecordsTemplate: function () {
                var wrapper = '<div class="{0}">{1}</div>';
                var defaultTemplate = '<div class="k-grid-norecords-template"{1}>{0}</div>';
                var scrollableNoGridHeightStyles = this.options.scrollable && !this.wrapper[0].style.height ? ' style="margin:0 auto;position:static;"' : '';
                var template;
                this._contentTree.render([]);
                if (this._hasLockedColumns) {
                    this._lockedContentTree.render([]);
                }
                template = kendo.format(defaultTemplate, this.options.messages.noRows, scrollableNoGridHeightStyles);
                $(kendo.template(kendo.format(wrapper, NORECORDSCLASS, template))({})).insertAfter(this.table);
            },
            _showStatus: function (message) {
                var status = this.element.find('.k-status');
                var content = $(this.content).add(this.lockedContent);
                if (!status.length) {
                    status = $('<div class=\'k-status\' />').appendTo(this.element);
                }
                this._contentTree.render([]);
                if (this._hasLockedColumns) {
                    this._lockedContentTree.render([]);
                }
                content.hide();
                status.html(message);
            },
            _hideStatus: function () {
                this.element.find('.k-status').remove();
                this._hideNoRecordsTempalte();
                $(this.content).add(this.lockedContent).show();
            },
            _hideNoRecordsTempalte: function () {
                this.element.find('.' + NORECORDSCLASS).remove();
            },
            _adjustHeight: function () {
                var that = this;
                var element = this.element;
                var contentWrap = element.find(DOT + classNames.gridContentWrap);
                var header = element.find(DOT + classNames.gridHeader);
                var toolbar = element.find(DOT + classNames.gridToolbar);
                var status = element.find(DOT + classNames.status);
                var pagerHeight = that._isPageable() && that.pager && that.pager.element.is(':visible') ? outerHeight(that.pager.element) : 0;
                var height;
                var scrollbar = kendo.support.scrollbar();
                element.css(HEIGHT, this.options.height);
                var isHeightSet = function (el) {
                    var initialHeight, newHeight;
                    if (el[0].style.height) {
                        return true;
                    } else {
                        initialHeight = el.height();
                    }
                    el.height('auto');
                    newHeight = el.height();
                    el.height('');
                    return initialHeight != newHeight;
                };
                if (isHeightSet(element)) {
                    height = element.height() - outerHeight(header) - outerHeight(toolbar) - outerHeight(status) - pagerHeight;
                    contentWrap.height(height);
                    if (this._hasLockedColumns) {
                        scrollbar = this.table[0].offsetWidth > this.table.parent()[0].clientWidth ? scrollbar : 0;
                        this.lockedContent.height(height - scrollbar);
                    }
                }
            },
            _resize: function (size, force) {
                this._applyLockedContainersWidth();
                this._adjustHeight();
                if (this.pager && this.pager.element) {
                    this.pager.resize(force);
                }
            },
            _minScreenSupport: function () {
                var any = this.hideMinScreenCols();
                if (any) {
                    this.minScreenResizeHandler = proxy(this.hideMinScreenCols, this);
                    $(window).on('resize', this.minScreenResizeHandler);
                }
            },
            _iterateMinScreenCols: function (cols, screenWidth) {
                var any = false;
                for (var i = 0; i < cols.length; i++) {
                    var col = cols[i];
                    var minWidth = col.minScreenWidth;
                    if (minWidth !== undefined && minWidth !== null) {
                        any = true;
                        if (minWidth > screenWidth) {
                            this.hideColumn(col);
                        } else {
                            this.showColumn(col);
                        }
                    }
                    if (!col.hidden && col.columns) {
                        any = this._iterateMinScreenCols(col.columns, screenWidth) || any;
                    }
                }
                return any;
            },
            hideMinScreenCols: function () {
                var cols = this.columns, screenWidth = window.innerWidth > 0 ? window.innerWidth : screen.width;
                return this._iterateMinScreenCols(cols, screenWidth);
            },
            destroy: function () {
                DataBoundWidget.fn.destroy.call(this);
                var dataSource = this.dataSource;
                dataSource.unbind(CHANGE, this._refreshHandler);
                dataSource.unbind(ERROR, this._errorHandler);
                dataSource.unbind(PROGRESS, this._progressHandler);
                this._navigatableTables = null;
                this._current = null;
                if (this._resizeHandler) {
                    $(window).off('resize' + NS, this._resizeHandler);
                }
                if (this._dragging) {
                    this._dragging.destroy();
                    this._dragging = null;
                }
                if (this.resizable) {
                    this.resizable.destroy();
                    this.resizable = null;
                }
                if (this.reorderable) {
                    this.reorderable.destroy();
                    this.reorderable = null;
                }
                if (this._draggableInstance && this._draggableInstance.element) {
                    this._draggableInstance.destroy();
                    this._draggableInstance = null;
                }
                if (this.minScreenResizeHandler) {
                    $(window).off('resize', this.minScreenResizeHandler);
                }
                this._destroyEditor();
                this.element.off(NS);
                this.wrapper.off(NS);
                if (this._touchScroller) {
                    this._touchScroller.destroy();
                }
                this._destroyPager();
                if (dataSource) {
                    dataSource._dataMaps = null;
                }
                this._autoExpandable = null;
                this._refreshHandler = this._errorHandler = this._progressHandler = this._dataSourceFetchProxy = null;
                this.thead = this.content = this.tbody = this.table = this.element = this.lockedHeader = this.lockedContent = null;
                this._statusTree = this._headerTree = this._contentTree = this._lockedHeaderColsTree = this._lockedContentColsTree = this._lockedHeaderTree = this._lockedContentTree = null;
            },
            options: {
                name: 'TreeList',
                columns: [],
                autoBind: true,
                scrollable: true,
                selectable: false,
                sortable: false,
                toolbar: null,
                height: null,
                columnMenu: false,
                messages: {
                    noRows: 'No records to display',
                    loading: 'Loading...',
                    requestFailed: 'Request failed.',
                    retry: 'Retry',
                    commands: {
                        edit: 'Edit',
                        update: 'Update',
                        canceledit: 'Cancel',
                        create: 'Add new record',
                        createchild: 'Add child record',
                        destroy: 'Delete',
                        excel: 'Export to Excel',
                        pdf: 'Export to PDF'
                    }
                },
                excel: { hierarchy: true },
                resizable: false,
                filterable: false,
                editable: false,
                reorderable: false,
                pageable: false
            },
            events: [
                CHANGE,
                BEFORE_EDIT,
                EDIT,
                PAGE,
                SAVE,
                SAVE_CHANGES,
                REMOVE,
                EXPAND,
                COLLAPSE,
                DATABINDING,
                DATABOUND,
                CANCEL,
                DRAGSTART,
                DRAG,
                DROP,
                DRAGEND,
                FILTERMENUINIT,
                ITEM_CHANGE,
                CELL_CLOSE,
                FILTERMENUOPEN,
                COLUMNHIDE,
                COLUMNSHOW,
                COLUMNREORDER,
                COLUMNRESIZE,
                COLUMNMENUINIT,
                COLUMNMENUOPEN,
                COLUMNLOCK,
                COLUMNUNLOCK
            ],
            _toggle: function (model, expand) {
                var that = this;
                var defaultPromise = $.Deferred().resolve().promise();
                var loaded = model.loaded();
                if (that._isIncellEditable() && that.editor) {
                    $(activeElement()).change();
                    that.closeCell();
                }
                if (model._error) {
                    model.expanded = false;
                    model._error = undefined;
                }
                if (!loaded && model.expanded) {
                    return defaultPromise;
                }
                if (typeof expand == 'undefined') {
                    expand = !model.expanded;
                }
                model.expanded = expand;
                function afterModelLoaded() {
                    that._toggleData();
                    that._render();
                    that._syncLockedContentHeight();
                }
                if (!loaded) {
                    defaultPromise = this.dataSource.load(model).always(proxy(function () {
                        afterModelLoaded();
                    }, this));
                }
                afterModelLoaded();
                return defaultPromise;
            },
            _toggleData: function () {
                var that = this;
                if (that._isPageable()) {
                    that._togglePageableData();
                }
            },
            _togglePageableData: function () {
                var that = this;
                var dataSource = that.dataSource;
                var data = dataSource._getData();
                var result;
                var queryOptions = dataSource._defaultPageableQueryOptions();
                that._renderProgress(true);
                var childrenMap = dataSource._getChildrenMap() || dataSource.childrenMap(dataSource._getData());
                dataSource._processDataItemsState(data, childrenMap);
                result = dataSource._processPageableQuery(data, queryOptions);
                queryOptions.childrenMap = result.childrenMap;
                queryOptions.filteredChildrenMap = result.filteredChildrenMap;
                dataSource._aggregateResult = dataSource._calculateAggregates(result.dataToAggregate, queryOptions);
                dataSource.view(result.data);
                dataSource._calculateCollapsedTotal();
                that._refreshPager();
                that._renderProgress(false);
            },
            _refreshPager: function () {
                var pager = this.pager;
                if (pager) {
                    pager.refresh();
                }
            },
            expand: function (row) {
                return this._toggle(this.dataItem(row), true);
            },
            collapse: function (row) {
                return this._toggle(this.dataItem(row), false);
            },
            _toggleChildren: function (e) {
                var icon = $(e.currentTarget);
                var model = this.dataItem(icon);
                if (!model) {
                    return;
                }
                var event = !model.expanded ? EXPAND : COLLAPSE;
                if (!this.trigger(event, { model: model })) {
                    this._toggle(model);
                }
                e.preventDefault();
            },
            _navigatable: function () {
                var that = this;
                if (!that.options.navigatable) {
                    return;
                }
                var tables = that.table.add(that.lockedTable);
                var headerTables = that.thead.parent().add($('>table', that.lockedHeader));
                if (that.options.scrollable) {
                    tables = tables.add(headerTables);
                    headerTables.attr(TABINDEX, -1);
                }
                this._navigatableTables = tables;
                tables.on(kendo.support.touch ? 'touchstart' + NS : 'mousedown' + NS, NAVROW + '>:visible', proxy(that._tableClick, that)).on('focus' + NS, proxy(that._tableFocus, that)).on('focusout' + NS, proxy(that._tableBlur, that)).on('keydown' + NS, proxy(that._tableKeyDown, that));
            },
            cellIndex: function (td) {
                var lockedColumnOffset = 0;
                if (this.lockedTable && !$.contains(this.lockedTable[0], td[0])) {
                    lockedColumnOffset = leafColumns(lockedColumns(this.columns)).length;
                }
                return $(td).parent().children().index(td) + lockedColumnOffset;
            },
            _isActiveInTable: function () {
                var active = kendo._activeElement();
                if (!active) {
                    return false;
                }
                return this.table[0] === active || $.contains(this.table[0], active) || this.lockedTable && (this.lockedTable[0] === active || $.contains(this.lockedTable[0], active));
            },
            _restoreCurrent: function (currentIndex, isCurrentInHeader) {
                var rowIndex;
                var row;
                var td;
                if (currentIndex === undefined || currentIndex < 0) {
                    return;
                }
                if (this._current) {
                    this._current.removeClass('k-state-focused');
                }
                if (isCurrentInHeader) {
                    this.current(this.thead.find('th').eq(currentIndex));
                } else {
                    rowIndex = 0;
                    currentIndex = 0;
                    row = $();
                    if (this.lockedTable) {
                        row = this.lockedTable.find('>tbody>tr:visible').eq(rowIndex);
                    }
                    row = row.add(this.tbody.children().eq(rowIndex));
                    td = row.find('>td:visible').eq(currentIndex);
                    this.current(td);
                }
                if (this._current) {
                    focusTable(this._current.closest('table')[0], true);
                }
            },
            current: function (newCurrent) {
                var current = this._current;
                newCurrent = $(newCurrent);
                if (newCurrent.length && (!current || current[0] !== newCurrent[0])) {
                    this._updateCurrentAttr(current, newCurrent);
                    this._scrollCurrent();
                }
                if (newCurrent && newCurrent.length) {
                    this._lastCellIndex = newCurrent.parent().children(DATA_CELL).index(newCurrent);
                }
                return this._current;
            },
            _setCurrent: function (newCurrent) {
                var that = this;
                newCurrent = $(newCurrent);
                if (newCurrent[0]) {
                    that._current = newCurrent;
                    that._updateCurrentAttr(that._current, newCurrent);
                    that._scrollCurrent();
                }
                return that._current;
            },
            _scrollCurrent: function () {
                var current = this._current;
                var scrollable = this.options.scrollable;
                if (!current || !scrollable) {
                    return;
                }
                var row = current.parent();
                var tableContainer = row.closest('table').parent();
                var isInLockedContainer = tableContainer.is('.k-grid-content-locked,.k-grid-header-locked');
                var isInContent = tableContainer.is('.k-grid-content-locked,.k-grid-content');
                var scrollableContainer = $(this.content)[0];
                if (isInContent) {
                    this._scrollTo(this._relatedRow(row)[0], scrollableContainer);
                }
                if (this.lockedContent) {
                    this.lockedContent[0].scrollTop = scrollableContainer.scrollTop;
                }
                if (!isInLockedContainer) {
                    this._scrollTo(current[0], scrollableContainer);
                }
            },
            _findCurrentCell: function () {
                var that = this;
                var current = that.current();
                var elements = $(that.table).add(that.header).add(that.lockedTable).add(that.lockedHeader);
                if (current && elements.find(current).length > 0) {
                    return current;
                } else {
                    return elements.find(DOT + classNames.focused);
                }
            },
            _scrollTo: function (element, container) {
                var elementToLowercase = element.tagName.toLowerCase();
                var isHorizontal = elementToLowercase === 'td' || elementToLowercase === 'th';
                var elementOffset = element[isHorizontal ? 'offsetLeft' : 'offsetTop'];
                var elementOffsetDir = element[isHorizontal ? 'offsetWidth' : 'offsetHeight'];
                var containerScroll = container[isHorizontal ? 'scrollLeft' : 'scrollTop'];
                var containerOffsetDir = container[isHorizontal ? 'clientWidth' : 'clientHeight'];
                var bottomDistance = elementOffset + elementOffsetDir;
                var result = 0;
                var ieCorrection = 0;
                var firefoxCorrection = 0;
                if (isRtl && isHorizontal) {
                    var table = $(element).closest('table')[0];
                    if (browser.msie) {
                        ieCorrection = table.offsetLeft;
                    } else if (browser.mozilla) {
                        firefoxCorrection = table.offsetLeft - kendo.support.scrollbar();
                    }
                }
                containerScroll = Math.abs(containerScroll + ieCorrection - firefoxCorrection);
                if (containerScroll > elementOffset) {
                    result = elementOffset;
                } else if (bottomDistance > containerScroll + containerOffsetDir) {
                    if (elementOffsetDir <= containerOffsetDir) {
                        result = bottomDistance - containerOffsetDir;
                    } else {
                        result = elementOffset;
                    }
                } else {
                    result = containerScroll;
                }
                result = Math.abs(result + ieCorrection) + firefoxCorrection;
                container[isHorizontal ? 'scrollLeft' : 'scrollTop'] = result;
            },
            _aria: function () {
                var id = this.element.attr('id') || 'aria';
                if (id) {
                    this._elementId = id + '_active_element';
                }
            },
            _currentDataIndex: function (table, current) {
                var index = current.attr('data-index');
                if (!index) {
                    return undefined;
                }
                var lockedColumnsCount = lockedColumns(this.columns).length;
                if (lockedColumnsCount && !table.closest('div').hasClass('k-grid-content-locked')[0]) {
                    return index - lockedColumnsCount;
                }
                return index;
            },
            _prevVerticalCell: function (container, current) {
                var cells;
                var row = current.parent();
                var rows = container.children(NAVROW);
                var rowIndex = rows.index(row);
                var index = this._currentDataIndex(container, current);
                if (index || current.hasClass('k-header')) {
                    cells = parentColumnsCells(current);
                    return cells.eq(cells.length - 2);
                }
                index = Math.max(row.children(DATA_CELL).index(current), this._lastCellIndex || 0);
                if (row.hasClass('k-filter-row')) {
                    return leafDataCells(container).filter(isCellVisible).eq(index);
                }
                if (rowIndex == -1) {
                    row = container.find('tr.k-filter-row:visible');
                    if (!row[0]) {
                        return leafDataCells(container).filter(isCellVisible).eq(index);
                    }
                } else {
                    row = rowIndex === 0 ? $() : rows.eq(rowIndex - 1);
                }
                cells = row.children(DATA_CELL);
                if (cells.length > index) {
                    return cells.eq(index);
                }
                return cells.eq(0);
            },
            _nextVerticalCell: function (container, current) {
                var cells;
                var row = current.parent();
                var rows = container.children(NAVROW);
                var rowIndex = rows.index(row);
                var index = this._currentDataIndex(container, current);
                if (rowIndex != -1 && index === undefined && current.hasClass('k-header')) {
                    return childColumnsCells(current).eq(1);
                }
                index = index ? parseInt(index, 10) : row.children(DATA_CELL).index(current);
                index = Math.max(index, this._lastCellIndex || 0);
                if (rowIndex == -1) {
                    row = rows.eq(0);
                } else {
                    row = rows.eq(rowIndex + current[0].rowSpan);
                }
                var tmpIndex = index;
                if (this._currentDataIndex(container, current) !== undefined) {
                    var currentRowCells = row.children(':not(.k-group-cell):not(.k-hierarchy-cell)');
                    var hiddenColumns = currentRowCells.filter(':hidden');
                    for (var idx = 0, length = hiddenColumns.length; idx < length; idx++) {
                        if (currentRowCells.index(hiddenColumns[idx]) < index) {
                            tmpIndex--;
                        }
                    }
                }
                index = tmpIndex;
                cells = row.children(DATA_CELL);
                if (cells.length > index) {
                    return cells.eq(index);
                }
                return cells.eq(0);
            },
            _verticalContainer: function (container, up) {
                var table = container.parent();
                var length = this._navigatableTables.length;
                var step = Math.floor(length / 2);
                var index = inArray(table[0], this._navigatableTables);
                if (up) {
                    step *= -1;
                }
                index += step;
                if (index >= 0 || index < length) {
                    table = this._navigatableTables.eq(index);
                }
                return table.find(up ? 'thead' : 'tbody');
            },
            _updateCurrentAttr: function (current, next) {
                var headerId = $(current).data('headerId');
                $(current).removeClass(classNames.focused).closest('table').removeAttr('aria-activedescendant');
                if (headerId) {
                    headerId = headerId.replace(this._elementId, '');
                    $(current).attr('id', headerId);
                } else {
                    $(current).removeAttr('id');
                }
                next.data('headerId', next.attr('id')).attr('id', this._elementId).addClass(classNames.focused).closest('table').attr('aria-activedescendant', this._elementId);
                this._current = next;
            },
            _tableKeyDown: function (e) {
                var handled = false;
                var current = this.current();
                var target = $(e.target);
                var canHandle = !e.isDefaultPrevented() && !target.is(':button,a,:input,a>.k-icon');
                current = current ? current : $(this.lockedTable).add(this.table).find(FIRSTNAVITEM);
                if (canHandle && e.keyCode == keys.UP) {
                    handled = this._moveUp(current, e.shiftKey);
                }
                if (canHandle && e.keyCode == keys.DOWN) {
                    handled = this._moveDown(current, e.shiftKey);
                }
                if (canHandle && e.keyCode == (isRtl ? keys.LEFT : keys.RIGHT)) {
                    if (e.altKey) {
                        handled = this._handleExpand(current);
                    } else {
                        handled = this._moveRight(current);
                    }
                }
                if (canHandle && e.keyCode == (isRtl ? keys.RIGHT : keys.LEFT)) {
                    if (e.altKey) {
                        handled = this._handleCollapse(current);
                    } else {
                        handled = this._moveLeft(current);
                    }
                }
                if (canHandle && e.keyCode == keys.PAGEDOWN) {
                    handled = this._handlePageDown();
                }
                if (canHandle && e.keyCode == keys.PAGEUP) {
                    handled = this._handlePageUp();
                }
                if (e.keyCode == keys.ENTER || e.keyCode == keys.F2) {
                    handled = this._handleEnterKey(current, e.currentTarget, target);
                }
                if (e.keyCode == keys.ESC) {
                    handled = this._handleEscKey(current, e.currentTarget);
                }
                if (canHandle && e.keyCode == keys.HOME) {
                    handled = this._handleHome(current, e.ctrlKey);
                }
                if (canHandle && e.keyCode == keys.END) {
                    handled = this._handleEnd(current, e.ctrlKey);
                }
                if (e.keyCode == keys.TAB) {
                    handled = this._handleTabKey(current, e.currentTarget, e.shiftKey);
                }
                if (handled) {
                    e.preventDefault();
                    e.stopPropagation();
                }
            },
            _handleExpand: function (current) {
                var that = this;
                var row = current.parent();
                var model = that.dataItem(row);
                if (current.hasClass('k-header')) {
                    return false;
                }
                if (model && model.hasChildren && !model.expanded && !that.trigger(EXPAND, { model: model })) {
                    this.expand(row);
                    return true;
                }
                return false;
            },
            _handleCollapse: function (current) {
                var that = this;
                var row = current.parent();
                var model = that.dataItem(row);
                if (current.hasClass('k-header')) {
                    return false;
                }
                if (model && model.hasChildren && model.expanded && !that.trigger(COLLAPSE, { model: model })) {
                    that.collapse(row);
                    return true;
                }
                return false;
            },
            _handleHome: function (current, ctrl) {
                var row = current.parent();
                var rowContainer = row.parent();
                var isInLockedTable = this.lockedTable && this.lockedTable.children('tbody')[0] === rowContainer[0];
                var isInBody = rowContainer[0] === this.tbody[0];
                var prev;
                if (ctrl) {
                    if (this.lockedTable) {
                        prev = this.lockedTable.find(FIRSTNAVITEM);
                    } else {
                        prev = this.table.find(FIRSTNAVITEM);
                    }
                } else if (isInBody || isInLockedTable) {
                    if (isInBody && this.lockedTable) {
                        row = this._relatedRow(row);
                    }
                    prev = row.children(NAVCELL + ':first');
                }
                if (prev && prev.length) {
                    this.current(prev);
                    return true;
                }
            },
            _handleEnd: function (current, ctrl) {
                var row = current.parent();
                var rowContainer = row.parent();
                var isInLockedTable = this.lockedTable && this.lockedTable.children('tbody')[0] === rowContainer[0];
                var isInBody = rowContainer[0] === this.tbody[0];
                var next;
                if (ctrl) {
                    next = this.table.find(LASTITEMROW + '>' + NAVCELL + ':last');
                } else if (isInBody || isInLockedTable) {
                    if (!isInBody && this.lockedTable) {
                        row = this._relatedRow(row);
                    }
                    next = row.children(NAVCELL + ':last');
                }
                if (next && next.length) {
                    this.current(next);
                    return true;
                }
            },
            _handlePageDown: function () {
                var that = this;
                if (!that._isPageable()) {
                    return false;
                }
                that.dataSource._restorePageSizeAfterAddChild();
                that.dataSource.page(that.dataSource.page() + 1);
                return true;
            },
            _handlePageUp: function () {
                var that = this;
                if (!that._isPageable()) {
                    return false;
                }
                that.dataSource._restorePageSizeAfterAddChild();
                that.dataSource.page(that.dataSource.page() - 1);
                return true;
            },
            _handleEscKey: function (current, currentTable) {
                var active = kendo._activeElement();
                var currentIndex;
                var that = this;
                var row;
                var rowIndex;
                var cellIndex;
                var tbody;
                if (!current || !current.parent().hasClass('k-grid-edit-row')) {
                    if (current.has(active).length) {
                        focusTable(currentTable, true);
                        return true;
                    }
                    return false;
                }
                if (that._isIncellEditable()) {
                    row = current.parent();
                    cellIndex = current.index();
                    rowIndex = row.index();
                    tbody = row.closest('tbody');
                    that.closeCell(true);
                    that._setCurrent(tbody.children().eq(rowIndex).children().eq(cellIndex));
                } else {
                    currentIndex = $(current).parent().index();
                    if (active) {
                        active.blur();
                    }
                    this.cancelRow();
                    if (currentIndex >= 0) {
                        this.current(this.items().eq(currentIndex).children(NAVCELL).first());
                    }
                }
                if (browser.msie && browser.version < 9) {
                    document.body.focus();
                }
                focusTable(currentTable, true);
                return true;
            },
            _handleEnterKey: function (current, currentTable, target) {
                var editable = this.options.editable;
                var container = target.closest('[role=gridcell]');
                var focusable;
                if (!target.is('table') && !$.contains(current[0], target[0])) {
                    current = container;
                }
                if (current.is('th')) {
                    current.find('.k-link').click();
                    return true;
                }
                focusable = current.find(':kendoFocusable:first');
                if (focusable[0] && current.hasClass('k-state-focused')) {
                    focusable.focus();
                    return true;
                }
                if (editable && !target.is(':button,.k-button,textarea')) {
                    if (!container[0]) {
                        container = current;
                    }
                    this._handleEditing(container, false, currentTable);
                    return true;
                }
                return false;
            },
            _handleTabKey: function (current, currentTable, shiftKey) {
                var that = this;
                var incellEditing = that.options.editable && that._isIncellEditable();
                var cell;
                if (!incellEditing || current.is('th')) {
                    return false;
                }
                cell = $(activeElement()).closest(DOT + classNames.editCell);
                if (cell[0] && cell[0] !== current[0]) {
                    current = cell;
                }
                cell = that._tabNext(current, currentTable, shiftKey);
                if (cell.length) {
                    that._handleEditing(current, cell, cell.closest(TABLE));
                    return true;
                } else {
                    that._preventPageSizeRestore = false;
                }
                return false;
            },
            _tabNext: function (current, currentTable, back) {
                var that = this;
                var switchRow = true;
                var next = back ? current.prevAll(DATA_CELL + ':first') : current.nextAll(':visible:first');
                if (!next.length) {
                    next = current.parent();
                    if (that.lockedTable) {
                        switchRow = back && currentTable == that.lockedTable[0] || !back && currentTable == that.table[0];
                        next = that._relatedRow(next);
                    }
                    if (switchRow) {
                        next = next[back ? 'prevAll' : 'nextAll']('tr:not(.k-grouping-row):not(.k-detail-row):visible:first');
                    }
                    next = next.children(DATA_CELL + (back ? ':last' : ':first'));
                    that.dataSource._restorePageSizeAfterAddChild();
                }
                return next;
            },
            _handleEditing: function (current, next, table) {
                var that = this, active = $(kendo._activeElement()), isIE = browser.msie, editContainer, focusable, isEdited;
                var editable = that.options.editable && that.options.editable.update !== false;
                var incellEditing = that._isIncellEditable();
                var nextFocusableCellRowIndex = $(next).parents('tr').index();
                var nextFocusableCellIndex = $(next).index();
                var currentFocusedCellRowIndex = $(current).parents('tr').index();
                var currentFocusedCellIndex = current.index();
                var editedCell;
                table = $(table);
                if (incellEditing) {
                    isEdited = current.hasClass(classNames.editCell);
                } else {
                    isEdited = current.parent().hasClass('k-grid-edit-row');
                }
                if (that.editor) {
                    editContainer = that.editor.wrapper;
                    if (editContainer && $.contains(editContainer[0], active[0])) {
                        if (browser.opera) {
                            active.blur().change().triggerHandler('blur');
                        } else {
                            active.blur();
                            if (isIE) {
                                active.blur();
                            }
                        }
                    }
                    if (!that.editor) {
                        focusTable(table);
                        return;
                    }
                    if (that.editor.end()) {
                        if (incellEditing) {
                            that._preventPageSizeRestore = true;
                            that.closeCell();
                            that._preventPageSizeRestore = false;
                            if ($(that.table).add(that.lockedTable).find(DOT + classNames.editCell).length === 0) {
                                that.current(table.find('tbody').children().eq(currentFocusedCellRowIndex).children().eq(currentFocusedCellIndex));
                            }
                        } else {
                            that.saveRow();
                            isEdited = true;
                        }
                    } else {
                        if (incellEditing) {
                            that.current(editContainer);
                        } else {
                            that.current(editContainer.children().filter(NAVCELL).first());
                        }
                        focusable = editContainer.find(':kendoFocusable:first')[0];
                        if (focusable) {
                            focusable.focus();
                        }
                        return;
                    }
                }
                next = $(next).length && table.find(next).length === 0 ? table.find('tbody').children().eq(nextFocusableCellRowIndex).children().eq(nextFocusableCellIndex) : next;
                if (next) {
                    that.current(next);
                }
                focusTable(table, true);
                if (!editable) {
                    return;
                }
                if (!isEdited && !next || next) {
                    var currentIndex = that.current().index();
                    if (incellEditing) {
                        that.editCell(that.current());
                        editedCell = $(that.table).add(that.lockedTable).find(DOT + classNames.editCell)[0];
                        if (editedCell) {
                            that._current = $(editedCell);
                        } else {
                            that.current(that._findCurrentCell());
                        }
                    } else {
                        that.editRow(that.current().parent());
                        that.current(that.editor.wrapper.children().eq(currentIndex));
                        that.current().removeClass('k-state-focused');
                    }
                } else {
                    that.dataSource._restorePageSizeAfterAddChild();
                }
            },
            _moveRight: function (current) {
                var next = current.nextAll(NAVCELL).first();
                var row = current.parent();
                if (current.hasClass('k-header')) {
                    next = current.nextAll(NAVHEADER).first();
                    if (!next[0] && this.lockedTable && current.closest('table')[0] === this.lockedHeader.find('table')[0]) {
                        next = this.thead.find(NAVHEADER + ':first');
                    }
                }
                if (!next[0] && this.lockedTable && current.closest('table')[0] === this.lockedTable[0]) {
                    next = this._relatedRow(row).children(NAVCELL).first();
                }
                if (next[0] && next[0] !== current[0]) {
                    focusTable(next.closest('table'), true);
                }
                this.current(next);
                return true;
            },
            _moveLeft: function (current) {
                var prev = current.prevAll(NAVCELL).first();
                var row = current.parent();
                if (current.hasClass('k-header')) {
                    prev = current.prevAll(NAVHEADER).first();
                    if (!prev[0] && this.lockedTable && current.closest('table')[0] === this.thead.parent()[0]) {
                        prev = this.lockedHeader.find('>table>thead>tr>' + NAVHEADER + ':last');
                    }
                }
                if (!prev[0] && this.lockedTable && current.closest('table')[0] === this.table[0]) {
                    prev = this._relatedRow(row).children(NAVCELL).last();
                }
                if (prev[0] && prev[0] !== current[0]) {
                    focusTable(prev.closest('table'), true);
                }
                this.current(prev);
                return true;
            },
            _moveUp: function (current, shiftKey) {
                var container = current.parent().parent();
                var prev;
                if (shiftKey) {
                    prev = current.parent();
                    prev = prev.prevAll(ITEMROW + ':first');
                    prev = current.parent().is(ITEMROW) ? prev.children().eq(current.index()) : prev.children(DATA_CELL + ':last');
                } else {
                    prev = this._prevVerticalCell(container, current);
                    if (!prev[0]) {
                        this._lastCellIndex = 0;
                        container = this._verticalContainer(container, true);
                        prev = this._prevVerticalCell(container, current);
                        if (prev[0]) {
                            focusTable(container.parent(), true);
                        }
                    }
                }
                var tmp = this._lastCellIndex || 0;
                this.current(prev);
                this._lastCellIndex = tmp;
                return true;
            },
            _moveDown: function (current, shiftKey) {
                var container = current.parent().parent();
                var next;
                if (shiftKey) {
                    next = current.parent();
                    next = next.nextAll(ITEMROW + ':first');
                    next = current.parent().is(ITEMROW) ? next.children().eq(current.index()) : next.children(DATA_CELL + ':first');
                } else {
                    next = this._nextVerticalCell(container, current);
                    if (!next[0]) {
                        this._lastCellIndex = 0;
                        container = this._verticalContainer(container);
                        next = this._nextVerticalCell(container, current);
                        if (next[0]) {
                            focusTable(container.parent(), true);
                        }
                    }
                }
                var tmp = this._lastCellIndex || 0;
                this.current(next);
                this._lastCellIndex = tmp;
                return true;
            },
            _tableClick: function (e) {
                var currentTarget = $(e.currentTarget), isHeader = currentTarget.is('th'), table = this.table.add(this.lockedTable), headerTable = this.thead.parent().add($('>table', this.lockedHeader)), isInput = isInputElement(e.target), currentTable = currentTarget.closest('table')[0];
                if (kendo.support.touch) {
                    return;
                }
                if (currentTable !== table[0] && currentTable !== table[1] && currentTable !== headerTable[0] && currentTable !== headerTable[1]) {
                    return;
                }
                if (this.options.navigatable) {
                    this.current(currentTarget);
                }
                if (isHeader || !isInput) {
                    setTimeout(function () {
                        if (!isInputElement(kendo._activeElement()) || !$.contains(currentTable, kendo._activeElement())) {
                            focusTable(currentTable, true);
                        }
                    });
                }
                if (isHeader) {
                    e.preventDefault();
                }
            },
            _setTabIndex: function (table) {
                this._navigatableTables.attr(TABINDEX, -1);
                table.attr(TABINDEX, 0);
            },
            _tableFocus: function (e) {
                var current = this.current();
                var table = $(e.currentTarget);
                if (current && current.is(':visible')) {
                    current.addClass(classNames.focused);
                } else {
                    this.current(table.find(FIRSTNAVITEM));
                }
                this._setTabIndex(table);
            },
            _tableBlur: function () {
                var current = this.current();
                if (current) {
                    current.removeClass(classNames.focused);
                }
            },
            _attachEvents: function () {
                var icons = DOT + classNames.iconCollapse + ', .' + classNames.iconExpand + ', .' + classNames.refresh;
                var retryButton = DOT + classNames.retry;
                this.element.on(MOUSEDOWN + NS, icons, proxy(this._toggleChildren, this)).on(CLICK + NS, retryButton, this._dataSourceFetchProxy).on(CLICK + NS, '.k-button[data-command]', proxy(this._commandClick, this));
                this._attachCellEditingEventHandlers();
            },
            _attachCellEditingEventHandlers: function () {
                var that = this;
                var editable = that.options.editable;
                var selectable = that.selectable && that.selectable.options.multiple;
                var closeCell = function (e) {
                    var target = activeElement();
                    var editor = that.editor || {};
                    var cell = editor.element;
                    if (cell && !$.contains(cell[0], target) && cell[0] !== target && !$(target).closest('.k-animation-container').length) {
                        if (editor.end()) {
                            if (!e.relatedTarget && that._isPageable() && !isUndefined(that.dataSource._addChildPageSize)) {
                                that._preventPageSizeRestore = false;
                            }
                            that.closeCell();
                        }
                    }
                    that._preventPageSizeRestore = false;
                };
                if (that._isIncellEditable() && editable.update !== false) {
                    that.wrapper.on(CLICK + NS, 'tr:not(.k-grouping-row) > td', function (e) {
                        var td = $(this), isLockedCell = that.lockedTable && td.closest('table')[0] === that.lockedTable[0];
                        if (td.hasClass(classNames.editCell) || td.has('a.k-grid-delete').length || td.has('button.k-grid-delete').length || td.closest('tbody')[0] !== that.tbody[0] && !isLockedCell || $(e.target).is(':input') || $(e.target).hasClass(classNames.iconExpand) || $(e.target).hasClass(classNames.iconCollapse)) {
                            if (!that.editor) {
                                that.dataSource._restorePageSizeAfterAddChild();
                            }
                            that._preventPageSizeRestore = false;
                            return;
                        }
                        if (that.editor) {
                            if (that.editor.end()) {
                                if (selectable) {
                                    $(activeElement()).blur();
                                }
                                that.closeCell();
                                that.editCell(td);
                            }
                        } else {
                            that.editCell(td);
                        }
                    }).on('mousedown' + NS, 'tr:not(.k-grouping-row) > td', function (e) {
                        if (that.editor && that._isPageable() && !isUndefined(that.dataSource._addChildPageSize)) {
                            that._preventPageSizeRestore = $(e.target).parents(DOT + classNames.editRow).length > 0;
                        } else {
                            that._preventPageSizeRestore = false;
                        }
                    }).on('focusin' + NS, function () {
                        if (!$.contains(this, activeElement())) {
                            clearTimeout(that._closeCellTimeout);
                            that._closeCellTimeout = null;
                        }
                    }).on('focusout' + NS, function (e) {
                        that._closeCellTimeout = setTimeout(function () {
                            closeCell(e);
                        }, 1);
                    });
                }
            },
            _commandByName: function (name) {
                var columns = this.columns;
                var toolbar = $.isArray(this.options.toolbar) ? this.options.toolbar : [];
                var i, j, commands, currentName;
                name = name.toLowerCase();
                if (defaultCommands[name]) {
                    return defaultCommands[name];
                }
                for (i = 0; i < columns.length; i++) {
                    commands = columns[i].command;
                    if (commands) {
                        for (j = 0; j < commands.length; j++) {
                            currentName = commands[j].name;
                            if (!currentName) {
                                continue;
                            }
                            if (currentName.toLowerCase() == name) {
                                return commands[j];
                            }
                        }
                    }
                }
                for (i = 0; i < toolbar.length; i++) {
                    currentName = toolbar[i].name;
                    if (!currentName) {
                        continue;
                    }
                    if (currentName.toLowerCase() == name) {
                        return toolbar[i];
                    }
                }
            },
            _commandClick: function (e) {
                var button = $(e.currentTarget);
                var commandName = button.attr('data-command');
                var command = this._commandByName(commandName);
                var row = button.parentsUntil(this.wrapper, 'tr');
                row = row.length ? row : undefined;
                if (command) {
                    if (command.methodName) {
                        this[command.methodName](row);
                    } else if (command.click) {
                        command.click.call(this, e);
                    }
                    e.preventDefault();
                }
            },
            _ensureExpandableColumn: function () {
                if (this._autoExpandable) {
                    delete this._autoExpandable.expandable;
                }
                var visibleColumns = grep(this.columns, not(is('hidden')));
                visibleColumns = grep(visibleColumns, not(is('command')));
                var expandableColumns = grep(visibleColumns, is('expandable'));
                if (this.columns.length && !expandableColumns.length) {
                    this._autoExpandable = visibleColumns[0];
                    visibleColumns[0].expandable = true;
                }
            },
            _columns: function () {
                var columns = this.options.columns || [];
                this.columns = map(columns, function (column) {
                    column = typeof column === 'string' ? { field: column } : column;
                    return extend({ encoded: true }, column);
                });
                var lockedCols = lockedColumns(columns);
                if (lockedCols.length > 0) {
                    this._hasLockedColumns = true;
                    this.columns = lockedCols.concat(nonLockedColumns(this.columns));
                }
                this.columns = normalizeColumns(this.columns);
                this._ensureExpandableColumn();
                this._columnTemplates();
                this._columnAttributes();
            },
            _columnTemplates: function () {
                var idx, length, column;
                var columns = leafColumns(this.columns);
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    column = columns[idx];
                    if (column.template) {
                        column.template = kendo.template(column.template);
                    }
                    if (column.headerTemplate) {
                        column.headerTemplate = kendo.template(column.headerTemplate);
                    }
                    if (column.footerTemplate) {
                        column.footerTemplate = kendo.template(column.footerTemplate);
                    }
                }
            },
            _columnAttributes: function () {
                var idx, length;
                var columns = this.columns;
                function convertStyle(attr) {
                    var properties, i, declaration;
                    if (attr && attr.style) {
                        properties = attr.style.split(';');
                        attr.style = {};
                        for (i = 0; i < properties.length; i++) {
                            declaration = properties[i].split(':');
                            var name = $.trim(declaration[0]);
                            if (name) {
                                attr.style[$.camelCase(name)] = $.trim(declaration[1]);
                            }
                        }
                    }
                }
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    convertStyle(columns[idx].attributes);
                    convertStyle(columns[idx].headerAttributes);
                }
            },
            _layout: function () {
                var columns = this.columns;
                var element = this.element;
                var layout = '';
                this.wrapper = element.addClass(classNames.wrapper);
                layout = '<div class=\'#= gridHeader #\'>';
                if (this._hasLockedColumns) {
                    layout += '<div class=\'k-grid-header-locked\'>' + '<table role=\'grid\'>' + '<colgroup></colgroup>' + '<thead role=\'rowgroup\' />' + '</table>' + '</div>';
                }
                layout += '<div class=\'#= gridHeaderWrap #\'>' + '<table role=\'grid\'>' + '<colgroup></colgroup>' + '<thead role=\'rowgroup\' />' + '</table>' + '</div>' + '</div>';
                if (this._hasLockedColumns) {
                    layout += '<div class=\'k-grid-content-locked\'>' + '<table role=\'treegrid\' tabindex=\'0\'>' + '<colgroup></colgroup>' + '<tbody />' + '</table>' + '</div>';
                }
                layout += '<div class=\'#= gridContentWrap # k-auto-scrollable\'>' + '<table role=\'treegrid\' tabindex=\'0\'>' + '<colgroup></colgroup>' + '<tbody />' + '</table>' + '</div>';
                if (!this.options.scrollable) {
                    layout = '<table role=\'treegrid\' tabindex=\'0\'>' + '<colgroup></colgroup>' + '<thead class=\'#= gridHeader #\' role=\'rowgroup\' />' + '<tbody />' + '</table>';
                }
                if (this.options.toolbar) {
                    layout = '<div class=\'#= header # #= gridToolbar #\' />' + layout;
                }
                element.append(kendo.template(layout)(classNames) + '<div class=\'k-status\' />');
                this.toolbar = element.find(DOT + classNames.gridToolbar);
                var header = element.find(DOT + classNames.gridHeader).find('thead').addBack().filter('thead');
                this.thead = header.last();
                if (this.options.scrollable) {
                    var rtl = kendo.support.isRtl(element);
                    element.find('div.' + classNames.gridHeader).css(rtl ? 'padding-left' : 'padding-right', kendo.support.scrollbar());
                }
                var content = element.find(DOT + classNames.gridContentWrap);
                if (!content.length) {
                    content = element;
                } else {
                    this.content = content;
                }
                this.table = content.find('>table');
                this.tbody = this.table.find('>tbody');
                if (this._hasLockedColumns) {
                    this.lockedHeader = header.first().closest('.k-grid-header-locked');
                    this.lockedContent = element.find('.k-grid-content-locked');
                    this.lockedTable = this.lockedContent.children();
                }
                this._initVirtualTrees();
                this._renderCols();
                this._renderHeader();
                this.angular('compile', function () {
                    return {
                        elements: header.find('th.k-header').get(),
                        data: map(columns, function (col) {
                            return { column: col };
                        })
                    };
                });
            },
            _initVirtualTrees: function () {
                this._headerColsTree = new kendoDom.Tree(this.thead.prev()[0]);
                this._contentColsTree = new kendoDom.Tree(this.tbody.prev()[0]);
                this._headerTree = new kendoDom.Tree(this.thead[0]);
                this._contentTree = new kendoDom.Tree(this.tbody[0]);
                this._statusTree = new kendoDom.Tree(this.element.children('.k-status')[0]);
                if (this.lockedHeader) {
                    this._lockedHeaderColsTree = new kendoDom.Tree(this.lockedHeader.find('colgroup')[0]);
                    this._lockedContentColsTree = new kendoDom.Tree(this.lockedTable.find('>colgroup')[0]);
                    this._lockedHeaderTree = new kendoDom.Tree(this.lockedHeader.find('thead')[0]);
                    this._lockedContentTree = new kendoDom.Tree(this.lockedTable.find('>tbody')[0]);
                }
            },
            _toolbar: function () {
                var options = this.options.toolbar;
                var toolbar = this.toolbar;
                if (!options) {
                    return;
                }
                if ($.isArray(options)) {
                    var buttons = this._buildCommands(options);
                    new kendoDom.Tree(toolbar[0]).render(buttons);
                } else {
                    toolbar.append(kendo.template(options)({}));
                }
                this.angular('compile', function () {
                    return { elements: toolbar.get() };
                });
            },
            _lockedColumns: function () {
                return grep(this.columns, is('locked'));
            },
            _nonLockedColumns: function () {
                return grep(this.columns, not(is('locked')));
            },
            _templateColumns: function () {
                return grep(this.columns, is('template'));
            },
            _flushCache: function () {
                if (this.options.$angular && this._templateColumns().length) {
                    this._contentTree.render([]);
                    if (this._hasLockedColumns) {
                        this._lockedContentTree.render([]);
                    }
                }
            },
            _render: function (options) {
                var that = this;
                options = options || {};
                options = that._renderOptions(options);
                var messages = this.options.messages;
                var pageable = that._isPageable();
                var dataSource = that.dataSource;
                var maps = {
                    children: options.filteredChildrenMap || options.childrenMap,
                    ids: options.idsMap
                };
                var dataMaps = pageable ? maps && maps.children && maps.ids ? maps : dataSource._initDataMaps(dataSource._getData()) : {};
                var childrenMap = dataMaps.children;
                var idsMap = dataMaps.ids;
                options.childrenMap = childrenMap;
                options.idsMap = idsMap;
                var data = that._dataToRender(options);
                var level = that._renderedModelLevel(data[0], options);
                var uidAttr = kendo.attr('uid');
                var selected = this.select().removeClass('k-state-selected').map(function (_, row) {
                    return $(row).attr(uidAttr);
                });
                var viewChildrenMap;
                this._absoluteIndex = 0;
                this._angularItems('cleanup');
                this._angularFooters('cleanup');
                this._flushCache();
                that._clearRenderMap();
                if (options.error) {
                    this._showStatus(kendo.template('#: messages.requestFailed # ' + '<button class=\'#= buttonClass #\'>#: messages.retry #</button>')({
                        buttonClass: [
                            classNames.button,
                            classNames.retry
                        ].join(' '),
                        messages: messages
                    }));
                } else if (!data.length) {
                    this._hideStatus();
                    this._showNoRecordsTemplate();
                } else {
                    if (pageable) {
                        viewChildrenMap = that._viewChildrenMap(options);
                    }
                    this._hideStatus();
                    this._contentTree.render(this._trs({
                        columns: leafColumns(nonLockedColumns(this.columns)),
                        editedColumn: options.editedColumn,
                        editedColumnIndex: options.editedColumnIndex,
                        aggregates: options.aggregates,
                        selected: selected,
                        data: data,
                        childrenMap: childrenMap,
                        viewChildrenMap: viewChildrenMap,
                        visible: true,
                        level: 0
                    }));
                    if (this._hasLockedColumns) {
                        this._absoluteIndex = 0;
                        this._lockedContentTree.render(this._trs({
                            columns: leafColumns(lockedColumns(this.columns)),
                            editedColumn: options.editedColumn,
                            editedColumnIndex: options.editedColumnIndex,
                            aggregates: options.aggregates,
                            selected: selected,
                            data: data,
                            childrenMap: childrenMap,
                            viewChildrenMap: viewChildrenMap,
                            visible: true,
                            level: level
                        }));
                    }
                }
                if (this._touchScroller) {
                    this._touchScroller.contentResized();
                }
                this._muteAngularRebind(function () {
                    this._angularItems('compile');
                    this._angularFooters('compile');
                });
                this.items().filter(function () {
                    return $.inArray($(this).attr(uidAttr), selected) >= 0;
                }).addClass('k-state-selected');
                this._syncLockedContentHeight();
                that._togglePagerVisibility();
            },
            _renderProgress: function (toggle) {
                kendo.ui.progress(this.wrapper, toggle);
            },
            _renderOptions: function (options) {
                options = options || {};
                var that = this;
                var dataMaps = that.dataSource._getDataMaps();
                var filter = that.dataSource.filter();
                if (that._isPageable()) {
                    options.childrenMap = dataMaps.children;
                    options.idsMap = dataMaps.ids;
                    if (filter) {
                        options.filteredChildrenMap = dataMaps.filteredChildren;
                    }
                }
                return options;
            },
            _renderedModelLevel: function (model, options) {
                return !this._isPageable() ? 0 : this.dataSource._pageableModelLevel(model, options);
            },
            _viewChildrenMap: function (options) {
                options = options || {};
                var that = this;
                var dataSource = that.dataSource;
                var viewChildrenMap = dataSource.childrenMap(dataSource.view());
                var idField = dataSource._modelIdField();
                var parentsNotInView = dataSource._parentNodesNotInView();
                var parentNotInView;
                var parentNotInViewId;
                var parents;
                var parent;
                var parentId;
                var child;
                var childId;
                var parentsCopy;
                that._clearRenderMap();
                for (var i = 0; i < parentsNotInView.length; i++) {
                    parentNotInView = parentsNotInView[i];
                    parentNotInViewId = parentNotInView[idField];
                    that._markNodeAsNonRenderable(parentNotInViewId);
                    viewChildrenMap[parentNotInViewId] = viewChildrenMap[parentNotInViewId] || [];
                    parents = dataSource._parentNodes(parentNotInView);
                    parentsCopy = parents.slice();
                    parentsCopy.push(parentNotInView);
                    for (var parentIndex = 0; parentIndex < parentsCopy.length - 1; parentIndex++) {
                        parent = parentsCopy[parentIndex];
                        parentId = parent[idField];
                        that._markNodeAsNonRenderable(parentId);
                        viewChildrenMap[parentId] = viewChildrenMap[parentId] || [];
                        child = parentsCopy[parentIndex + 1];
                        childId = child[idField];
                        that._markNodeAsNonRenderable(childId);
                        viewChildrenMap[childId] = viewChildrenMap[childId] || [];
                        if (viewChildrenMap[parentId].indexOf(child) === -1) {
                            viewChildrenMap[parentId].unshift(child);
                        }
                    }
                }
                return viewChildrenMap;
            },
            _clearRenderMap: function () {
                this._skipRenderingMap = {};
            },
            _dataToRender: function (options) {
                var that = this;
                if (that._isPageable()) {
                    return that.dataSource._pageableRootNodes(options);
                }
                return that.dataSource.rootNodes();
            },
            _markNodeAsNonRenderable: function (nodeId) {
                this._skipRenderingMap[nodeId] = true;
            },
            _adjustRowsHeight: function (table1, table2) {
                if (!this._hasLockedColumns) {
                    return;
                }
                var rows = table1[0].rows;
                var length = rows.length;
                var idx;
                var rows2 = table2[0].rows;
                var containers = table1.add(table2);
                var containersLength = containers.length;
                var heights = [];
                for (idx = 0; idx < length; idx++) {
                    if (!rows2[idx]) {
                        break;
                    }
                    if (rows[idx].style.height) {
                        rows[idx].style.height = rows2[idx].style.height = '';
                    }
                }
                for (idx = 0; idx < length; idx++) {
                    if (!rows2[idx]) {
                        break;
                    }
                    var offsetHeight1 = rows[idx].offsetHeight;
                    var offsetHeight2 = rows2[idx].offsetHeight;
                    var height = 0;
                    if (offsetHeight1 > offsetHeight2) {
                        height = offsetHeight1;
                    } else if (offsetHeight1 < offsetHeight2) {
                        height = offsetHeight2;
                    }
                    heights.push(height);
                }
                for (idx = 0; idx < containersLength; idx++) {
                    containers[idx].style.display = 'none';
                }
                for (idx = 0; idx < length; idx++) {
                    if (heights[idx]) {
                        rows[idx].style.height = rows2[idx].style.height = heights[idx] + 1 + 'px';
                    }
                }
                for (idx = 0; idx < containersLength; idx++) {
                    containers[idx].style.display = '';
                }
            },
            _ths: function (columns, rowSpan) {
                var ths = [];
                var column, title, children, cellClasses, attr, headerContent;
                for (var i = 0, length = columns.length; i < length; i++) {
                    column = columns[i];
                    children = [];
                    cellClasses = [classNames.header];
                    if (column.headerTemplate) {
                        title = column.headerTemplate({});
                    } else {
                        title = column.title || column.field || '';
                    }
                    if (column.headerTemplate) {
                        headerContent = kendoHtmlElement(title);
                    } else {
                        headerContent = kendoTextElement(title);
                    }
                    if (column.sortable) {
                        children.push(kendoDomElement('a', {
                            href: '#',
                            className: classNames.link
                        }, [headerContent]));
                    } else {
                        children.push(headerContent);
                    }
                    attr = {
                        'data-field': column.field,
                        'data-title': column.title,
                        'style': column.hidden === true ? { 'display': 'none' } : {},
                        className: cellClasses.join(' '),
                        'role': 'columnheader'
                    };
                    if (!column.columns) {
                        attr.rowSpan = rowSpan ? rowSpan : 1;
                    }
                    if (column.headerAttributes) {
                        if (column.headerAttributes.colSpan === 1) {
                            delete column.headerAttributes.colSpan;
                        }
                        if (column.headerAttributes['class']) {
                            attr.className += ' ' + column.headerAttributes['class'];
                            delete column.headerAttributes['class'];
                        }
                    }
                    if (column['data-index'] > -1) {
                        attr['data-index'] = column['data-index'];
                    }
                    attr = extend(true, {}, attr, column.headerAttributes);
                    ths.push(kendoDomElement('th', attr, children));
                }
                return ths;
            },
            _cols: function (columns) {
                var cols = [];
                var width, attr;
                for (var i = 0; i < columns.length; i++) {
                    if (columns[i].hidden === true) {
                        continue;
                    }
                    width = columns[i].width;
                    attr = {};
                    if (width && parseInt(width, 10) !== 0) {
                        attr.style = { width: typeof width === 'string' ? width : width + 'px' };
                    }
                    cols.push(kendoDomElement('col', attr));
                }
                return cols;
            },
            _clearColsCache: function () {
                this._headerColsTree.render([]);
                if (this.options.scrollable) {
                    this._contentColsTree.render([]);
                }
                if (this._hasLockedColumns) {
                    this._lockedHeaderColsTree.render([]);
                    this._lockedContentColsTree.render([]);
                }
            },
            _renderCols: function () {
                var columns = nonLockedColumns(this.columns);
                this._headerColsTree.render(this._cols(leafColumns(columns)));
                if (this.options.scrollable) {
                    this._contentColsTree.render(this._cols(leafColumns(columns)));
                }
                if (this._hasLockedColumns) {
                    columns = lockedColumns(this.columns);
                    this._lockedHeaderColsTree.render(this._cols(leafColumns(columns)));
                    this._lockedContentColsTree.render(this._cols(leafColumns(columns)));
                }
            },
            _retrieveFirstColumn: function (columns, rows) {
                var result = $();
                if (rows.length && columns[0]) {
                    var column = columns[0];
                    while (column.columns && column.columns.length) {
                        column = column.columns[0];
                        rows = rows.filter(':not(:first())');
                    }
                    result = result.add(rows);
                }
                return result;
            },
            _updateFirstColumnClass: function () {
                var that = this;
                var columns = that.columns || [];
                var tr = that.thead.find('>tr:not(:first)');
                var rows;
                columns = nonLockedColumns(columns);
                rows = that._retrieveFirstColumn(columns, tr);
                if (that.lockedHeader) {
                    tr = that.lockedHeader.find('thead>tr:not(.k-filter-row):not(:first)');
                    columns = lockedColumns(that.columns);
                    rows = rows.add(that._retrieveFirstColumn(columns, tr));
                }
                rows.each(function () {
                    var ths = $(this).find('th');
                    ths.removeClass('k-first');
                    ths.eq(0).addClass('k-first');
                });
            },
            _updateRowSpans: function (rows) {
                for (var i = rows.length - 1; i >= 0; i--) {
                    var included = visibleChildColumns(rows[i].cells).length > 0;
                    if (included) {
                        rows[i].rowSpan = rows.length - i;
                    }
                }
            },
            _setColumnDataIndexes: function (columns) {
                for (var i = 0; i < columns.length; i++) {
                    columns[i]['data-index'] = i;
                }
            },
            _updateColumnCellIndex: function () {
                var header;
                var offset = 0;
                if (this.lockedHeader) {
                    header = this.lockedHeader.find('thead');
                    offset = updateCellIndex(header, lockedColumns(this.columns));
                }
                updateCellIndex(this.thead, nonLockedColumns(this.columns), offset);
            },
            _setParentsVisibility: function (column, visible) {
                var columns = this.columns;
                var idx;
                var parents = [];
                var parent;
                var predicate = visible ? function (p) {
                    return visibleColumns(p.columns).length && p.hidden;
                } : function (p) {
                    return !visibleColumns(p.columns).length && !p.hidden;
                };
                if (columnParents(column, columns, parents) && parents.length) {
                    for (idx = parents.length - 1; idx >= 0; idx--) {
                        parent = parents[idx];
                        if (predicate(parent)) {
                            parent.hidden = !visible;
                        }
                    }
                }
            },
            _prepareColumns: function (rows, columns, parentCell, parentRow, parentColumn) {
                var row = parentRow || rows[rows.length - 1];
                var childRow = rows[row.index + 1];
                var totalColSpan = 0;
                for (var idx = 0; idx < columns.length; idx++) {
                    var cell = $.extend({}, columns[idx], { headerAttributes: columns[idx].headerAttributes || {} });
                    row.cells.push(cell);
                    if (columns[idx].columns && columns[idx].columns.length) {
                        if (!childRow) {
                            childRow = {
                                rowSpan: 0,
                                cells: [],
                                index: rows.length
                            };
                            rows.push(childRow);
                        }
                        if (columns[idx].columns.length) {
                            cell.headerAttributes.colSpan = visibleChildColumns(columns[idx].columns).length || 1;
                            cell.headerAttributes['data-colspan'] = leafColumns(columns[idx].columns).length;
                        }
                        this._prepareColumns(rows, columns[idx].columns, cell, childRow, columns[idx]);
                        if (!cell.hidden) {
                            totalColSpan += cell.headerAttributes.colSpan - 1;
                        }
                        row.rowSpan = rows.length - row.index;
                    }
                    columns[idx].rowIndex = row.index;
                    if (parentColumn) {
                        columns[idx].parentColumn = parentColumn;
                    }
                    columns[idx].cellIndex = row.cells.length - 1;
                }
                if (parentCell) {
                    parentCell.headerAttributes.colSpan += totalColSpan;
                }
            },
            _renderHeaderTree: function (tree, columns, hasMultiColumnHeaders) {
                var idx;
                var rows = [];
                var rowsToRender = [];
                if (hasMultiColumnHeaders) {
                    rows = [{
                            rowSpan: 1,
                            cells: [],
                            index: 0
                        }];
                    this._prepareColumns(rows, columns);
                    this._updateRowSpans(rows);
                    for (idx = 0; idx < rows.length; idx++) {
                        rowsToRender.push(kendoDomElement('tr', { 'role': 'row' }, this._ths(rows[idx].cells, rows[idx].rowSpan)));
                    }
                    tree.render(rowsToRender);
                } else {
                    tree.render([kendoDomElement('tr', { 'role': 'row' }, this._ths(columns))]);
                }
            },
            _renderHeader: function () {
                var columns = nonLockedColumns(this.columns);
                var hasMultiColumnHeaders = grep(this.columns, function (item) {
                    return item.columns !== undefined;
                }).length > 0;
                this._setColumnDataIndexes(leafColumns(this.columns));
                this._renderHeaderTree(this._headerTree, columns, hasMultiColumnHeaders);
                if (this._hasLockedColumns) {
                    columns = lockedColumns(this.columns);
                    this._renderHeaderTree(this._lockedHeaderTree, columns, hasMultiColumnHeaders);
                    this._applyLockedContainersWidth();
                    this._syncLockedHeaderHeight();
                }
                this._updateFirstColumnClass();
            },
            _applyLockedContainersWidth: function () {
                if (!this._hasLockedColumns) {
                    return;
                }
                var lockedWidth = columnsWidth(this.lockedHeader.find('>table>colgroup>col'));
                var headerTable = this.thead.parent();
                var nonLockedWidth = columnsWidth(headerTable.find('>colgroup>col'));
                var wrapperWidth = this.wrapper[0].clientWidth;
                var scrollbar = kendo.support.scrollbar();
                if (lockedWidth >= wrapperWidth) {
                    lockedWidth = wrapperWidth - 3 * scrollbar;
                }
                this.lockedHeader.add(this.lockedContent).width(lockedWidth);
                headerTable.add(this.table).width(nonLockedWidth);
                var width = wrapperWidth - lockedWidth - 2;
                this.content.width(width);
                headerTable.parent().width(width - scrollbar);
            },
            _trs: function (options) {
                var that = this;
                var model, attr, className, hasChildren, childNodes, i, length;
                var modelId;
                var rows = [];
                var level = options.level;
                var data = options.data;
                var dataSource = this.dataSource;
                var aggregates = dataSource.aggregates() || {};
                var idField = dataSource._modelIdField();
                var parentIdField = dataSource._modelParentIdField();
                var columns = options.columns;
                var pageable = that._isPageable();
                var childrenMap = options.childrenMap || dataSource.childrenMap(dataSource._getData());
                for (i = 0, length = data.length; i < length; i++) {
                    className = [];
                    model = data[i];
                    modelId = model[idField];
                    childNodes = pageable ? childrenMap[modelId] : model.loaded() ? dataSource.childNodes(model) : [];
                    hasChildren = childNodes && childNodes.length;
                    attr = { 'role': 'row' };
                    attr[kendo.attr('uid')] = model.uid;
                    if (hasChildren) {
                        attr['aria-expanded'] = !!model.expanded;
                    }
                    if (options.visible) {
                        if (!pageable || pageable && !that._skipRenderingMap[modelId]) {
                            if (this._absoluteIndex % 2 !== 0) {
                                className.push(classNames.alt);
                            }
                            this._absoluteIndex++;
                        }
                    } else {
                        attr.style = { display: 'none' };
                    }
                    if ($.inArray(model.uid, options.selected) >= 0) {
                        className.push(classNames.selected);
                    }
                    if (hasChildren) {
                        className.push(classNames.group);
                    }
                    if (model._edit) {
                        className.push('k-grid-edit-row');
                    }
                    attr.className = className.join(' ');
                    if (!that._skipRenderingMap[modelId]) {
                        var row = this._tds({
                            model: model,
                            attr: attr,
                            level: pageable ? that._renderedModelLevel(model, options) : level,
                            editedColumn: options.editedColumn,
                            editedColumnIndex: options.editedColumnIndex
                        }, columns, proxy(this._td, this));
                        rows.push(row);
                    }
                    if (hasChildren) {
                        if (pageable) {
                            childNodes = (options.viewChildrenMap || {})[modelId] || [];
                        }
                        if (childNodes.length === 0) {
                            continue;
                        }
                        rows = rows.concat(this._trs({
                            columns: columns,
                            editedColumn: options.editedColumn,
                            editedColumnIndex: options.editedColumnIndex,
                            aggregates: aggregates,
                            selected: options.selected,
                            visible: pageable ? options.visible : options.visible && !!model.expanded,
                            data: childNodes,
                            childrenMap: options.childrenMap || childrenMap,
                            viewChildrenMap: options.viewChildrenMap,
                            level: level + 1
                        }));
                    }
                }
                if (this._hasFooterTemplate() && model) {
                    attr = {
                        className: classNames.footerTemplate,
                        'data-parentId': model[parentIdField]
                    };
                    if (!options.visible) {
                        attr.style = { display: 'none' };
                    }
                    rows.push(this._tds({
                        model: aggregates[model[parentIdField]],
                        attr: attr,
                        level: level,
                        editedColumn: options.editedColumn,
                        editedColumnIndex: options.editedColumnIndex
                    }, columns, this._footerId));
                }
                return rows;
            },
            _footerId: function (options) {
                var content = [];
                var column = options.column;
                var template = options.column.footerTemplate || $.noop;
                var aggregates = options.model[column.field] || {};
                var attr = {
                    'role': 'gridcell',
                    'style': column.hidden === true ? { 'display': 'none' } : {}
                };
                if (column.expandable) {
                    content = content.concat(createPlaceholders({
                        level: options.level + 1,
                        className: classNames.iconPlaceHolder
                    }));
                }
                if (column.attributes) {
                    extend(true, attr, column.attributes, { 'style': column.hidden === true ? { 'display': 'none' } : {} });
                }
                content.push(kendoHtmlElement(template(aggregates) || ''));
                return kendoDomElement('td', attr, content);
            },
            _hasFooterTemplate: function () {
                return !!grep(this.columns, function (c) {
                    return c.footerTemplate;
                }).length;
            },
            _tds: function (options, columns, renderer) {
                var children = [];
                var column;
                var editedColumnField = (options.editedColumn || {}).field;
                var incellEditing = this._isIncellEditable();
                var length = columns.length;
                for (var i = 0; i < length; i++) {
                    column = columns[i];
                    var col = renderer({
                        model: options.model,
                        column: column,
                        editColumn: !incellEditing || incellEditing && column.field === editedColumnField && options.editedColumnIndex === i,
                        level: options.level
                    });
                    children.push(col);
                }
                return kendoDomElement('tr', options.attr, children);
            },
            _td: function (options) {
                var children = [];
                var model = options.model;
                var column = options.column;
                var iconClass;
                var attr = {
                    'role': 'gridcell',
                    'style': column.hidden === true ? { 'display': 'none' } : {}
                };
                var incellEditing = this._isIncellEditable();
                var columnHasEditCommand = false;
                if (column.attributes) {
                    extend(true, attr, column.attributes);
                }
                if (model._edit && column.field && options.editColumn && (incellEditing || !incellEditing && isColumnEditable(column, model))) {
                    attr[kendo.attr('container-for')] = column.field;
                    if (incellEditing) {
                        if (attr.className && attr.className.indexOf(classNames.editCell) !== -1) {
                            attr.className += ' ' + classNames.editCell;
                        } else if (!attr.className) {
                            attr.className = classNames.editCell;
                        }
                    }
                } else {
                    if (column.expandable) {
                        children = createPlaceholders({
                            level: options.level,
                            className: classNames.iconPlaceHolder
                        });
                        iconClass = [classNames.icon];
                        if (model.hasChildren) {
                            iconClass.push(model.expanded ? classNames.iconCollapse : classNames.iconExpand);
                        } else {
                            iconClass.push(classNames.iconHidden);
                        }
                        if (model._error) {
                            iconClass.push(classNames.refresh);
                        } else if (!model.loaded() && model.expanded) {
                            iconClass.push(classNames.loading);
                        }
                        children.push(kendoDomElement('span', { className: iconClass.join(' ') }));
                        attr.style['white-space'] = 'nowrap';
                    }
                    if (isDirtyColumn(column, model)) {
                        if (attr.className) {
                            attr.className += classNames.dirtyCell;
                        } else if (!attr.className) {
                            attr.className = classNames.dirtyCell;
                        }
                    }
                    if (column.command) {
                        if (attr.className && attr.className.indexOf('k-command-cell') !== -1) {
                            attr.className += ' k-command-cell';
                        } else if (!attr.className) {
                            attr.className = 'k-command-cell';
                        }
                        columnHasEditCommand = grep(column.command, function (command) {
                            return command === EDIT || command.name === EDIT;
                        }).length > 0;
                        if (model._edit && !this._isIncellEditable() && columnHasEditCommand) {
                            children = this._buildCommands([
                                'update',
                                'canceledit'
                            ]);
                        } else {
                            children = this._buildCommands(column.command);
                        }
                    } else {
                        children.push(this._cellContent(column, model));
                    }
                    if (attr['class']) {
                        attr.className = attr['class'] + ' ' + attr.className;
                    }
                }
                return kendoDomElement('td', attr, children);
            },
            _cellContent: function (column, model) {
                var that = this;
                var value;
                var incellEditing = that._isIncellEditable();
                var dirtyIndicator = incellEditing ? that._evalDirtyIndicatorTemplate(column, model) : '';
                if (column.template) {
                    value = that._evalColumnTemplate(column, model);
                } else if (column.field) {
                    value = model.get(column.field);
                    if (value !== null && !isUndefined(value)) {
                        if (column.format) {
                            value = kendo.format(column.format, value);
                        }
                        value = dirtyIndicator + value;
                    } else {
                        value = dirtyIndicator;
                    }
                } else if (value === null || isUndefined(value)) {
                    value = '';
                }
                if (column.template || !column.encoded) {
                    return kendoHtmlElement(value);
                } else {
                    if (incellEditing) {
                        return kendoHtmlElement(value);
                    } else {
                        return kendoTextElement(value);
                    }
                }
            },
            _evalColumnTemplate: function (column, model) {
                if (this._isIncellEditable()) {
                    return this._evalCustomColumnTemplate(column, model);
                } else {
                    return column.template(model);
                }
            },
            _evalCustomColumnTemplate: function (column, model) {
                var that = this;
                var templateSettings = that._customTemplateSettings();
                var columnTemplateAlias = '#=this.columnTemplate(' + templateSettings.paramName + ')#';
                var templateString = that._dirtyIndicatorTemplate(column.field) + columnTemplateAlias;
                var templateFunction = proxy(kendoTemplate(templateString, templateSettings), { columnTemplate: column.template });
                return templateFunction(model);
            },
            _evalDirtyIndicatorTemplate: function (column, model) {
                var dirtyIndicatorTemplate = this._dirtyIndicatorTemplate(column.field);
                return kendoTemplate(dirtyIndicatorTemplate)(model);
            },
            _dirtyIndicatorTemplate: function (field) {
                var that = this;
                var dirtyField;
                var templateSettings = that._customTemplateSettings();
                var paramName = templateSettings.paramName;
                if (field && paramName) {
                    dirtyField = field.charAt(0) === '[' ? kendo.expr(field, paramName + '.dirtyFields') : paramName + '.dirtyFields[\'' + field + '\']';
                    return '#= ' + paramName + ' && ' + paramName + '.dirty && ' + paramName + '.dirtyFields && ' + dirtyField + ' ? \'<span class="k-dirty"></span>\' : \'\' #';
                }
                return '';
            },
            _customTemplateSettings: function () {
                return extend({}, kendo.Template, this.options.templateSettings);
            },
            _buildCommands: function (commands) {
                var i, result = [];
                for (i = 0; i < commands.length; i++) {
                    result.push(this._button(commands[i]));
                }
                return result;
            },
            _button: function (command) {
                var name = (command.name || command).toLowerCase();
                var text = this.options.messages.commands[name];
                var icon = [];
                command = extend({}, defaultCommands[name], { text: text }, command);
                if (command.imageClass) {
                    icon.push(kendoDomElement('span', {
                        className: [
                            'k-icon',
                            command.imageClass
                        ].join(' ')
                    }));
                }
                return kendoDomElement('button', {
                    'type': 'button',
                    'data-command': name,
                    className: [
                        'k-button',
                        'k-button-icontext',
                        command.className
                    ].join(' ')
                }, icon.concat([kendoTextElement(command.text || command.name)]));
            },
            _positionResizeHandle: function (e) {
                var th = $(e.currentTarget);
                var resizeHandle = this.resizeHandle;
                var position = th.position();
                var left;
                var cellWidth = outerWidth(th);
                var container = th.closest('div');
                var button = typeof e.buttons !== 'undefined' ? e.buttons : e.which || e.button;
                var indicatorWidth = this.options.columnResizeHandleWidth || 3;
                left = cellWidth;
                if (typeof button !== 'undefined' && button !== 0) {
                    return;
                }
                if (!resizeHandle) {
                    resizeHandle = this.resizeHandle = $('<div class="k-resize-handle"><div class="k-resize-handle-inner" /></div>');
                }
                var cells = leafDataCells(th.closest('thead')).filter(':visible');
                if (isRtl) {
                    left = th.position().left;
                } else {
                    for (var idx = 0; idx < cells.length; idx++) {
                        if (cells[idx] == th[0]) {
                            break;
                        }
                        left += cells[idx].offsetWidth;
                    }
                }
                container.append(resizeHandle);
                resizeHandle.show().css({
                    top: position.top,
                    left: left - indicatorWidth * 3 / 2,
                    height: outerHeight(th),
                    width: indicatorWidth * 3
                }).data('th', th);
                var that = this;
                resizeHandle.off('dblclick' + NS).on('dblclick' + NS, function () {
                    var index = th.index();
                    if ($.contains(that.thead[0], th[0])) {
                        index += grep(that.columns, function (val) {
                            return val.locked && !val.hidden;
                        }).length;
                    }
                    that.autoFitColumn(index);
                });
            },
            autoFitColumn: function (column) {
                var that = this, options = that.options, columns = that.columns, index, browser = kendo.support.browser, th, headerTable, isLocked, visibleLocked = that.lockedHeader ? leafDataCells(that.lockedHeader.find('>table>thead')).filter(isCellVisible).length : 0, col;
                if (typeof column == 'number') {
                    column = columns[column];
                } else if (isPlainObject(column)) {
                    column = grep(columns, function (item) {
                        return item === column;
                    })[0];
                } else {
                    column = grep(columns, function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || column.hidden) {
                    return;
                }
                index = inArray(column, columns);
                isLocked = column.locked;
                if (isLocked) {
                    headerTable = that.lockedHeader.children('table');
                } else {
                    headerTable = that.thead.parent();
                }
                th = headerTable.find('[data-index=\'' + index + '\']');
                var contentTable = isLocked ? that.lockedTable : that.table, footer = that.footer || $();
                if (that.footer && that.lockedContent) {
                    footer = isLocked ? that.footer.children('.k-grid-footer-locked') : that.footer.children('.k-grid-footer-wrap');
                }
                var footerTable = footer.find('table').first();
                if (that.lockedHeader && visibleLocked >= index && !isLocked) {
                    index -= visibleLocked;
                }
                for (var j = 0; j < columns.length; j++) {
                    if (columns[j] === column) {
                        break;
                    } else {
                        if (columns[j].hidden) {
                            index--;
                        }
                    }
                }
                if (options.scrollable) {
                    col = headerTable.find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')').add(contentTable.children('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')')).add(footerTable.find('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')'));
                } else {
                    col = contentTable.children('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')');
                }
                var tables = headerTable.add(contentTable).add(footerTable);
                var oldColumnWidth = outerWidth(th);
                col.width('');
                tables.css('table-layout', 'fixed');
                col.width('auto');
                tables.addClass('k-autofitting');
                tables.css('table-layout', '');
                var newColumnWidth = Math.ceil(Math.max(outerWidth(th), outerWidth(contentTable.find('tr').eq(0).children('td:visible').eq(index)), outerWidth(footerTable.find('tr').eq(0).children('td:visible').eq(index))));
                col.width(newColumnWidth);
                column.width = newColumnWidth;
                if (options.scrollable) {
                    var cols = headerTable.find('col'), colWidth, totalWidth = 0;
                    for (var idx = 0, length = cols.length; idx < length; idx += 1) {
                        colWidth = cols[idx].style.width;
                        if (colWidth && colWidth.indexOf('%') == -1) {
                            totalWidth += parseInt(colWidth, 10);
                        } else {
                            totalWidth = 0;
                            break;
                        }
                    }
                    if (totalWidth) {
                        tables.each(function () {
                            this.style.width = totalWidth + 'px';
                        });
                    }
                }
                if (browser.msie && browser.version == 8) {
                    tables.css('display', 'inline-table');
                    setTimeout(function () {
                        tables.css('display', 'table');
                    }, 1);
                }
                tables.removeClass('k-autofitting');
                that.trigger(COLUMNRESIZE, {
                    column: column,
                    oldWidth: oldColumnWidth,
                    newWidth: newColumnWidth
                });
                that._applyLockedContainersWidth();
                that._syncLockedContentHeight();
                that._syncLockedHeaderHeight();
            },
            _adjustLockedHorizontalScrollBar: function () {
                var table = this.table, content = table.parent();
                var scrollbar = table[0].offsetWidth > content[0].clientWidth ? kendo.support.scrollbar() : 0;
                this.lockedContent.height(content.height() - scrollbar);
            },
            _syncLockedContentHeight: function () {
                if (this.lockedTable) {
                    if (!this._touchScroller) {
                        this._adjustLockedHorizontalScrollBar();
                    }
                    this._adjustRowsHeight(this.table, this.lockedTable);
                }
            },
            _syncLockedHeaderHeight: function () {
                if (this.lockedHeader) {
                    var lockedTable = this.lockedHeader.children('table');
                    var table = this.thead.parent();
                    this._adjustRowsHeight(lockedTable, table);
                    syncTableHeight(lockedTable, table);
                }
            },
            _resizable: function () {
                if (!this.options.resizable) {
                    return;
                }
                if (this.resizable) {
                    this.resizable.destroy();
                }
                var treelist = this;
                $(this.lockedHeader).find('thead').add(this.thead).on('mousemove' + NS, 'th', $.proxy(this._positionResizeHandle, this));
                this.resizable = new kendo.ui.Resizable(this.wrapper, {
                    handle: '.k-resize-handle',
                    start: function (e) {
                        var th = $(e.currentTarget).data('th');
                        var index = $.inArray(th[0], leafDataCells(th.closest('thead')).filter(':visible'));
                        var colSelector = 'col:eq(' + index + ')';
                        var header, contentTable;
                        treelist.wrapper.addClass('k-grid-column-resizing');
                        if (treelist.lockedHeader && $.contains(treelist.lockedHeader[0], th[0])) {
                            header = treelist.lockedHeader;
                            contentTable = treelist.lockedTable;
                        } else {
                            header = treelist.thead.parent();
                            contentTable = treelist.table;
                        }
                        this.col = contentTable.children('colgroup').find(colSelector).add(header.find(colSelector));
                        this.th = th;
                        this.startLocation = e.x.location;
                        this.columnWidth = outerWidth(th);
                        this.table = this.col.closest('table');
                        this.totalWidth = this.table.width();
                    },
                    resize: function (e) {
                        var rtlModifier = isRtl ? -1 : 1;
                        var minColumnWidth = 11;
                        var delta = e.x.location * rtlModifier - this.startLocation * rtlModifier;
                        if (this.columnWidth + delta < minColumnWidth) {
                            delta = minColumnWidth - this.columnWidth;
                        }
                        this.table.width(this.totalWidth + delta);
                        this.col.width(this.columnWidth + delta);
                    },
                    resizeend: function () {
                        treelist.wrapper.removeClass('k-grid-column-resizing');
                        var field = this.th.attr('data-field');
                        var column = grep(leafColumns(treelist.columns), function (c) {
                            return c.field == field;
                        });
                        var newWidth = Math.floor(outerWidth(this.th));
                        column[0].width = newWidth;
                        treelist._resize();
                        treelist._syncLockedContentHeight();
                        treelist._syncLockedHeaderHeight();
                        treelist.trigger(COLUMNRESIZE, {
                            column: column,
                            oldWidth: this.columnWidth,
                            newWidth: newWidth
                        });
                        this.table = this.col = this.th = null;
                    }
                });
            },
            _sortable: function () {
                var columns;
                var column;
                var sortableInstance;
                var cells;
                var cell, idx, length;
                var sortable = this.options.sortable;
                var hasMultiColumnHeaders = grep(this.columns, function (item) {
                    return item.columns !== undefined;
                }).length > 0;
                if (!sortable) {
                    return;
                }
                if (hasMultiColumnHeaders) {
                    if (this.lockedHeader) {
                        cells = sortCells(leafDataCells(this.lockedHeader.find('>table>thead')).add(leafDataCells(this.thead)));
                    } else {
                        cells = leafDataCells(this.thead);
                    }
                } else {
                    cells = $(this.lockedHeader).add(this.thead).find('th');
                }
                columns = leafColumns(this.columns);
                for (idx = 0, length = cells.length; idx < length; idx++) {
                    column = columns[idx];
                    if (column.sortable !== false && !column.command && column.field) {
                        cell = cells.eq(idx);
                        sortableInstance = cell.data('kendoColumnSorter');
                        if (sortableInstance) {
                            sortableInstance.destroy();
                        }
                        cell.kendoColumnSorter(extend({}, sortable, column.sortable, { dataSource: this.dataSource }));
                    }
                }
            },
            _filterable: function () {
                var cells;
                var filterable = this.options.filterable;
                var idx;
                var length;
                var columns;
                var column;
                var cell;
                var filterMenuInstance;
                var hasMultiColumnHeaders = grep(this.columns, function (item) {
                    return item.columns !== undefined;
                }).length > 0;
                if (!filterable || this.options.columnMenu) {
                    return;
                }
                var filterInit = proxy(function (e) {
                    this.trigger(FILTERMENUINIT, {
                        field: e.field,
                        container: e.container
                    });
                }, this);
                var filterOpen = proxy(function (e) {
                    this.trigger(FILTERMENUOPEN, {
                        field: e.field,
                        container: e.container
                    });
                }, this);
                if (hasMultiColumnHeaders) {
                    if (this.lockedHeader) {
                        cells = leafDataCells(this.lockedHeader.find('>table>thead')).add(leafDataCells(this.thead));
                    } else {
                        cells = leafDataCells(this.thead);
                    }
                } else {
                    cells = $(this.lockedHeader).add(this.thead).find('th');
                }
                columns = leafColumns(this.columns);
                for (idx = 0, length = cells.length; idx < length; idx++) {
                    column = columns[idx];
                    cell = cells.eq(idx);
                    filterMenuInstance = cell.data('kendoFilterMenu');
                    if (filterMenuInstance) {
                        filterMenuInstance.destroy();
                    }
                    if (column.command || column.filterable === false) {
                        continue;
                    }
                    cell.kendoFilterMenu(extend(true, {}, filterable, column.filterable, {
                        dataSource: this.dataSource,
                        init: filterInit,
                        open: filterOpen
                    }));
                }
            },
            _change: function () {
                this.trigger(CHANGE);
            },
            _isLocked: function () {
                return this.lockedHeader !== null;
            },
            _selectable: function () {
                var that = this;
                var selectable = this.options.selectable;
                var filter;
                var element = this.table;
                var useAllItems;
                var isLocked = that._isLocked();
                var multi;
                var cell;
                if (selectable) {
                    selectable = kendo.ui.Selectable.parseOptions(selectable);
                    if (this._hasLockedColumns) {
                        element = element.add(this.lockedTable);
                        useAllItems = selectable.multiple && selectable.cell;
                    }
                    filter = '>tbody>tr:not(.k-footer-template)';
                    if (selectable.cell) {
                        filter = filter + '>td';
                    }
                    this.selectable = new kendo.ui.Selectable(element, {
                        filter: filter,
                        aria: true,
                        multiple: selectable.multiple,
                        change: proxy(this._change, this),
                        useAllItems: useAllItems,
                        continuousItems: proxy(this._continuousItems, this, filter, selectable.cell),
                        relatedTarget: !selectable.cell && this._hasLockedColumns ? proxy(this._selectableTarget, this) : undefined
                    });
                    if (that.options.navigatable) {
                        multi = selectable.multiple;
                        cell = selectable.cell;
                        element.on('keydown' + NS, function (e) {
                            var current = that.current();
                            var target = e.target;
                            if (e.keyCode === keys.SPACEBAR && !e.shiftKey && $.inArray(target, element) > -1 && !current.is('.k-header')) {
                                e.preventDefault();
                                e.stopPropagation();
                                current = cell ? current : current.parent();
                                if (isLocked && !cell) {
                                    current = current.add(that._relatedRow(current));
                                }
                                if (multi) {
                                    if (!e.ctrlKey) {
                                        that.selectable.clear();
                                    } else {
                                        if (current.hasClass(classNames.selected)) {
                                            current.removeClass(classNames.selected);
                                            that.trigger(CHANGE);
                                            return;
                                        }
                                    }
                                } else {
                                    that.selectable.clear();
                                }
                                if (!cell) {
                                    that.selectable._lastActive = current;
                                }
                                that.selectable.value(current);
                            } else if (!cell && (e.shiftKey && e.keyCode == keys.LEFT || e.shiftKey && e.keyCode == keys.RIGHT || e.shiftKey && e.keyCode == keys.UP || e.shiftKey && e.keyCode == keys.DOWN || e.keyCode === keys.SPACEBAR && e.shiftKey)) {
                                e.preventDefault();
                                e.stopPropagation();
                                current = current.parent();
                                if (isLocked) {
                                    current = current.add(that._relatedRow(current));
                                }
                                if (multi) {
                                    if (!that.selectable._lastActive) {
                                        that.selectable._lastActive = current;
                                    }
                                    that.selectable.selectRange(that.selectable._firstSelectee(), current);
                                } else {
                                    that.selectable.clear();
                                    that.selectable.value(current);
                                }
                            }
                        });
                    }
                }
            },
            _continuousItems: function (filter, cell) {
                if (!this.lockedContent) {
                    return;
                }
                var lockedItems = $(filter, this.lockedTable);
                var nonLockedItems = $(filter, this.table);
                var columns = cell ? lockedColumns(this.columns).length : 1;
                var nonLockedColumns = cell ? this.columns.length - columns : 1;
                var result = [];
                for (var idx = 0; idx < lockedItems.length; idx += columns) {
                    push.apply(result, lockedItems.slice(idx, idx + columns));
                    push.apply(result, nonLockedItems.splice(0, nonLockedColumns));
                }
                return result;
            },
            _selectableTarget: function (items) {
                var related;
                var result = $();
                for (var idx = 0, length = items.length; idx < length; idx++) {
                    related = this._relatedRow(items[idx]);
                    if (inArray(related[0], items) < 0) {
                        result = result.add(related);
                    }
                }
                return result;
            },
            _relatedRow: function (row) {
                var lockedTable = this.lockedTable;
                row = $(row);
                if (!lockedTable) {
                    return row;
                }
                var table = row.closest(this.table.add(this.lockedTable));
                var index = table.find('>tbody>tr').index(row);
                table = table[0] === this.table[0] ? lockedTable : this.table;
                return table.find('>tbody>tr').eq(index);
            },
            select: function (value) {
                var selectable = this.selectable;
                if (!selectable) {
                    return $();
                }
                if (typeof value !== 'undefined') {
                    if (!selectable.options.multiple) {
                        selectable.clear();
                        value = value.first();
                    }
                    if (this._hasLockedColumns) {
                        value = value.add($.map(value, proxy(this._relatedRow, this)));
                    }
                }
                return selectable.value(value);
            },
            clearSelection: function () {
                var selected = this.select();
                if (selected.length) {
                    this.selectable.clear();
                    this.trigger(CHANGE);
                }
            },
            _dataSource: function (dataSource) {
                var that = this;
                var ds = this.dataSource;
                var pageable = that.options.pageable;
                if (ds) {
                    ds.unbind(CHANGE, this._refreshHandler);
                    ds.unbind(ERROR, this._errorHandler);
                    ds.unbind(PROGRESS, this._progressHandler);
                }
                this._refreshHandler = proxy(this.refresh, this);
                this._errorHandler = proxy(this._error, this);
                this._progressHandler = proxy(this._progress, this);
                if (isPlainObject(dataSource)) {
                    extend(dataSource, {
                        table: that.table,
                        fields: that.columns
                    });
                    if (isPlainObject(pageable) && pageable.pageSize !== undefined) {
                        dataSource.pageSize = pageable.pageSize;
                    }
                }
                ds = this.dataSource = TreeListDataSource.create(dataSource);
                if (pageable) {
                    ds._collapsedTotal = undefined;
                }
                ds.bind(CHANGE, this._refreshHandler);
                ds.bind(ERROR, this._errorHandler);
                ds.bind(PROGRESS, this._progressHandler);
                this._dataSourceFetchProxy = proxy(function () {
                    this.dataSource.fetch();
                }, this);
            },
            setDataSource: function (dataSource) {
                this._dataSource(dataSource);
                this._sortable();
                this._filterable();
                this._columnMenu();
                this._pageable();
                this._contentTree.render([]);
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
            },
            dataItem: function (element) {
                if (element instanceof TreeListModel) {
                    return element;
                }
                var row = $(element).closest('tr');
                var uid = row.attr(kendo.attr('uid'));
                var model = isUndefined(uid) ? null : this.dataSource.getByUid(uid);
                return model;
            },
            editRow: function (row) {
                var that = this;
                var model;
                if (this._isIncellEditable() || !this.options.editable) {
                    return;
                }
                if (typeof row === STRING) {
                    row = this.tbody.find(row);
                }
                if (that._isPageable() && that._isPopupEditable() && row instanceof TreeListModel) {
                    model = row;
                } else {
                    model = this.dataItem(row);
                }
                if (!model) {
                    return;
                }
                if (that.editor) {
                    model._edit = true;
                    this._render();
                    this._cancelEditor();
                } else {
                    that._preventPageSizeRestore = false;
                }
                if (this._editMode() != 'popup') {
                    model._edit = true;
                }
                if (this.trigger(BEFORE_EDIT, { model: model })) {
                    that.dataSource._restorePageSizeAfterAddChild();
                    return;
                }
                this._render();
                this._createEditor(model);
                this.trigger(EDIT, {
                    container: this.editor.wrapper,
                    model: model
                });
            },
            _cancelEdit: function (e) {
                if (!this.editor) {
                    return;
                }
                var currentIndex;
                e = extend(e, {
                    container: this.editor.wrapper,
                    model: this.editor.model
                });
                if (this.trigger(CANCEL, e)) {
                    return;
                }
                if (this.options.navigatable) {
                    currentIndex = this.items().index($(this.current()).parent());
                }
                this.cancelRow();
                if (this.options.navigatable) {
                    this.current(this.items().eq(currentIndex).children().filter(NAVCELL).first());
                    focusTable(this.table, true);
                }
            },
            cancelRow: function () {
                if (this._isIncellEditable()) {
                    return;
                }
                this._cancelEditor();
                this._render();
            },
            saveRow: function () {
                var editor = this.editor;
                var args;
                if (this._isIncellEditable()) {
                    return;
                }
                if (!editor) {
                    return;
                }
                args = {
                    model: editor.model,
                    container: editor.wrapper
                };
                if (editor.end() && !this.trigger(SAVE, args)) {
                    this.dataSource.sync();
                }
            },
            addRow: function (parent) {
                var that = this;
                var dataSource = that.dataSource;
                var pageable = that._isPageable();
                var incellEditing = that._isIncellEditable();
                var inlineEditing = that._isInlineEditable();
                var editor = this.editor;
                var index = 0;
                var model = {};
                if (editor && !editor.end() || !this.options.editable) {
                    return;
                }
                if (parent) {
                    if (!(parent instanceof TreeListModel)) {
                        parent = this.dataItem(parent);
                    }
                    model[parent.parentIdField] = parent.id;
                    index = this.dataSource.indexOf(parent) + 1;
                    this.expand(parent).then(function () {
                        var showNewModelInView = pageable && dataSource._isLastItemInView(parent) && (incellEditing || inlineEditing);
                        that._insertAt(model, index, showNewModelInView);
                    });
                    return;
                }
                this._insertAt(model, index);
            },
            _insertAt: function (model, index, showNewModelInView) {
                var that = this;
                var dataSource = that.dataSource;
                model = that.dataSource.insert(index, model);
                if (showNewModelInView) {
                    dataSource._setAddChildPageSize();
                }
                var row = this._itemFor(model);
                var cell;
                if (that._isIncellEditable()) {
                    cell = row.children('td').eq(that._firstEditableColumnIndex(row));
                    that.editCell(cell);
                } else if (row && row[0]) {
                    that.editRow(row);
                } else if (that._isPageable() && that._isPopupEditable()) {
                    that.editRow(model);
                }
            },
            _firstEditableColumnIndex: function (container) {
                var that = this;
                var model = that.dataItem(container);
                var columns = leafColumns(that.columns);
                var length = columns.length;
                var column;
                var idx;
                for (idx = 0; idx < length; idx++) {
                    column = columns[idx];
                    if (model && (!model.editable || model.editable(column.field)) && !column.command && column.field && column.hidden !== true) {
                        return idx;
                    }
                }
                return -1;
            },
            removeRow: function (row) {
                var model = this.dataItem(row);
                var args = {
                    model: model,
                    row: row
                };
                if (this.options.editable && model && !this.trigger(REMOVE, args)) {
                    if (document.activeElement === $(row).find('.k-grid-delete')[0]) {
                        $(row).find('.k-grid-delete').blur();
                    }
                    this.dataSource.remove(model);
                    if (!this._isIncellEditable()) {
                        this.dataSource.sync();
                    }
                }
            },
            _cancelEditor: function () {
                var that = this;
                var model;
                var editor = that.editor;
                if (editor) {
                    model = editor.model;
                    that._destroyEditor();
                    if (!that._isIncellEditable()) {
                        that.dataSource.cancelChanges(model);
                    } else if (that._shouldRestorePageSize()) {
                        that.dataSource._restorePageSizeAfterAddChild();
                    }
                    model._edit = false;
                }
                that._preventPageSizeRestore = false;
            },
            _shouldRestorePageSize: function () {
                var that = this;
                return that._isPageable() && that._isIncellEditable() && !that._preventPageSizeRestore;
            },
            _destroyEditor: function () {
                if (!this.editor) {
                    return;
                }
                this.editor.close();
                this.editor = null;
            },
            _createEditor: function (model) {
                var row = this.itemFor(model);
                var columns = leafColumns(this.columns);
                var leafCols = [];
                for (var idx = 0; idx < columns.length; idx++) {
                    leafCols.push(extend({}, columns[idx]));
                    delete leafCols[idx].parentColumn;
                }
                row = row.add(this._relatedRow(row));
                var mode = this._editMode();
                var options = {
                    columns: leafCols,
                    model: model,
                    target: this,
                    clearContainer: false,
                    template: this.options.editable.template
                };
                if (mode == 'inline') {
                    this.editor = new Editor(row, options);
                } else {
                    extend(options, {
                        window: this.options.editable.window,
                        commandRenderer: proxy(function () {
                            return this._buildCommands([
                                'update',
                                'canceledit'
                            ]);
                        }, this),
                        fieldRenderer: proxy(this._cellContent, this),
                        save: proxy(this.saveRow, this),
                        cancel: proxy(this._cancelEdit, this),
                        appendTo: this.wrapper
                    });
                    this.editor = new PopupEditor(row, options);
                }
            },
            _createIncellEditor: function (cell, options) {
                var that = this;
                var column = extend({}, options.columns[0]);
                delete column.parentColumn;
                return new IncellEditor(cell, extend({}, {
                    fieldRenderer: proxy(that._cellContent, that),
                    appendTo: that.wrapper,
                    clearContainer: false,
                    target: that,
                    columns: [column],
                    model: options.model,
                    change: options.change
                }));
            },
            editCell: function (cell) {
                var that = this;
                cell = $(cell);
                var column = leafColumns(that.columns)[that.cellIndex(cell)];
                var model = that.dataItem(cell);
                if (that._isIncellEditable() && model && isColumnEditable(column, model)) {
                    that._editCell(cell, column, model);
                }
            },
            _editCell: function (cell, column, model) {
                var that = this;
                var editedCell;
                if (that.trigger(BEFORE_EDIT, { model: model })) {
                    that.dataSource._restorePageSizeAfterAddChild();
                    return;
                }
                that.closeCell();
                model._edit = true;
                that._cancelEditor();
                that._render({
                    editedColumn: column,
                    editedColumnIndex: cell.index()
                });
                editedCell = that.table.add(that.lockedTable).find(DOT + classNames.editCell).first();
                that.editor = that._createIncellEditor(editedCell, {
                    columns: [column],
                    model: model,
                    change: function (e) {
                        if (that.trigger(SAVE, {
                                values: e.values,
                                container: cell,
                                model: model
                            })) {
                            e.preventDefault();
                        }
                    }
                });
                that._current = editedCell;
                that.trigger(EDIT, {
                    container: cell,
                    model: model
                });
            },
            closeCell: function (isCancel) {
                var that = this;
                var cell = (that.editor || {}).element;
                var tr;
                var model;
                if (!cell || !cell[0] || !that._isIncellEditable()) {
                    return;
                }
                model = that.dataItem(cell);
                if (isCancel && that.trigger(CANCEL, {
                        container: cell,
                        model: model
                    })) {
                    return;
                }
                that.trigger(CELL_CLOSE, {
                    type: isCancel ? CANCEL : SAVE,
                    model: model,
                    container: cell
                });
                that._cancelEditor();
                cell.removeClass(classNames.editCell);
                tr = cell.parent().removeClass(classNames.editRow);
                if (that.lockedContent) {
                    that._relatedRow(tr).removeClass(classNames.editRow);
                }
                that._render();
                that.trigger(ITEM_CHANGE, {
                    item: tr,
                    data: model,
                    ns: ui
                });
                if (that.lockedContent) {
                    adjustRowHeight(tr.css('height', '')[0], that._relatedRow(tr).css('height', '')[0]);
                }
            },
            cancelChanges: function () {
                this.dataSource.cancelChanges();
            },
            saveChanges: function () {
                var that = this;
                var editable = (that.editor || {}).editable;
                var valid = editable && editable.end();
                if ((valid || !editable) && !that.trigger(SAVE_CHANGES)) {
                    that.dataSource.sync();
                }
            },
            _editMode: function () {
                var mode = 'inline', editable = this.options.editable;
                if (editable !== true) {
                    if (typeof editable == 'string') {
                        mode = editable;
                    } else {
                        mode = editable.mode || mode;
                    }
                }
                return mode.toLowerCase();
            },
            _isIncellEditable: function () {
                return this._editMode() === INCELL;
            },
            _isInlineEditable: function () {
                return this._editMode() === INLINE;
            },
            _isPopupEditable: function () {
                return this._editMode() === POPUP;
            },
            hideColumn: function (column) {
                this._toggleColumnVisibility(column, true);
            },
            showColumn: function (column) {
                this._toggleColumnVisibility(column, false);
            },
            _toggleColumnVisibility: function (column, hidden) {
                column = this._findColumn(column);
                if (!column || column.hidden === hidden) {
                    return;
                }
                column.hidden = hidden;
                this._setParentsVisibility(column, !hidden);
                this._ensureExpandableColumn();
                this._clearColsCache();
                this._renderCols();
                this._renderHeader();
                this._render();
                this._adjustTablesWidth();
                this.trigger(hidden ? COLUMNHIDE : COLUMNSHOW, { column: column });
                if (!hidden && !column.width) {
                    this.table.add(this.thead.closest('table')).width('');
                }
                this._updateFirstColumnClass();
            },
            _findColumn: function (column) {
                if (typeof column == 'number') {
                    column = this.columns[column];
                } else if (isPlainObject(column)) {
                    column = grep(leafColumns(this.columns), function (item) {
                        return item === column;
                    })[0];
                } else {
                    column = grep(leafColumns(this.columns), function (item) {
                        return item.field === column;
                    })[0];
                }
                return column;
            },
            _adjustTablesWidth: function () {
                var idx, length;
                var cols = this.thead.prev().children();
                var colWidth, width = 0;
                for (idx = 0, length = cols.length; idx < length; idx++) {
                    colWidth = cols[idx].style.width;
                    if (colWidth && colWidth.indexOf('%') == -1) {
                        width += parseInt(colWidth, 10);
                    } else {
                        width = 0;
                        break;
                    }
                }
                if (width) {
                    this.table.add(this.thead.closest('table')).width(width);
                }
            },
            _reorderable: function () {
                if (!this.options.reorderable) {
                    return;
                }
                var scrollable = this.options.scrollable === true;
                var selector = (scrollable ? '.k-grid-header:first ' : 'table:first>.k-grid-header ') + HEADERCELLS;
                var that = this;
                this._draggableInstance = new ui.Draggable(this.wrapper, {
                    group: kendo.guid(),
                    filter: selector,
                    hint: function (target) {
                        return $('<div class="k-header k-reorder-clue k-drag-clue" />').html(target.attr(kendo.attr('title')) || target.attr(kendo.attr('field')) || target.text()).prepend('<span class="k-icon k-drag-status k-i-cancel" />');
                    }
                });
                this.reorderable = new ui.Reorderable(this.wrapper, {
                    draggable: this._draggableInstance,
                    dragOverContainers: proxy(this._allowDragOverContainers, this),
                    inSameContainer: function (e) {
                        return $(e.source).parent()[0] === $(e.target).parent()[0] && targetParentContainerIndex(flatColumnsInDomOrder(that.columns), that.columns, e.sourceIndex, e.targetIndex) > -1;
                    },
                    change: function (e) {
                        var columns = flatColumnsInDomOrder(that.columns);
                        var column = columns[e.oldIndex];
                        var newIndex = targetParentContainerIndex(columns, that.columns, e.oldIndex, e.newIndex);
                        that.trigger(COLUMNREORDER, {
                            newIndex: newIndex,
                            oldIndex: inArray(column, columns),
                            column: column
                        });
                        that.reorderColumn(newIndex, column, e.position === 'before');
                    }
                });
            },
            _allowDragOverContainers: function (sourceIndex, targetIndex) {
                var columns = flatColumnsInDomOrder(this.columns);
                return columns[sourceIndex].lockable !== false && targetParentContainerIndex(columns, this.columns, sourceIndex, targetIndex) > -1;
            },
            _reorderTrees: function (destSources, destContainer, destDomTree, sources, sourcesContainer, sourcesDomTree, before, depth) {
                var ths = $();
                var source = sourcesContainer.find('tr:eq(' + sources[0].rowIndex + ')');
                var sourceDOM = sourcesDomTree.children[sources[0].rowIndex];
                var sourceChildren = source.children();
                var destDomChildren;
                var currentIndex;
                var destColumn = before ? destSources[0] : destSources[destSources.length - 1];
                var destRow;
                var sourcesLeafs;
                var destLeafs;
                var reorderTaget;
                var destThs;
                for (var idx = 0; idx < sources.length; idx++) {
                    currentIndex = sources[idx].cellIndex;
                    ths = ths.add(sourceChildren.eq(currentIndex));
                    destDomChildren = destDomTree.children[destColumn.rowIndex].children;
                    if (destDomTree === sourcesDomTree && before) {
                        currentIndex += idx;
                    }
                    destDomChildren.splice(before ? destColumn.cellIndex + idx : destColumn.cellIndex + 1 + idx, 0, sourceDOM.children[currentIndex]);
                }
                if (destDomTree === sourcesDomTree && before) {
                    sourceDOM.children.splice(sources[0].cellIndex + sources.length, sources.length);
                } else {
                    sourceDOM.children.splice(sources[0].cellIndex, sources.length);
                }
                destRow = destContainer.find('tr:eq(' + destColumn.rowIndex + ')');
                destThs = destRow.find('>th.k-header:eq(' + destColumn.cellIndex + ')');
                if (destThs.length && ths[0] !== destThs[0]) {
                    ths[before ? 'insertBefore' : 'insertAfter'](destThs);
                }
                if (depth >= sources[0].rowIndex + 1 && depth != 1) {
                    sourcesLeafs = [];
                    for (idx = 0; idx < sources.length; idx++) {
                        if (sources[idx].columns) {
                            sourcesLeafs = sourcesLeafs.concat(sources[idx].columns);
                        }
                    }
                    if (!sourcesLeafs.length) {
                        return;
                    }
                    destLeafs = [];
                    for (idx = 0; idx < destSources.length; idx++) {
                        if (destSources[idx].columns) {
                            destLeafs = destLeafs.concat(destSources[idx].columns);
                        }
                    }
                    if (!destLeafs.length && (destContainer !== sourcesContainer || (destColumn.cellIndex - sources[0].cellIndex > 1 || sources[0].cellIndex - destColumn.cellIndex > 1))) {
                        reorderTaget = findReorderTarget(this.columns, destColumn, sources[0], before, this.columns);
                        destLeafs = [reorderTaget];
                        if (!reorderTaget && sourcesLeafs.length && destContainer.find('tr').length > sources[0].rowIndex + 1) {
                            this._insertTree(sourcesLeafs, sourcesContainer, sourcesDomTree, destContainer, destDomTree);
                            return;
                        }
                    }
                    if (!destLeafs.length) {
                        return;
                    }
                    this._reorderTrees(destLeafs, destContainer, destDomTree, sourcesLeafs, sourcesContainer, sourcesDomTree, before, depth);
                }
            },
            _insertTree: function (columns, sourcesContainer, sourcesDomTree, destContainer, destDomTree) {
                var leafs = [];
                var row;
                var ths = $();
                var domTr;
                row = sourcesContainer.find('tr:eq(' + columns[0].rowIndex + ')');
                domTr = sourcesDomTree.children[columns[0].rowIndex];
                for (var idx = 0; idx < columns.length; idx++) {
                    if (columns[idx].columns) {
                        leafs = leafs.concat(columns[idx].columns);
                    }
                    destDomTree.children[columns[0].rowIndex].children.splice(idx, 0, domTr.children[columns[idx].rowIndex]);
                    ths = ths.add(row.find('>th.k-header:eq(' + columns[idx].cellIndex + ')'));
                }
                sourcesDomTree.children[columns[0].rowIndex].children.splice(columns[0].cellIndex, columns.length);
                destContainer.find('tr:eq(' + columns[0].rowIndex + ')').append(ths);
                if (leafs.length) {
                    this._insertTree(leafs, sourcesContainer, sourcesDomTree, destContainer, destDomTree);
                }
            },
            _reorderHeader: function (destColumn, column, before) {
                var sourcesDepth = column.columns ? depth([column]) : 1;
                var targetDepth = destColumn.columns ? depth([destColumn]) : 1;
                var sourceLocked = isLocked(column);
                var destLocked = isLocked(destColumn);
                var destContainer = destLocked ? this.lockedHeader : this.thead;
                var sourcesContainer = sourceLocked ? this.lockedHeader : this.thead;
                var destDomTree = destLocked ? this._lockedHeaderTree : this._headerTree;
                var sourcesDomTree = sourceLocked ? this._lockedHeaderTree : this._headerTree;
                var rowsToAdd;
                var destRows = destContainer.find('tr');
                if (sourcesDepth === targetDepth || sourcesDepth < destRows.length) {
                    this._reorderTrees([destColumn], destContainer, destDomTree, [column], sourcesContainer, sourcesDomTree, before, sourcesDepth);
                    updateRowSpans(destContainer, destDomTree);
                    removeEmptyRows(sourcesContainer, sourcesDomTree);
                } else {
                    if (destContainer !== sourcesContainer) {
                        rowsToAdd = sourcesDepth - destRows.length;
                        destRows.each(function (idx) {
                            var cells = this.cells;
                            for (var i = 0; i < cells.length; i++) {
                                if (cells[i].colSpan <= 1 && cells[i].attributes.rowspan) {
                                    destDomTree.children[idx].children[i].attr.rowSpan += rowsToAdd;
                                    cells[i].rowSpan += rowsToAdd;
                                }
                            }
                        });
                        for (var j = 0; j < rowsToAdd; j++) {
                            destDomTree.children.push(kendoDomElement('tr', { 'role': 'row' }));
                            if (destContainer.is('thead')) {
                                destContainer.append('<tr role=\'row\'></tr>');
                            } else {
                                destContainer.find('thead').append('<tr role=\'row\'></tr>');
                            }
                        }
                    }
                    this._reorderTrees([destColumn], destContainer, destDomTree, [column], sourcesContainer, sourcesDomTree, before, sourcesDepth);
                    removeEmptyRows(sourcesContainer, sourcesDomTree);
                }
            },
            reorderColumn: function (destIndex, column, before) {
                var lockChanged;
                var parent = column.parentColumn;
                var columns = parent ? parent.columns : this.columns;
                var sourceIndex = inArray(column, columns);
                var destColumn = columns[destIndex];
                var isLocked = !!destColumn.locked;
                var hasMultiColumnHeaders = grep(this.columns, function (item) {
                    return item.columns !== undefined;
                }).length > 0;
                var nonLockedColumnsLength = nonLockedColumns(columns).length;
                if (sourceIndex === destIndex) {
                    return;
                }
                if (isLocked && !column.locked && nonLockedColumnsLength == 1) {
                    return;
                }
                if (!isLocked && column.locked && columns.length - nonLockedColumnsLength == 1) {
                    return;
                }
                if (before === undefined) {
                    before = destIndex < sourceIndex;
                }
                if (hasMultiColumnHeaders) {
                    this._reorderHeader(destColumn, column, before);
                }
                lockChanged = !!column.locked;
                lockChanged = lockChanged != isLocked;
                column.locked = isLocked;
                columns.splice(before ? destIndex : destIndex + 1, 0, column);
                columns.splice(sourceIndex < destIndex ? sourceIndex : sourceIndex + 1, 1);
                this._setColumnDataIndexes(leafColumns(this.columns));
                this._clearColsCache();
                this._renderCols();
                if (!hasMultiColumnHeaders) {
                    var ths = $(this.lockedHeader).add(this.thead).find('th');
                    ths.eq(sourceIndex)[before ? 'insertBefore' : 'insertAfter'](ths.eq(destIndex));
                    var dom = this._headerTree.children[0].children;
                    if (this._hasLockedColumns) {
                        dom = this._lockedHeaderTree.children[0].children.concat(dom);
                    }
                    dom.splice(before ? destIndex : destIndex + 1, 0, dom[sourceIndex]);
                    dom.splice(sourceIndex < destIndex ? sourceIndex : sourceIndex + 1, 1);
                    if (this._hasLockedColumns) {
                        this._lockedHeaderTree.children[0].children = dom.splice(0, lockedColumns(columns).length);
                        this._headerTree.children[0].children = dom;
                    }
                } else {
                    if (this.lockedHeader) {
                        columns = nonLockedColumns(this.columns);
                        this._prepareColumns([{
                                rowSpan: 1,
                                cells: [],
                                index: 0
                            }], columns);
                        columns = lockedColumns(this.columns);
                        this._prepareColumns([{
                                rowSpan: 1,
                                cells: [],
                                index: 0
                            }], columns);
                    } else {
                        this._prepareColumns([{
                                rowSpan: 1,
                                cells: [],
                                index: 0
                            }], this.columns);
                    }
                }
                this._updateColumnCellIndex();
                this._applyLockedContainersWidth();
                this._syncLockedHeaderHeight();
                this._updateFirstColumnClass();
                this.refresh();
                if (!lockChanged) {
                    return;
                }
                if (isLocked) {
                    this.trigger(COLUMNLOCK, { column: column });
                } else {
                    this.trigger(COLUMNUNLOCK, { column: column });
                }
            },
            lockColumn: function (column) {
                var columns = this.columns;
                if (typeof column == 'number') {
                    column = columns[column];
                } else {
                    column = grep(columns, function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || column.hidden) {
                    return;
                }
                var index = lockedColumns(columns).length - 1;
                this.reorderColumn(index, column, false);
            },
            unlockColumn: function (column) {
                var columns = this.columns;
                if (typeof column == 'number') {
                    column = columns[column];
                } else {
                    column = grep(columns, function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || column.hidden) {
                    return;
                }
                var index = lockedColumns(columns).length;
                this.reorderColumn(index, column, true);
            },
            _columnMenu: function () {
                var ths = $(this.lockedHeader).add(this.thead).find('th');
                var columns = this.columns;
                var options = this.options;
                var columnMenu = options.columnMenu;
                var column, menu, menuOptions, sortable, filterable;
                var initHandler = proxy(this._columnMenuInit, this);
                var openHandler = proxy(this._columnMenuOpen, this);
                var lockedColumnsLength = lockedColumns(columns).length;
                var hasMultiColumnHeaders = grep(this.columns, function (item) {
                    return item.columns !== undefined;
                }).length > 0;
                if (hasMultiColumnHeaders) {
                    columns = leafColumns(columns);
                    if (this.lockedHeader) {
                        ths = sortCells(leafDataCells(this.lockedHeader.find('>table>thead')).add(leafDataCells(this.thead)));
                    } else {
                        ths = leafDataCells(this.thead);
                    }
                } else {
                    ths = $(this.lockedHeader).add(this.thead).find('th');
                }
                if (!columnMenu) {
                    return;
                }
                if (typeof columnMenu == 'boolean') {
                    columnMenu = {};
                }
                for (var i = 0; i < ths.length; i++) {
                    column = columns[i];
                    if (!column.field) {
                        continue;
                    }
                    menu = ths.eq(i).data('kendoColumnMenu');
                    if (menu) {
                        menu.destroy();
                    }
                    sortable = false;
                    if (column.sortable !== false && columnMenu.sortable !== false && options.sortable !== false) {
                        sortable = extend({}, options.sortable, { compare: (column.sortable || {}).compare });
                    }
                    filterable = false;
                    if (options.filterable && column.filterable !== false && columnMenu.filterable !== false) {
                        filterable = extend({ pane: this.pane }, column.filterable, options.filterable);
                    }
                    menuOptions = {
                        dataSource: this.dataSource,
                        values: column.values,
                        columns: columnMenu.columns,
                        sortable: sortable,
                        filterable: filterable,
                        messages: columnMenu.messages,
                        owner: this,
                        closeCallback: $.noop,
                        init: initHandler,
                        open: openHandler,
                        pane: this.pane,
                        lockedColumns: !hasMultiColumnHeaders && column.lockable !== false && lockedColumnsLength > 0
                    };
                    if (options.$angular) {
                        menuOptions.$angular = options.$angular;
                    }
                    ths.eq(i).kendoColumnMenu(menuOptions);
                }
            },
            _columnMenuInit: function (e) {
                this.trigger(COLUMNMENUINIT, {
                    field: e.field,
                    container: e.container
                });
            },
            _pageable: function () {
                var that = this, wrapper, pageable = that.options.pageable;
                if (pageable) {
                    wrapper = that.wrapper.children('div.k-grid-pager');
                    if (!wrapper.length) {
                        wrapper = $('<div class="k-pager-wrap k-grid-pager"/>').appendTo(that.wrapper);
                    }
                    that._destroyPager();
                    if (typeof pageable === 'object' && pageable instanceof kendo.ui.TreeListPager) {
                        that.pager = pageable;
                    } else if (that.dataSource && !that.dataSource.options.serverPaging) {
                        that._createPager(wrapper);
                    }
                    if (that.pager) {
                        that.pager.bind(PAGE_CHANGE, function (e) {
                            if (that.trigger(PAGE, { page: e.index })) {
                                e.preventDefault();
                            }
                        });
                    }
                }
            },
            _createPager: function (element, options) {
                var that = this;
                that.pager = new TreeListPager(element, extend({}, that.options.pageable, { dataSource: that.dataSource }, options));
            },
            _destroyPager: function () {
                if (this.pager) {
                    this.pager.destroy();
                }
            },
            _isPageable: function () {
                var that = this;
                return that.options.pageable && (!that.dataSource || that.dataSource && that.dataSource._isPageable());
            },
            _togglePagerVisibility: function () {
                var that = this;
                var pageable = that.options.pageable;
                if (pageable && (isPlainObject(pageable) || pageable instanceof TreeListPager) && pageable.alwaysVisible === false) {
                    that.wrapper.find('.k-grid-pager').toggle((that.dataSource.collapsedTotal() || 0) >= that.dataSource.pageSize());
                }
            }
        });
        function isInputElement(element) {
            return $(element).is(':button,a,:input,a>.k-icon,textarea,span.k-select,span.k-icon,span.k-link,.k-input,.k-multiselect-wrap,.k-tool-icon');
        }
        function isLocked(column) {
            if (!column.parentColumn) {
                return !!column.locked;
            }
            return !!isLocked(column.parentColumn);
        }
        function findParentColumnWithChildren(columns, index, source, rtl) {
            var target;
            var locked = !!source.locked;
            var targetLocked;
            do {
                target = columns[index];
                index += rtl ? 1 : -1;
                targetLocked = !!target.locked;
            } while (target && index > -1 && index < columns.length && target != source && !target.columns && targetLocked === locked);
            return target;
        }
        function findReorderTarget(columns, target, source, before, masterColumns) {
            if (target.columns) {
                target = target.columns;
                return target[before ? 0 : target.length - 1];
            } else {
                var parent = columnParent(target, columns);
                var parentColumns;
                if (parent) {
                    parentColumns = parent.columns;
                } else {
                    parentColumns = columns;
                }
                var index = inArray(target, parentColumns);
                if (index === 0 && before && parentColumns.length !== 1) {
                    index++;
                } else if (index == parentColumns.length - 1 && !before && index !== 0) {
                    index--;
                } else if (index > 0 || index === 0 && !before && index !== 0) {
                    index += before ? -1 : 1;
                }
                var sourceIndex = inArray(source, parentColumns);
                target = findParentColumnWithChildren(parentColumns, index, source, sourceIndex > index);
                var targetIndex = inArray(target, masterColumns);
                if (target.columns && (!targetIndex || targetIndex === parentColumns.length - 1)) {
                    return null;
                }
                if (target && target != source && target.columns) {
                    return findReorderTarget(columns, target, source, before, masterColumns);
                }
            }
            return null;
        }
        function leafColumns(columns) {
            var result = [];
            for (var idx = 0; idx < columns.length; idx++) {
                if (!columns[idx].columns) {
                    result.push(columns[idx]);
                    continue;
                }
                result = result.concat(leafColumns(columns[idx].columns));
            }
            return result;
        }
        function visibleChildColumns(columns) {
            return grep(columns, function (column) {
                return !column.hidden;
            });
        }
        function isVisible(column) {
            return visibleColumns([column]).length > 0;
        }
        function visibleColumns(columns) {
            return grep(columns, function (column) {
                var result = !column.hidden;
                if (result && column.columns) {
                    result = visibleColumns(column.columns).length > 0;
                }
                return result;
            });
        }
        function normalizeColumns(columns, hide) {
            return map(columns, function (column) {
                var hidden;
                if (!isVisible(column) || hide) {
                    hidden = true;
                }
                if (column.columns) {
                    column.columns = normalizeColumns(column.columns, hidden);
                }
                return extend({ hidden: hidden }, column);
            });
        }
        function flatColumnsInDomOrder(columns) {
            var result = flatColumns(lockedColumns(columns));
            return result.concat(flatColumns(nonLockedColumns(columns)));
        }
        function targetParentContainerIndex(flatColumns, columns, sourceIndex, targetIndex) {
            var column = flatColumns[sourceIndex];
            var target = flatColumns[targetIndex];
            var parent = columnParent(column, columns);
            columns = parent ? parent.columns : columns;
            return inArray(target, columns);
        }
        function parentColumnsCells(cell) {
            var container = cell.closest('table');
            var result = $().add(cell);
            var row = cell.closest('tr');
            var headerRows = container.find('tr');
            var level = headerRows.index(row);
            if (level > 0) {
                var parent = headerRows.eq(level - 1);
                var parentCellsWithChildren = parent.find('th').filter(function () {
                    return !$(this).attr('rowspan');
                });
                var offset = 0;
                var index = row.find('th').index(cell);
                var prevCells = cell.prevAll().filter(function () {
                    return this.colSpan > 1;
                });
                for (var idx = 0; idx < prevCells.length; idx++) {
                    offset += prevCells[idx].colSpan || 1;
                }
                index += Math.max(offset - 1, 0);
                offset = 0;
                for (idx = 0; idx < parentCellsWithChildren.length; idx++) {
                    var parentCell = parentCellsWithChildren.eq(idx);
                    if (parentCell.attr('data-colspan')) {
                        offset += parentCell[0].getAttribute('data-colspan');
                    } else {
                        offset += 1;
                    }
                    if (index >= idx && index < offset) {
                        result = parentColumnsCells(parentCell).add(result);
                        break;
                    }
                }
            }
            return result;
        }
        function childColumnsCells(cell) {
            var container = cell.closest('thead');
            var result = $().add(cell);
            var row = cell.closest('tr');
            var headerRows = container.find('tr');
            var level = headerRows.index(row) + cell[0].rowSpan;
            var colSpanAttr = kendo.attr('colspan');
            if (level <= headerRows.length - 1) {
                var child = row.next();
                var prevCells = cell.prevAll();
                var idx;
                prevCells = prevCells.filter(function () {
                    return !this.rowSpan || this.rowSpan === 1;
                });
                var offset = 0;
                for (idx = 0; idx < prevCells.length; idx++) {
                    offset += parseInt(prevCells.eq(idx).attr(colSpanAttr), 10) || 1;
                }
                var cells = child.find('th');
                var colSpan = parseInt(cell.attr(colSpanAttr), 10) || 1;
                idx = 0;
                while (idx < colSpan) {
                    child = cells.eq(idx + offset);
                    result = result.add(childColumnsCells(child));
                    var value = parseInt(child.attr(colSpanAttr), 10);
                    if (value > 1) {
                        colSpan -= value - 1;
                    }
                    idx++;
                }
            }
            return result;
        }
        function columnParent(column, columns) {
            var parents = [];
            columnParents(column, columns, parents);
            return parents[parents.length - 1];
        }
        function columnParents(column, columns, parents) {
            parents = parents || [];
            for (var idx = 0; idx < columns.length; idx++) {
                if (column === columns[idx]) {
                    return true;
                } else if (columns[idx].columns) {
                    var inserted = parents.length;
                    parents.push(columns[idx]);
                    if (!columnParents(column, columns[idx].columns, parents)) {
                        parents.splice(inserted, parents.length - inserted);
                    } else {
                        return true;
                    }
                }
            }
            return false;
        }
        function flatColumns(columns) {
            var result = [];
            var children = [];
            for (var idx = 0; idx < columns.length; idx++) {
                result.push(columns[idx]);
                if (columns[idx].columns) {
                    children = children.concat(columns[idx].columns);
                }
            }
            if (children.length) {
                result = result.concat(flatColumns(children));
            }
            return result;
        }
        function columnPosition(column, columns, row, cellCounts) {
            var result;
            var idx;
            row = row || 0;
            cellCounts = cellCounts || {};
            cellCounts[row] = cellCounts[row] || 0;
            for (idx = 0; idx < columns.length; idx++) {
                if (columns[idx] == column) {
                    result = {
                        cell: cellCounts[row],
                        row: row
                    };
                    break;
                } else if (columns[idx].columns) {
                    result = columnPosition(column, columns[idx].columns, row + 1, cellCounts);
                    if (result) {
                        break;
                    }
                }
                cellCounts[row]++;
            }
            return result;
        }
        function updateCellIndex(thead, columns, offset) {
            offset = offset || 0;
            var position;
            var cell;
            var allColumns = columns;
            columns = leafColumns(columns);
            var cells = {};
            var rows = thead.find('>tr:not(.k-filter-row)');
            var filter = function () {
                var el = $(this);
                return !el.hasClass('k-group-cell') && !el.hasClass('k-hierarchy-cell');
            };
            for (var idx = 0, length = columns.length; idx < length; idx++) {
                position = columnPosition(columns[idx], allColumns);
                if (!cells[position.row]) {
                    cells[position.row] = rows.eq(position.row).find('.k-header').filter(filter);
                }
                cell = cells[position.row].eq(position.cell);
                cell.attr(kendo.attr('index'), offset + idx);
            }
            return columns.length;
        }
        function depth(columns) {
            var result = 1;
            var max = 0;
            for (var idx = 0; idx < columns.length; idx++) {
                if (columns[idx].columns) {
                    var temp = depth(columns[idx].columns);
                    if (temp > max) {
                        max = temp;
                    }
                }
            }
            return result + max;
        }
        function lockedColumns(columns) {
            return grep(columns, is('locked'));
        }
        function nonLockedColumns(columns) {
            return grep(columns, not(is('locked')));
        }
        function updateRowSpans(container, containerDOMtree) {
            var rows = container.find('tr');
            var length = rows.length;
            rows.each(function (idx) {
                var cells = this.cells;
                for (var i = 0; i < cells.length; i++) {
                    if (cells[i].colSpan <= 1 && cells[i].attributes.rowspan) {
                        containerDOMtree.children[idx].children[i].attr.rowSpan = length - idx;
                        cells[i].rowSpan = length - idx;
                    }
                }
            });
        }
        function removeEmptyRows(container, containerDOMtree) {
            var rows = container.find('tr');
            var emptyRows = [];
            rows.filter(function (idx) {
                var shouldRemove = !$(this).children().length;
                if (shouldRemove) {
                    emptyRows.push(idx);
                }
                return shouldRemove;
            }).remove();
            for (var i = emptyRows.length - 1; i >= 0; i--) {
                containerDOMtree.children.splice(emptyRows[i], 1);
            }
            updateRowSpans(container, containerDOMtree);
        }
        function focusTable(table, direct) {
            if (direct === true) {
                table = $(table);
                var scrollTop, scrollLeft;
                scrollTop = table.parent().scrollTop();
                scrollLeft = table.parent().scrollLeft();
                kendo.focusElement(table);
                table.parent().scrollTop(scrollTop).scrollLeft(scrollLeft);
            } else {
                $(table).one('focusin', function (e) {
                    e.preventDefault();
                }).focus();
            }
        }
        function adjustRowHeight(row1, row2) {
            var height;
            var offsetHeight1 = row1.offsetHeight;
            var offsetHeight2 = row2.offsetHeight;
            if (offsetHeight1 > offsetHeight2) {
                height = offsetHeight1 + 'px';
            } else if (offsetHeight1 < offsetHeight2) {
                height = offsetHeight2 + 'px';
            }
            if (height) {
                row1.style.height = row2.style.height = height;
            }
        }
        function isColumnEditable(column, model) {
            if (!column || !model || !column.field || column.selectable || column.command || column.editable && !column.editable(model)) {
                return false;
            }
            return column.field && model.editable && model.editable(column.field);
        }
        function isDirtyColumn(column, model) {
            var field = (column || {}).field || '';
            return model.dirty && model.dirtyFields && model.dirtyFields[field] && isColumnEditable(column, model);
        }
        function isUndefined(value) {
            return typeof value === 'undefined';
        }
        function isNumber(value) {
            return typeof value === 'number' && !isNaN(value);
        }
        if (kendo.ExcelMixin) {
            kendo.ExcelMixin.extend(TreeList.prototype);
        }
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(TreeList.prototype);
            TreeList.prototype._drawPDF = function (progress) {
                var treeList = this;
                if (treeList.options.pdf.paperSize && treeList.options.pdf.paperSize != 'auto') {
                    return treeList._drawPDF_autoPageBreak(progress);
                }
                var result = new $.Deferred();
                var dataSource = treeList.dataSource;
                var allPages = treeList.options.pdf.allPages;
                this._initPDFProgress(progress);
                var doc = new kendo.drawing.Group();
                var startingPage = dataSource.page();
                function resolve() {
                    if (allPages && startingPage !== undefined) {
                        dataSource.unbind('change', exportPage);
                        dataSource.one('change', function () {
                            result.resolve(doc);
                        });
                        dataSource.page(startingPage);
                    } else {
                        result.resolve(doc);
                    }
                }
                function exportPage() {
                    treeList._drawPDFShadow({ width: treeList.wrapper.width() }, { avoidLinks: treeList.options.pdf.avoidLinks }).done(function (group) {
                        var pageNum = dataSource.page();
                        var totalPages = allPages ? dataSource.totalPages() : 1;
                        var args = {
                            page: group,
                            pageNumber: pageNum,
                            progress: pageNum / totalPages,
                            totalPages: totalPages
                        };
                        progress.notify(args);
                        doc.append(args.page);
                        if (pageNum < totalPages) {
                            dataSource.page(pageNum + 1);
                        } else {
                            resolve();
                        }
                    }).fail(function (err) {
                        result.reject(err);
                    });
                }
                if (allPages) {
                    dataSource.bind('change', exportPage);
                    dataSource.page(1);
                } else {
                    exportPage();
                }
                return result.promise();
            };
            TreeList.prototype._initPDFProgress = function (deferred) {
                var loading = $('<div class=\'k-loading-pdf-mask\'><div class=\'k-loading-color\'/></div>');
                loading.prepend(this.wrapper.clone().css({
                    position: 'absolute',
                    top: 0,
                    left: 0
                }));
                this.wrapper.append(loading);
                var progressBar = $('<div class=\'k-loading-pdf-progress\'>').appendTo(loading).kendoProgressBar({
                    type: 'chunk',
                    chunkCount: 10,
                    min: 0,
                    max: 1,
                    value: 0
                }).data('kendoProgressBar');
                deferred.progress(function (e) {
                    progressBar.value(e.progress);
                }).always(function () {
                    kendo.destroy(loading);
                    loading.remove();
                });
            };
            TreeList.prototype._drawPDF_autoPageBreak = function (progress) {
                var treeList = this;
                var result = new $.Deferred();
                var dataSource = treeList.dataSource;
                var allPages = treeList.options.pdf.allPages;
                var origBody = treeList.wrapper.find('table[role="treeList"] > tbody');
                var cont = $('<div>').css({
                    position: 'absolute',
                    left: -10000,
                    top: -10000
                });
                var clone = treeList.wrapper.clone().css({
                    height: 'auto',
                    width: 'auto'
                }).appendTo(cont);
                clone.find('.k-grid-content').css({
                    height: 'auto',
                    width: 'auto',
                    overflow: 'visible'
                });
                clone.find('table[role="treeList"], .k-grid-footer table').css({
                    height: 'auto',
                    width: '100%',
                    overflow: 'visible'
                });
                clone.find('.k-grid-pager, .k-grid-toolbar, .k-grouping-header').remove();
                clone.find('.k-grid-header, .k-grid-footer').css({ paddingRight: 0 });
                this._initPDFProgress(progress);
                var body = clone.find('table[role="treeList"] > tbody').empty();
                var startingPage = dataSource.page();
                function resolve() {
                    if (allPages && startingPage !== undefined) {
                        dataSource.one('change', draw);
                        dataSource.page(startingPage);
                    } else {
                        treeList.refresh();
                        draw();
                    }
                }
                function draw() {
                    cont.appendTo(document.body);
                    var options = $.extend({}, treeList.options.pdf, {
                        _destructive: true,
                        progress: function (p) {
                            progress.notify({
                                page: p.page,
                                pageNumber: p.pageNum,
                                progress: 0.5 + p.pageNum / p.totalPages / 2,
                                totalPages: p.totalPages
                            });
                        }
                    });
                    kendo.drawing.drawDOM(clone, options).always(function () {
                        cont.remove();
                    }).then(function (group) {
                        result.resolve(group);
                    }).fail(function (err) {
                        result.reject(err);
                    });
                }
                function renderPage() {
                    var pageNum = dataSource.page();
                    var totalPages = allPages ? dataSource.totalPages() : 1;
                    body.append(origBody.find('tr'));
                    if (pageNum < totalPages) {
                        dataSource.page(pageNum + 1);
                    } else {
                        dataSource.unbind('change', renderPage);
                        resolve();
                    }
                }
                if (allPages) {
                    dataSource.bind('change', renderPage);
                    dataSource.page(1);
                } else {
                    renderPage();
                }
                return result.promise();
            };
        }
        extend(true, kendo.data, {
            TreeListDataSource: TreeListDataSource,
            TreeListModel: TreeListModel
        });
        ui.plugin(TreeList);
        ui.plugin(TreeListPager);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/main', ['kendo.core'], f);
}(function () {
    (function () {
        var kendo = window.kendo, deepExtend = kendo.deepExtend;
        function sqr(value) {
            return value * value;
        }
        var now = Date.now;
        if (!now) {
            now = function () {
                return new Date().getTime();
            };
        }
        function renderSize(size) {
            if (typeof size !== 'string') {
                size += 'px';
            }
            return size;
        }
        function renderPos(pos) {
            var result = [];
            if (pos) {
                var parts = kendo.toHyphens(pos).split('-');
                for (var i = 0; i < parts.length; i++) {
                    result.push('k-pos-' + parts[i]);
                }
            }
            return result.join(' ');
        }
        function arabicToRoman(n) {
            var literals = {
                1: 'i',
                10: 'x',
                100: 'c',
                2: 'ii',
                20: 'xx',
                200: 'cc',
                3: 'iii',
                30: 'xxx',
                300: 'ccc',
                4: 'iv',
                40: 'xl',
                400: 'cd',
                5: 'v',
                50: 'l',
                500: 'd',
                6: 'vi',
                60: 'lx',
                600: 'dc',
                7: 'vii',
                70: 'lxx',
                700: 'dcc',
                8: 'viii',
                80: 'lxxx',
                800: 'dccc',
                9: 'ix',
                90: 'xc',
                900: 'cm',
                1000: 'm'
            };
            var values = [
                1000,
                900,
                800,
                700,
                600,
                500,
                400,
                300,
                200,
                100,
                90,
                80,
                70,
                60,
                50,
                40,
                30,
                20,
                10,
                9,
                8,
                7,
                6,
                5,
                4,
                3,
                2,
                1
            ];
            var roman = '';
            while (n > 0) {
                if (n < values[0]) {
                    values.shift();
                } else {
                    roman += literals[values[0]];
                    n -= values[0];
                }
            }
            return roman;
        }
        function romanToArabic(r) {
            r = r.toLowerCase();
            var digits = {
                i: 1,
                v: 5,
                x: 10,
                l: 50,
                c: 100,
                d: 500,
                m: 1000
            };
            var value = 0, prev = 0;
            for (var i = 0; i < r.length; ++i) {
                var v = digits[r.charAt(i)];
                if (!v) {
                    return null;
                }
                value += v;
                if (v > prev) {
                    value -= 2 * prev;
                }
                prev = v;
            }
            return value;
        }
        function memoize(f) {
            var cache = Object.create(null);
            return function () {
                var id = '';
                for (var i = arguments.length; --i >= 0;) {
                    id += ':' + arguments[i];
                }
                return id in cache ? cache[id] : cache[id] = f.apply(this, arguments);
            };
        }
        function isUnicodeLetter(ch) {
            return RX_UNICODE_LETTER.test(ch);
        }
        function withExit(f, obj) {
            try {
                return f.call(obj, function (value) {
                    throw new Return(value);
                });
            } catch (ex) {
                if (ex instanceof Return) {
                    return ex.value;
                }
                throw ex;
            }
            function Return(value) {
                this.value = value;
            }
        }
        deepExtend(kendo, {
            util: {
                now: now,
                renderPos: renderPos,
                renderSize: renderSize,
                sqr: sqr,
                romanToArabic: romanToArabic,
                arabicToRoman: arabicToRoman,
                memoize: memoize,
                isUnicodeLetter: isUnicodeLetter,
                withExit: withExit
            }
        });
        var RX_UNICODE_LETTER = new RegExp('[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0-\\u08B2\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F8\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA7AD\\uA7B0\\uA7B1\\uA7F7-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB5F\\uAB64\\uAB65\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]');
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/parse-xml', [
        'kendo.core',
        'util/main'
    ], f);
}(function () {
    'use strict';
    var STRING = String.fromCharCode;
    var ENTITIES = {
        'amp': 38,
        'lt': 60,
        'gt': 62,
        'quot': 34,
        'apos': 39,
        'nbsp': 160
    };
    function CODE(str) {
        var out = [];
        for (var i = 0; i < str.length; ++i) {
            out.push(str.charCodeAt(i));
        }
        return out;
    }
    function UCS2(out, code) {
        if (code > 65535) {
            code -= 65536;
            out.push(code >>> 10 & 1023 | 55296, 56320 | code & 1023);
        } else {
            out.push(code);
        }
    }
    var START_CDATA = CODE('<![CDATA[');
    var END_CDATA = CODE(']]>');
    var END_COMMENT = CODE('-->');
    var START_COMMENT = CODE('!--');
    var END_SHORT_TAG = CODE('/>');
    var END_TAG = CODE('</');
    var END_DECLARATION = CODE('?>');
    var QUESTION_MARK = CODE('?');
    var LESS_THAN = CODE('<');
    var GREATER_THAN = CODE('>');
    var SEMICOLON = CODE(';');
    var EQUAL = CODE('=');
    var AMPERSAND = CODE('&');
    var QUOTE = CODE('"');
    var APOSTROPHE = CODE('\'');
    var SHARP = CODE('#');
    var LOWERCASE_X = CODE('x');
    var UPPERCASE_X = CODE('X');
    var EXIT = {};
    function parse(data, callbacks) {
        var index = 0;
        var stack = [];
        var object = {
            is: function (selector) {
                var i = stack.length, j = selector.length;
                while (--i >= 0 && --j >= 0) {
                    if (stack[i].$tag != selector[j] && selector[j] != '*') {
                        return false;
                    }
                }
                return j < 0 ? stack[stack.length - 1] : null;
            },
            exit: function () {
                throw EXIT;
            },
            stack: stack
        };
        function readChar(body) {
            var code = data[index++];
            if (!(code & 240 ^ 240)) {
                UCS2(body, (code & 3) << 18 | (data[index++] & 63) << 12 | (data[index++] & 63) << 6 | data[index++] & 63);
            } else if (!(code & 224 ^ 224)) {
                UCS2(body, (code & 15) << 12 | (data[index++] & 63) << 6 | data[index++] & 63);
            } else if (!(code & 192 ^ 192)) {
                UCS2(body, (code & 31) << 6 | data[index++] & 63);
            } else {
                body.push(code);
            }
        }
        function croak(msg) {
            throw new Error(msg + ', at ' + index);
        }
        function readWhile(pred) {
            var a = [];
            while (index < data.length && pred(data[index])) {
                a.push(data[index++]);
            }
            return a;
        }
        function readAsciiWhile(pred) {
            return STRING.apply(0, readWhile(pred));
        }
        function skipWhitespace() {
            readWhile(isWhitespace);
        }
        function eat(a) {
            var save = index;
            for (var i = 0; i < a.length; ++i) {
                if (data[index++] != a[i]) {
                    index = save;
                    return false;
                }
            }
            return a;
        }
        function skip(code) {
            if (!eat(code)) {
                croak('Expecting ' + code.join(', '));
            }
        }
        function isWhitespace(code) {
            return code == 9 || code == 10 || code == 13 || code == 32;
        }
        function isDigit(code) {
            return code >= 48 && code <= 57;
        }
        function isHexDigit(code) {
            return code >= 48 && code <= 57 || (code |= 32) >= 97 && code <= 102;
        }
        function isNameStart(code) {
            return code == 58 || code == 95 || (code |= 32) >= 97 && code <= 122;
        }
        function isName(code) {
            return code == 45 || isDigit(code) || isNameStart(code);
        }
        function xmlComment() {
            var body = [];
            while (index < data.length) {
                if (eat(END_COMMENT)) {
                    return call('comment', STRING.apply(0, body));
                }
                readChar(body);
            }
        }
        function xmlTag() {
            var name, attrs;
            if (eat(QUESTION_MARK)) {
                xmlDecl();
            } else if (eat(START_COMMENT)) {
                xmlComment();
            } else {
                name = xmlName();
                attrs = xmlAttrs(name);
                stack.push(attrs);
                if (eat(END_SHORT_TAG)) {
                    call('enter', name, attrs, true);
                } else {
                    skip(GREATER_THAN);
                    call('enter', name, attrs);
                    xmlContent(name);
                    if (name != xmlName()) {
                        croak('Bad closing tag');
                    }
                    call('leave', name, attrs);
                    skipWhitespace();
                    skip(GREATER_THAN);
                }
                stack.pop();
            }
        }
        function xmlContent(name) {
            var body = [];
            while (index < data.length) {
                if (eat(END_TAG)) {
                    return body.length && call('text', STRING.apply(0, body));
                } else if (eat(START_CDATA)) {
                    while (index < data.length && !eat(END_CDATA)) {
                        readChar(body);
                    }
                } else if (eat(LESS_THAN)) {
                    if (body.length) {
                        call('text', STRING.apply(0, body));
                    }
                    xmlTag();
                    body = [];
                } else if (eat(AMPERSAND)) {
                    xmlEntity(body);
                } else {
                    readChar(body);
                }
            }
            croak('Unclosed tag ' + name);
        }
        function xmlName() {
            if (!isNameStart(data[index])) {
                croak('Expecting XML name');
            }
            return readAsciiWhile(isName);
        }
        function xmlString() {
            var quote = eat(QUOTE) || eat(APOSTROPHE);
            if (!quote) {
                croak('Expecting string');
            }
            var body = [];
            while (index < data.length) {
                if (eat(quote)) {
                    return STRING.apply(0, body);
                } else if (eat(AMPERSAND)) {
                    xmlEntity(body);
                } else {
                    readChar(body);
                }
            }
            croak('Unfinished string');
        }
        function xmlEntity(body) {
            var code;
            if (eat(SHARP)) {
                if (eat(LOWERCASE_X) || eat(UPPERCASE_X)) {
                    code = parseInt(readAsciiWhile(isHexDigit), 16);
                } else {
                    code = parseInt(readAsciiWhile(isDigit), 10);
                }
                if (isNaN(code)) {
                    croak('Bad numeric entity');
                }
            } else {
                var name = xmlName();
                code = ENTITIES[name];
                if (code === undefined) {
                    croak('Unknown entity ' + name);
                }
            }
            UCS2(body, code);
            skip(SEMICOLON);
        }
        function xmlDecl() {
            call('decl', xmlName(), xmlAttrs());
            skip(END_DECLARATION);
        }
        function xmlAttrs(name) {
            var map = { $tag: name };
            while (index < data.length) {
                skipWhitespace();
                var code = data[index];
                if (code == 63 || code == 62 || code == 47) {
                    break;
                }
                map[xmlName()] = (skip(EQUAL), xmlString());
            }
            return map;
        }
        function call(what, thing, arg1, arg2) {
            var f = callbacks && callbacks[what];
            if (f) {
                f.call(object, thing, arg1, arg2);
            }
        }
        var tmp = [];
        readChar(tmp);
        if (tmp[0] != 65279) {
            index = 0;
        }
        while (index < data.length) {
            skipWhitespace();
            skip(LESS_THAN);
            xmlTag();
            skipWhitespace();
        }
    }
    kendo.util.parseXML = function parseXML() {
        try {
            return parse.apply(this, arguments);
        } catch (ex) {
            if (ex !== EXIT) {
                throw ex;
            }
        }
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/commands', [
        'kendo.core',
        'kendo.binder',
        'kendo.window',
        'kendo.list',
        'kendo.tabstrip'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var COMMAND_TYPES = {
            AUTO_FILL: 'autoFill',
            CLEAR: 'clear',
            CUT: 'cut',
            EDIT: 'edit',
            PASTE: 'paste',
            VALIDATION: 'validation'
        };
        var Command = kendo.spreadsheet.Command = kendo.Class.extend({
            init: function (options) {
                this.options = options;
                this._workbook = options.workbook;
                this._property = options && options.property;
                this._state = {};
            },
            range: function (range) {
                if (range !== undefined) {
                    this._setRange(range);
                }
                return this._range;
            },
            _setRange: function (range) {
                this._range = range;
            },
            redo: function () {
                this.range().select();
                this.exec();
            },
            undo: function () {
                this.setState(this._state);
            },
            getState: function () {
                this._state = this.range().getState(this._property);
            },
            setState: function (state) {
                this.range().setState(state);
            },
            rejectState: function (validationState) {
                this.undo();
                return {
                    title: validationState.title,
                    body: validationState.message,
                    reason: 'error',
                    type: 'validationError'
                };
            },
            _forEachCell: function (callback) {
                var range = this.range();
                var ref = range._ref;
                ref.forEach(function (ref) {
                    range.sheet().forEach(ref.toRangeRef(), callback.bind(this));
                }.bind(this));
            },
            usesImage: function () {
                return false;
            }
        });
        kendo.spreadsheet.DrawingUpdateCommand = Command.extend({
            init: function (options) {
                this._sheet = options.sheet;
                this._drawing = options.drawing;
                this._orig = this._drawing.clone();
                this._previous = options.previous;
            },
            exec: function () {
            },
            undo: function () {
                this._drawing.reset(this._previous);
                this._sheet._activeDrawing = this._drawing;
                this._sheet.triggerChange({ layout: true });
            },
            redo: function () {
                this._drawing.reset(this._orig);
                this._sheet._activeDrawing = this._drawing;
                this._sheet.triggerChange({ layout: true });
            },
            usesImage: function (img) {
                return this._drawing.image === img || this._orig.image === img || this._previous.image === img;
            }
        });
        var DrawingCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._drawing = options.drawing;
            },
            usesImage: function (img) {
                return this._drawing.image === img;
            }
        });
        kendo.spreadsheet.InsertImageCommand = DrawingCommand.extend({
            init: function (options) {
                DrawingCommand.fn.init.call(this, options);
                this._blob = options.blob;
                this._width = options.width;
                this._height = options.height;
            },
            exec: function () {
                var range = this.range();
                var sheet = range.sheet();
                var width = this._width;
                var height = this._height;
                var aspect = width / height;
                if (width > height) {
                    width = Math.min(width, 300);
                    height = width / aspect;
                } else {
                    height = Math.min(height, 300);
                    width = height * aspect;
                }
                this._drawing = sheet.addDrawing({
                    topLeftCell: range.topLeft(),
                    offsetX: 5,
                    offsetY: 5,
                    width: width,
                    height: height,
                    opacity: 1,
                    image: this._workbook.addImage(this._blob)
                }, true);
                this._blob = null;
            },
            undo: function () {
                var sheet = this.range().sheet();
                sheet._activeDrawing = null;
                sheet.removeDrawing(this._drawing);
            },
            redo: function () {
                var sheet = this.range().sheet();
                sheet._activeDrawing = this._drawing;
                sheet.addDrawing(this._drawing);
            }
        });
        kendo.spreadsheet.DeleteDrawingCommand = DrawingCommand.extend({
            exec: function () {
                var sheet = this.range().sheet();
                sheet._activeDrawing = null;
                sheet.removeDrawing(this._drawing);
            },
            undo: function () {
                var sheet = this.range().sheet();
                sheet._activeDrawing = this._drawing;
                sheet.addDrawing(this._drawing);
            },
            redo: function () {
                this.exec();
            }
        });
        var ReorderDrawingsCommand = DrawingCommand.extend({
            exec: function () {
                var sheet = this.range().sheet();
                this._origIndex = sheet._drawings.indexOf(this._drawing);
                sheet._drawings.splice(this._origIndex, 1);
                this._newIndex = this._reorder();
                sheet._drawings.splice(this._newIndex, 0, this._drawing);
                sheet.triggerChange({ drawings: true });
            },
            undo: function () {
                var sheet = this.range().sheet();
                sheet._drawings.splice(this._newIndex, 1);
                sheet._drawings.splice(this._origIndex, 0, this._drawing);
                sheet.triggerChange({ drawings: true });
            }
        });
        kendo.spreadsheet.BringToFrontCommand = ReorderDrawingsCommand.extend({
            _reorder: function () {
                return this.range().sheet()._drawings.length;
            }
        });
        kendo.spreadsheet.SendToBackCommand = ReorderDrawingsCommand.extend({
            _reorder: function () {
                return 0;
            }
        });
        var TargetValueCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._target = options.target;
                this._value = options.value;
            },
            exec: function () {
                this.getState();
                this.setState(this._value);
            }
        });
        kendo.spreadsheet.ColumnWidthCommand = TargetValueCommand.extend({
            getState: function () {
                this._state = this.range().sheet().columnWidth(this._target);
            },
            setState: function (state) {
                this.range().sheet().columnWidth(this._target, state);
            }
        });
        kendo.spreadsheet.RowHeightCommand = TargetValueCommand.extend({
            getState: function () {
                this._state = this.range().sheet().rowHeight(this._target);
            },
            setState: function (state) {
                this.range().sheet().rowHeight(this._target, state);
            }
        });
        kendo.spreadsheet.HyperlinkCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._link = options.link;
            },
            exec: function () {
                var range = this.range();
                this._prevLink = range.link();
                this._prevUnderline = range.underline();
                range.link(this._link);
                range.underline(true);
                if (range.value() == null) {
                    this._hasSetValue = true;
                    range.value(this._link);
                }
            },
            undo: function () {
                var range = this.range();
                range.link(this._prevLink);
                range.underline(this._prevUnderline);
                if (this._hasSetValue) {
                    range.value(null);
                }
            }
        });
        kendo.spreadsheet.GridLinesChangeCommand = TargetValueCommand.extend({
            getState: function () {
                this._state = this._range.sheet().showGridLines();
            },
            setState: function (v) {
                this._range.sheet().showGridLines(v);
            }
        });
        var PropertyChangeCommand = kendo.spreadsheet.PropertyChangeCommand = Command.extend({
            _setRange: function (range) {
                Command.prototype._setRange.call(this, range.skipHiddenCells());
            },
            init: function (options) {
                Command.fn.init.call(this, options);
                this._value = options.value;
            },
            exec: function () {
                var range = this.range();
                if (range.enable()) {
                    this.getState();
                    if (this.options.property === 'format') {
                        this._workbook.trigger('changeFormat', { range: range });
                    }
                    range[this._property](this._value);
                }
            }
        });
        kendo.spreadsheet.ClearContentCommand = Command.extend({
            exec: function () {
                var values = [], range, rowValues, nullValues, validationState, currentRange;
                if (!this.range().enable()) {
                    return {
                        reason: 'error',
                        type: 'cannotModifyDisabled'
                    };
                }
                if (!this.range().canEditArrayFormula()) {
                    return {
                        reason: 'error',
                        type: 'intersectsArray'
                    };
                }
                this.getState();
                range = this.range().skipHiddenCells();
                if (range._ref.refs && range._ref.refs.length > 1) {
                    range._ref.refs.forEach(function (ref) {
                        currentRange = range.sheet().range(ref);
                        values = values.concat(currentRange.values());
                    });
                } else {
                    values = range.values();
                }
                nullValues = [];
                values.forEach(function (row) {
                    rowValues = [];
                    row.forEach(function () {
                        rowValues.push(null);
                    });
                    nullValues.push(rowValues);
                });
                if (range.sheet().trigger('changing', {
                        data: nullValues,
                        range: range,
                        changeType: COMMAND_TYPES.CLEAR
                    })) {
                    return;
                }
                range.clearContent();
                validationState = range._getValidationState();
                if (validationState) {
                    return this.rejectState(validationState);
                }
            },
            undo: function () {
                var range = this.range().skipHiddenCells();
                var sheet = range.sheet();
                var data = this._state.data;
                var values = [];
                var rowValues;
                data.forEach(function (row) {
                    rowValues = [];
                    row.forEach(function (cell) {
                        rowValues.push(cell.value);
                    });
                    values.push(rowValues);
                });
                if (sheet.trigger('changing', {
                        data: values,
                        range: range,
                        changeType: COMMAND_TYPES.CLEAR
                    })) {
                    return;
                }
                this.setState(this._state);
            }
        });
        kendo.spreadsheet.EditCommand = PropertyChangeCommand.extend({
            init: function (options) {
                options.property = options.property || 'input';
                PropertyChangeCommand.fn.init.call(this, options);
            },
            _setRange: function (range) {
                PropertyChangeCommand.prototype._setRange.apply(this, arguments);
                this._editRange = this.options.arrayFormula ? range : range.sheet().activeCellSelection();
            },
            getState: function () {
                this._state = this.range().getState();
            },
            exec: function () {
                return this.range().sheet().withCultureDecimals(this._exec.bind(this));
            },
            undo: function () {
                var editRange = this._editRange;
                var state = this._state;
                if (editRange.sheet().trigger('changing', {
                        data: state.data[0][0].value,
                        range: editRange,
                        changeType: COMMAND_TYPES.EDIT
                    })) {
                    return;
                }
                this.setState(this._state);
            },
            _exec: function () {
                var arrayFormula = this.options.arrayFormula;
                var editRange = this._editRange;
                if (!editRange.enable()) {
                    return {
                        reason: 'error',
                        type: 'rangeDisabled'
                    };
                }
                if (!editRange.canEditArrayFormula()) {
                    return {
                        reason: 'error',
                        type: 'intersectsArray'
                    };
                }
                var value = this._value;
                this.getState();
                if (this.range().sheet().trigger('changing', {
                        data: value,
                        range: this._editRange,
                        changeType: COMMAND_TYPES.EDIT
                    })) {
                    return;
                }
                if (this._property == 'value') {
                    editRange.value(value);
                    return;
                }
                try {
                    editRange.link(null);
                    if (value === '') {
                        editRange.value(null);
                    } else {
                        editRange.input(value, { arrayFormula: arrayFormula });
                        if (/\n/.test(editRange.value())) {
                            editRange.wrap(true);
                        }
                    }
                    editRange._adjustRowHeight();
                    var validationState = editRange._getValidationState();
                    if (validationState) {
                        return this.rejectState(validationState);
                    }
                } catch (ex) {
                    if (ex instanceof kendo.spreadsheet.calc.ParseError) {
                        return {
                            title: 'Error in formula',
                            body: ex + '',
                            reason: 'error'
                        };
                    } else {
                        throw ex;
                    }
                }
            }
        });
        kendo.spreadsheet.InsertCommentCommand = PropertyChangeCommand.extend({
            init: function (options) {
                options.property = 'comment';
                PropertyChangeCommand.fn.init.call(this, options);
            }
        });
        kendo.spreadsheet.TextWrapCommand = PropertyChangeCommand.extend({
            init: function (options) {
                options.property = 'wrap';
                PropertyChangeCommand.fn.init.call(this, options);
                this._value = options.value;
            },
            getState: function () {
                var rowHeight = {};
                this.range().forEachRow(function (range) {
                    var index = range.topLeft().row;
                    rowHeight[index] = range.sheet().rowHeight(index);
                });
                this._state = this.range().getState(this._property);
                this._rowHeight = rowHeight;
            },
            undo: function () {
                var sheet = this.range().sheet();
                var rowHeight = this._rowHeight;
                this.range().setState(this._state);
                for (var row in rowHeight) {
                    sheet.rowHeight(row, rowHeight[row]);
                }
            }
        });
        kendo.spreadsheet.AdjustDecimalsCommand = Command.extend({
            init: function (options) {
                this._delta = options.value;
                options.property = 'format';
                Command.fn.init.call(this, options);
            },
            exec: function () {
                var sheet = this.range().sheet();
                var delta = this._delta;
                var formatting = kendo.spreadsheet.formatting;
                this.getState();
                sheet.batch(function () {
                    this.range().forEachCell(function (row, col, cell) {
                        var format = cell.format;
                        if (!format) {
                            var value = cell.value;
                            if (typeof value == 'number' && /\./.test(value)) {
                                format = '0.' + String(value).split('.')[1].replace(/\d/g, '0');
                            }
                        }
                        if (format || delta > 0) {
                            format = formatting.adjustDecimals(format || '0', delta);
                            sheet.range(row, col).format(format);
                        }
                    });
                }.bind(this));
            }
        });
        kendo.spreadsheet.BorderChangeCommand = Command.extend({
            init: function (options) {
                options.property = 'border';
                Command.fn.init.call(this, options);
                this._type = options.border;
                this._style = options.style;
            },
            _batch: function (f) {
                return this.range().sheet().batch(f, {});
            },
            exec: function () {
                var self = this;
                self.getState();
                self._batch(function () {
                    self[self._type](self._style);
                });
            },
            noBorders: function () {
                this.range().insideBorders(null);
                this.outsideBorders(null);
            },
            allBorders: function (style) {
                this.range().insideBorders(style);
                this.outsideBorders(style);
            },
            leftBorder: function (style) {
                this.range().leftColumn().borderLeft(style);
            },
            rightBorder: function (style) {
                this.range().rightColumn().borderRight(style);
            },
            topBorder: function (style) {
                this.range().topRow().borderTop(style);
            },
            bottomBorder: function (style) {
                this.range().bottomRow().borderBottom(style);
            },
            outsideBorders: function (style) {
                var range = this.range();
                range.leftColumn().borderLeft(style);
                range.topRow().borderTop(style);
                range.rightColumn().borderRight(style);
                range.bottomRow().borderBottom(style);
            },
            insideBorders: function (style) {
                this.range().insideBorders(style);
                this.outsideBorders(null);
            },
            insideHorizontalBorders: function (style) {
                this.range().insideHorizontalBorders(style);
            },
            insideVerticalBorders: function (style) {
                this.range().insideVerticalBorders(style);
            }
        });
        kendo.spreadsheet.MergeCellCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._type = options.value;
            },
            exec: function () {
                this.getState();
                this[this._type]();
            },
            activate: function (ref) {
                this.range().sheet().activeCell(ref);
            },
            getState: function () {
                this._state = this.range().getState();
            },
            undo: function () {
                if (this._type !== 'unmerge') {
                    this.range().unmerge();
                    this.activate(this.range().topLeft());
                }
                this.range().setState(this._state);
            },
            cells: function () {
                var range = this.range();
                var ref = range._ref;
                range.merge();
                this.activate(ref);
            },
            horizontally: function () {
                var ref = this.range().topRow()._ref;
                this.range().forEachRow(function (range) {
                    range.merge();
                });
                this.activate(ref);
            },
            vertically: function () {
                var ref = this.range().leftColumn()._ref;
                this.range().forEachColumn(function (range) {
                    range.merge();
                });
                this.activate(ref);
            },
            unmerge: function () {
                var range = this.range();
                var ref = range._ref.topLeft;
                range.unmerge();
                this.activate(ref);
            }
        });
        kendo.spreadsheet.FreezePanesCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._type = options.value;
            },
            exec: function () {
                this.getState();
                this._topLeft = this.range().topLeft();
                this[this._type]();
            },
            getState: function () {
                this._state = this.range().sheet().getState();
            },
            undo: function () {
                this.range().sheet().setState(this._state);
            },
            panes: function () {
                var topLeft = this._topLeft;
                var sheet = this.range().sheet();
                sheet.frozenColumns(topLeft.col).frozenRows(topLeft.row);
            },
            rows: function () {
                var topLeft = this._topLeft;
                var sheet = this.range().sheet();
                sheet.frozenRows(topLeft.row);
            },
            columns: function () {
                var topLeft = this._topLeft;
                var sheet = this.range().sheet();
                sheet.frozenColumns(topLeft.col);
            },
            unfreeze: function () {
                var sheet = this.range().sheet();
                sheet.frozenRows(0).frozenColumns(0);
            }
        });
        kendo.spreadsheet.PasteCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._clipboard = options.workbook.clipboard();
                this._clipboard.parse();
                this._event = options.event;
                this._clipboardContent = this._clipboard._content;
                this._clipboardPasteRef = this._clipboard.pasteRef();
                this._sheet = this._workbook.activeSheet();
                this._range = this._sheet.range(this._clipboard.pasteRef());
                this._state = this._range.getState();
            },
            exec: function () {
                return this.range().sheet().withCultureDecimals(this._exec.bind(this));
            },
            undo: function () {
                var sheet = this._sheet;
                var range = sheet.range(this._clipboardPasteRef);
                if (sheet.trigger('changing', {
                        data: this._state.data,
                        range: range,
                        changeType: COMMAND_TYPES.PASTE
                    })) {
                    return;
                }
                this.setState(this._state);
            },
            _exec: function () {
                var status = this._clipboard.canPaste();
                if (!status.canPaste) {
                    if (status.menuInvoked) {
                        return {
                            reason: 'error',
                            type: 'useKeyboard'
                        };
                    }
                    if (status.pasteOnMerged) {
                        return {
                            reason: 'error',
                            type: 'modifyMerged'
                        };
                    }
                    if (status.overflow) {
                        return {
                            reason: 'error',
                            type: 'overflow'
                        };
                    }
                    if (status.pasteOnDisabled) {
                        this._event.preventDefault();
                        return {
                            reason: 'error',
                            type: 'cannotModifyDisabled'
                        };
                    }
                    return { reason: 'error' };
                }
                var range = this._sheet.range(this._clipboardPasteRef);
                if (this._workbook.trigger('paste', {
                        range: range,
                        clipboardContent: this._clipboardContent
                    }) || this._sheet.trigger('changing', {
                        data: this._clipboardContent.data,
                        range: range,
                        changeType: COMMAND_TYPES.PASTE
                    })) {
                    this._event.preventDefault();
                    return;
                } else {
                    this._sheet.range(this._clipboardPasteRef).setState(this._clipboardContent, this._clipboard);
                    range._adjustRowHeight();
                }
            }
        });
        kendo.spreadsheet.AdjustRowHeightCommand = Command.extend({
            exec: function () {
                var options = this.options;
                var sheet = this._workbook.activeSheet();
                var range = options.range || sheet.range(options.rowIndex);
                range._adjustRowHeight();
            }
        });
        kendo.spreadsheet.ToolbarPasteCommand = Command.extend({
            exec: function () {
                if (kendo.support.clipboard.paste) {
                    this._workbook._view.clipboard.focus().select();
                    document.execCommand('paste');
                } else {
                    return {
                        reason: 'error',
                        type: 'useKeyboard'
                    };
                }
            }
        });
        kendo.spreadsheet.CutCommand = Command.extend({
            _eventType: 'cut',
            init: function (options) {
                Command.fn.init.call(this, options);
                this._clipboard = options.workbook.clipboard();
                this._event = options.event;
            },
            exec: function () {
                var status = this._clipboard.canCopy();
                var data = [], rangeValues, currentRow;
                if (!status.canCopy) {
                    if (status.menuInvoked) {
                        return {
                            reason: 'error',
                            type: 'useKeyboard'
                        };
                    } else if (status.multiSelection) {
                        return {
                            reason: 'error',
                            type: 'unsupportedSelection'
                        };
                    }
                    return;
                }
                var range = this._workbook.activeSheet().selection();
                if (this._eventType == 'cut') {
                    if (!range.enable()) {
                        this._event.preventDefault();
                        return {
                            reason: 'error',
                            type: 'cannotModifyDisabled'
                        };
                    }
                    this.getState();
                }
                if (this._workbook.trigger(this._eventType, { range: range })) {
                    this._event.preventDefault();
                } else if (this._eventType == 'cut') {
                    rangeValues = range.values();
                    rangeValues.forEach(function (row) {
                        currentRow = [];
                        row.forEach(function () {
                            currentRow.push({});
                        });
                        data.push(currentRow);
                    });
                    if (range.sheet().trigger('changing', {
                            data: data,
                            range: range,
                            changeType: COMMAND_TYPES.CUT
                        })) {
                        return;
                    }
                    this._clipboard.cut();
                } else {
                    this._clipboard.copy();
                }
            },
            undo: function () {
                var range = this.range();
                if (range.sheet().trigger('changing', {
                        data: this._state.data,
                        range: range,
                        changeType: COMMAND_TYPES.CUT
                    })) {
                    return;
                }
                this.setState(this._state);
            }
        });
        kendo.spreadsheet.CopyCommand = kendo.spreadsheet.CutCommand.extend({
            _eventType: 'copy',
            undo: $.noop
        });
        function copyToClipboard(html) {
            var textarea = document.createElement('textarea');
            $(textarea).addClass('k-spreadsheet-clipboard').val(html).appendTo(document.body).focus().select();
            document.execCommand('copy');
            $(textarea).remove();
        }
        kendo.spreadsheet.ToolbarCopyCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._clipboard = options.workbook.clipboard();
            },
            undo: $.noop,
            exec: function () {
                if (kendo.support.clipboard.copy) {
                    var clipboard = this._workbook._view.clipboard;
                    copyToClipboard(clipboard.html());
                    clipboard.trigger('copy');
                } else {
                    return {
                        reason: 'error',
                        type: 'useKeyboard'
                    };
                }
            }
        });
        kendo.spreadsheet.AutoFillCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
            },
            origin: function (origin) {
                this._origin = origin;
            },
            exec: function () {
                var range = this.range(), autoFillData;
                if (!range.enable()) {
                    return {
                        reason: 'error',
                        type: 'rangeDisabled'
                    };
                }
                if (range.intersectingArrayFormula()) {
                    return {
                        reason: 'error',
                        type: 'intersectsArray'
                    };
                }
                this.getState();
                try {
                    autoFillData = range._previewFillFrom(this._origin);
                    if (range.sheet().trigger('changing', {
                            data: autoFillData.props,
                            range: autoFillData.dest,
                            changeType: COMMAND_TYPES.AUTO_FILL
                        })) {
                        return;
                    }
                    autoFillData.dest._properties(autoFillData.props, true);
                } catch (ex) {
                    if (ex instanceof kendo.spreadsheet.Range.FillError) {
                        return {
                            reason: 'error',
                            type: ex.code
                        };
                    }
                    throw ex;
                }
            },
            undo: function () {
                var range = this.range();
                var state = this._state;
                if (range.sheet().trigger('changing', {
                        data: state.data,
                        range: range,
                        changeType: COMMAND_TYPES.AUTO_FILL
                    })) {
                    return;
                }
                this.setState(this._state);
            }
        });
        kendo.spreadsheet.ToolbarCutCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._clipboard = options.workbook.clipboard();
            },
            exec: function () {
                if (kendo.support.clipboard.copy) {
                    var clipboard = this._workbook._view.clipboard;
                    copyToClipboard(clipboard.html());
                    clipboard.trigger('cut');
                } else {
                    return {
                        reason: 'error',
                        type: 'useKeyboard'
                    };
                }
            }
        });
        kendo.spreadsheet.FilterCommand = Command.extend({
            undo: function () {
                this.range().filter(this._state);
            },
            exec: function () {
                var range = this.range();
                this._state = range.hasFilter();
                range.filter(!this._state);
            }
        });
        kendo.spreadsheet.SortCommand = Command.extend({
            undo: function () {
                var sheet = this.range().sheet();
                sheet.setState(this._state);
            },
            exec: function () {
                var range = this.range();
                var sheet = range.sheet();
                var activeCell = sheet.activeCell();
                var col = this.options.sheet ? activeCell.topLeft.col : this.options.column || 0;
                var ascending = this.options.value === 'asc' ? true : false;
                this._state = sheet.getState();
                if (this.options.sheet) {
                    range = this.expandRange();
                }
                var reason = range.cantSort();
                if (reason) {
                    return {
                        reason: 'error',
                        type: reason.code
                    };
                }
                range.sort({
                    column: col,
                    ascending: ascending
                });
            },
            expandRange: function () {
                var sheet = this.range().sheet();
                return new kendo.spreadsheet.Range(sheet._sheetRef, sheet);
            }
        });
        var ApplyFilterCommand = kendo.spreadsheet.ApplyFilterCommand = Command.extend({
            column: function () {
                return this.options.column || 0;
            },
            undo: function () {
                var sheet = this.range().sheet();
                sheet.clearFilter(this.column());
                if (this._state.length) {
                    this.range().filter(this._state);
                }
            },
            getState: function () {
                var sheet = this.range().sheet();
                var current = sheet.filter();
                if (current) {
                    this._state = current.columns.filter(function (c) {
                        return c.index == this.column();
                    }.bind(this));
                }
            },
            exec: function () {
                var range = this.range();
                var column = this.column();
                var current = range.sheet().filter();
                var options;
                var filterRule;
                var exists = false;
                if (this.options.valueFilter) {
                    filterRule = {
                        column: column,
                        filter: new kendo.spreadsheet.ValueFilter(this.options.valueFilter)
                    };
                } else if (this.options.customFilter) {
                    filterRule = {
                        column: column,
                        filter: new kendo.spreadsheet.CustomFilter(this.options.customFilter)
                    };
                }
                this.getState();
                if (current && current.ref.eq(range._ref) && current.columns.length) {
                    current.columns.forEach(function (element) {
                        if (element.index === column) {
                            exists = true;
                        }
                    });
                    options = current.columns.map(function (element) {
                        return element.index === column ? filterRule : {
                            column: element.index,
                            filter: element.filter
                        };
                    });
                    if (!exists) {
                        options.push(filterRule);
                    }
                } else {
                    options = filterRule;
                }
                range.filter(options);
            }
        });
        kendo.spreadsheet.ClearFilterCommand = ApplyFilterCommand.extend({
            exec: function () {
                var range = this.range();
                var column = this.column();
                this.getState();
                range.clearFilter(column);
            }
        });
        kendo.spreadsheet.HideLineCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this.axis = options.axis;
            },
            undo: function () {
                var sheet = this.range().sheet();
                sheet.setAxisState(this._state);
            },
            exec: function () {
                var sheet = this.range().sheet();
                this._state = sheet.getAxisState();
                if (this.axis == 'row') {
                    sheet.axisManager().hideSelectedRows();
                } else {
                    sheet.axisManager().hideSelectedColumns();
                }
            }
        });
        kendo.spreadsheet.UnHideLineCommand = kendo.spreadsheet.HideLineCommand.extend({
            exec: function () {
                var sheet = this.range().sheet();
                this._state = sheet.getAxisState();
                if (this.axis == 'row') {
                    sheet.axisManager().unhideSelectedRows();
                } else {
                    sheet.axisManager().unhideSelectedColumns();
                }
            }
        });
        var DeleteCommand = Command.extend({
            exec: function () {
                this._expandedRange = this._expand(this.range());
                this._state = this._expandedRange.getState();
                this._indexes = this._exec(this._expandedRange.sheet());
            },
            undo: function () {
                var self = this;
                var range = self._expandedRange;
                var sheet = range.sheet();
                sheet.batch(function () {
                    self._indexes.forEach(function (x) {
                        self._undoOne(sheet, x);
                        sheet._restoreModifiedFormulas(x.formulas);
                    });
                    range.setState(self._state);
                }, {
                    layout: true,
                    recalc: true,
                    ref: range._ref
                });
            }
        });
        kendo.spreadsheet.DeleteRowCommand = DeleteCommand.extend({
            _expand: function (range) {
                return range.resize({
                    left: -Infinity,
                    right: +Infinity
                });
            },
            _exec: function (sheet) {
                return sheet.axisManager().deleteSelectedRows();
            },
            _undoOne: function (sheet, x) {
                sheet.insertRow(x.index);
                sheet.rowHeight(x.index, x.height);
            }
        });
        kendo.spreadsheet.DeleteColumnCommand = DeleteCommand.extend({
            _expand: function (range) {
                return range.resize({
                    top: -Infinity,
                    bottom: +Infinity
                });
            },
            _exec: function (sheet) {
                return sheet.axisManager().deleteSelectedColumns();
            },
            _undoOne: function (sheet, x) {
                sheet.insertColumn(x.index);
                sheet.columnWidth(x.index, x.width);
            }
        });
        var AddCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._value = options.value;
            },
            undo: function () {
                var self = this;
                var sheet = self.range().sheet();
                sheet.batch(function () {
                    for (var i = self._pos.count; --i >= 0;) {
                        self._undoOne(sheet, self._pos.base);
                    }
                }, {
                    layout: true,
                    recalc: true
                });
            }
        });
        kendo.spreadsheet.AddColumnCommand = AddCommand.extend({
            exec: function () {
                var sheet = this.range().sheet();
                var result = sheet.axisManager().preventAddColumn();
                if (result) {
                    return result;
                }
                if (this._value === 'left') {
                    this._pos = sheet.axisManager().addColumnLeft();
                } else {
                    this._pos = sheet.axisManager().addColumnRight();
                }
            },
            _undoOne: function (sheet, index) {
                sheet.deleteColumn(index);
            }
        });
        kendo.spreadsheet.AddRowCommand = AddCommand.extend({
            exec: function () {
                var sheet = this.range().sheet();
                var result = sheet.axisManager().preventAddRow();
                if (result) {
                    return result;
                }
                if (this._value === 'above') {
                    this._pos = sheet.axisManager().addRowAbove();
                } else {
                    this._pos = sheet.axisManager().addRowBelow();
                }
            },
            _undoOne: function (sheet, index) {
                sheet.deleteRow(index);
            }
        });
        kendo.spreadsheet.EditValidationCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._value = options.value;
            },
            exec: function () {
                var self = this, sheet = self.range().sheet();
                this.getState();
                if (sheet.trigger('changing', {
                        data: self._value,
                        range: self.range(),
                        changeType: COMMAND_TYPES.VALIDATION
                    })) {
                    return;
                }
                sheet.withCultureDecimals(function () {
                    self.range().validation(self._value);
                });
            },
            undo: function () {
                var editRange = this.range();
                var state = this._state;
                if (editRange.sheet().trigger('changing', {
                        data: state.data[0][0].validation,
                        range: editRange,
                        changeType: COMMAND_TYPES.VALIDATION
                    })) {
                    return;
                }
                this.setState(this._state);
            }
        });
        kendo.spreadsheet.OpenCommand = Command.extend({
            cannotUndo: true,
            exec: function () {
                var file = this.options.file;
                if (file.name.match(/.xlsx$/i) === null) {
                    return {
                        reason: 'error',
                        type: 'openUnsupported'
                    };
                }
                var workbook = this.options.workbook;
                workbook.fromFile(this.options.file).then(function () {
                    var errors = workbook.excelImportErrors;
                    if (errors && errors.length) {
                        workbook._view.openDialog('importError', { errors: errors });
                    }
                });
            }
        });
        kendo.spreadsheet.SaveAsCommand = Command.extend({
            exec: function () {
                var fileName = this.options.name + this.options.extension;
                if (this.options.extension === '.xlsx') {
                    this.options.workbook.saveAsExcel({ fileName: fileName });
                } else if (this.options.extension === '.pdf') {
                    this.options.workbook.saveAsPDF($.extend(this.options.pdf, {
                        workbook: this.options.workbook,
                        fileName: fileName
                    }));
                }
            }
        });
        var NameCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._name = options.name;
                this._value = options.value;
            },
            getState: function () {
                this._state = this._workbook.nameDefinition(this._name);
            },
            setState: function () {
                this._workbook.nameDefinition(this._name, this._state);
                this._workbook.trigger('change', { recalc: true });
            }
        });
        kendo.spreadsheet.DefineNameCommand = NameCommand.extend({
            exec: function () {
                this.getState();
                try {
                    this._workbook.defineName(this._name, this._value);
                    this._workbook.trigger('change', { recalc: true });
                } catch (ex) {
                    return {
                        title: 'Error',
                        body: ex + '',
                        reason: 'error'
                    };
                }
            }
        });
        kendo.spreadsheet.DeleteNameCommand = NameCommand.extend({
            exec: function () {
                this.getState();
                this._workbook.undefineName(this._name);
                this._workbook.trigger('change', { recalc: true });
            }
        });
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/formulabar', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var classNames = { wrapper: 'k-spreadsheet-formula-bar' };
        var FormulaBar = kendo.ui.Widget.extend({
            init: function (element, options) {
                kendo.ui.Widget.call(this, element, options);
                element = this.element.addClass(FormulaBar.classNames.wrapper);
                this.formulaInput = new kendo.spreadsheet.FormulaInput($('<div/>').appendTo(element));
            },
            destroy: function () {
                if (this.formulaInput) {
                    this.formulaInput.destroy();
                }
                this.formulaInput = null;
            }
        });
        kendo.spreadsheet.FormulaBar = FormulaBar;
        $.extend(true, FormulaBar, { classNames: classNames });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/formulainput', ['kendo.core'], f);
}(function () {
    (function (kendo, window) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var Widget = kendo.ui.Widget;
        var ns = '.kendoFormulaInput';
        var keys = kendo.keys;
        var classNames = {
            wrapper: 'k-spreadsheet-formula-input',
            listWrapper: 'k-spreadsheet-formula-list'
        };
        var styles = [
            'font-family',
            'font-size',
            'font-stretch',
            'font-style',
            'font-weight',
            'letter-spacing',
            'text-transform',
            'line-height'
        ];
        var KEY_NAMES = {
            27: 'esc',
            37: 'left',
            39: 'right',
            35: 'end',
            36: 'home',
            32: 'spacebar'
        };
        var PRIVATE_FORMULA_CHECK = /(^_|[^a-z0-9]$)/i;
        var FormulaInput = Widget.extend({
            init: function (element, options) {
                Widget.call(this, element, options);
                element = this.element;
                element.addClass(FormulaInput.classNames.wrapper).attr('contenteditable', true).attr('spellcheck', false).css('white-space', 'pre');
                if (this.options.autoScale) {
                    element.on('input', this.scale.bind(this));
                }
                this._highlightedRefs = [];
                this._staticTokens = [];
                this._formulaSource();
                this._formulaList();
                this._popup();
                this._tooltip();
                element.on('keydown', this._keydown.bind(this)).on('keyup', this._keyup.bind(this)).on('blur', this._blur.bind(this)).on('input click', this._input.bind(this)).on('focus', this._focus.bind(this)).on('paste', this._paste.bind(this));
            },
            options: {
                name: 'FormulaInput',
                autoScale: false,
                filterOperator: 'startswith',
                scalePadding: 30,
                minLength: 1
            },
            events: [
                'keyup',
                'focus'
            ],
            enable: function (enable) {
                if (enable === undefined) {
                    return this.element.attr('contenteditable') === 'true';
                }
                if (enable) {
                    this.element.attr('contenteditable', enable);
                } else {
                    this.element.removeAttr('contenteditable');
                }
                this.element.toggleClass('k-state-disabled', !enable);
            },
            getPos: function () {
                var div = this.element[0];
                var sel = window.getSelection();
                var a = lookup(sel.focusNode, sel.focusOffset);
                var b = lookup(sel.anchorNode, sel.anchorOffset);
                if (a != null && b != null) {
                    if (a > b) {
                        var tmp = a;
                        a = b;
                        b = tmp;
                    }
                    return {
                        begin: a,
                        end: b,
                        collapsed: a == b
                    };
                }
                function lookup(lookupNode, pos) {
                    try {
                        (function loop(node) {
                            if (node === lookupNode) {
                                throw pos;
                            } else if (node.nodeType == 1) {
                                for (var i = node.firstChild; i; i = i.nextSibling) {
                                    loop(i);
                                }
                            } else if (node.nodeType == 3) {
                                pos += node.nodeValue.length;
                            }
                        }(div));
                    } catch (index) {
                        return index;
                    }
                }
            },
            setPos: function (begin, end) {
                var eiv = this.element[0];
                begin = lookup(eiv, begin);
                if (end != null) {
                    end = lookup(eiv, end);
                } else {
                    end = begin;
                }
                if (begin && end) {
                    var range = document.createRange();
                    range.setStart(begin.node, begin.pos);
                    range.setEnd(end.node, end.pos);
                    var sel = window.getSelection();
                    var currentRange = sel.getRangeAt(0);
                    if (differ(range, currentRange)) {
                        sel.removeAllRanges();
                        sel.addRange(range);
                    }
                }
                function differ(a, b) {
                    return a.startOffset != b.startOffset || a.endOffset != b.endOffset || a.startContainer != b.endContainer || a.endContainer != b.endContainer;
                }
                function lookup(node, pos) {
                    try {
                        (function loop(node) {
                            if (node.nodeType == 3) {
                                var len = node.nodeValue.length;
                                if (len >= pos) {
                                    throw node;
                                }
                                pos -= len;
                            } else if (node.nodeType == 1) {
                                for (var i = node.firstChild; i; i = i.nextSibling) {
                                    loop(i);
                                }
                            }
                        }(node));
                    } catch (el) {
                        return {
                            node: el,
                            pos: pos
                        };
                    }
                }
            },
            end: function () {
                this.setPos(this.length());
            },
            home: function () {
                this.setPos(0);
            },
            select: function () {
                this.setPos(0, this.length());
            },
            length: function () {
                return this.value().length;
            },
            _formulaSource: function () {
                var result = [];
                var value;
                for (var key in kendo.spreadsheet.calc.runtime.FUNCS) {
                    if (!PRIVATE_FORMULA_CHECK.test(key)) {
                        value = key.toUpperCase();
                        result.push({
                            value: value,
                            text: value
                        });
                    }
                }
                this.formulaSource = new kendo.data.DataSource({ data: result });
            },
            _formulaList: function () {
                this.list = new kendo.ui.StaticList($('<ul />').addClass(FormulaInput.classNames.listWrapper).insertAfter(this.element), {
                    autoBind: false,
                    selectable: true,
                    change: this._formulaListChange.bind(this),
                    dataSource: this.formulaSource,
                    dataValueField: 'value',
                    template: '#:data.value#'
                });
                this.list.element.on('mousedown', function (e) {
                    e.preventDefault();
                });
            },
            _formulaListChange: function () {
                var tokenCtx = this._tokenContext();
                if (!tokenCtx || this._mute) {
                    return;
                }
                var activeToken = tokenCtx.token;
                var completion = this.list.value()[0];
                var ctx = {
                    replace: true,
                    token: activeToken,
                    end: activeToken.end
                };
                if (!tokenCtx.nextToken || tokenCtx.nextToken.value != '(') {
                    completion += '(';
                }
                this._replaceAt(ctx, completion);
                this.popup.close();
            },
            _popup: function () {
                this.popup = new kendo.ui.Popup(this.list.element, { anchor: this.element });
            },
            _blur: function () {
                this.popup.close();
                clearTimeout(this._focusId);
                this.trigger('blur');
            },
            _isFormula: function () {
                return /^=/.test(this.value());
            },
            _keydown: function (e) {
                var key = e.keyCode;
                if (KEY_NAMES[key]) {
                    this.popup.close();
                    this._navigated = true;
                } else if (this._move(key)) {
                    this._navigated = true;
                    e.preventDefault();
                }
                this._keyDownTimeout = setTimeout(this._syntaxHighlight.bind(this));
            },
            _keyup: function () {
                var popup = this.popup;
                var value;
                if (this._isFormula() && !this._navigated) {
                    value = ((this._tokenContext() || {}).token || {}).value;
                    this.filter(value);
                    if (!value || !this.formulaSource.view().length) {
                        popup.close();
                    } else {
                        popup[popup.visible() ? 'position' : 'open']();
                        this.list.focusFirst();
                    }
                }
                this._navigated = false;
                this._syntaxHighlight();
                this.trigger('keyup');
            },
            _input: function () {
                this._syntaxHighlight();
            },
            _focus: function () {
                setTimeout(this._sync.bind(this));
                this._focusTimeout = setTimeout(this._syntaxHighlight.bind(this));
                this.trigger('focus');
            },
            _paste: function (ev) {
                ev.preventDefault();
                var pos = this.getPos();
                var text;
                if (kendo.support.browser.msie) {
                    text = window.clipboardData.getData('Text');
                } else {
                    text = ev.originalEvent.clipboardData.getData('text/plain');
                }
                var val = this.value();
                val = val.substr(0, pos.begin) + text + val.substr(pos.end);
                this.value(val);
                this.setPos(pos.begin + text.length);
                this.scale();
            },
            _move: function (key) {
                var list = this.list;
                var popup = this.popup;
                if (popup.visible()) {
                    if (key === keys.DOWN) {
                        list.focusNext();
                        if (!list.focus()) {
                            list.focusFirst();
                        }
                        return true;
                    }
                    if (key === keys.UP) {
                        list.focusPrev();
                        if (!list.focus()) {
                            list.focusLast();
                        }
                        return true;
                    }
                    if (key === keys.ENTER) {
                        list.select(list.focus());
                        popup.close();
                        return true;
                    }
                    if (key === keys.TAB) {
                        list.select(list.focus());
                        popup.close();
                        return true;
                    }
                    if (key === keys.PAGEUP) {
                        list.focusFirst();
                        return true;
                    }
                    if (key === keys.PAGEDOWN) {
                        list.focusLast();
                        return true;
                    }
                }
                return key === keys.ENTER || key === keys.TAB;
            },
            _tokenContext: function () {
                var point = this.getPos();
                var value = this.value();
                if (!value || !point || !point.collapsed) {
                    return null;
                }
                var tokens = kendo.spreadsheet.calc.tokenize(value, this.row(), this.col());
                var tok;
                for (var i = 0; i < tokens.length; ++i) {
                    tok = tokens[i];
                    if (touches(tok, point) && /^(?:str|sym|func)$/.test(tok.type)) {
                        return {
                            token: tok,
                            nextToken: tokens[i + 1]
                        };
                    }
                }
                return null;
            },
            _sync: function () {
                if (this._editorToSync && this.isActive()) {
                    this._editorToSync.value(this.value());
                }
            },
            _textContainer: function () {
                var computedStyles = kendo.getComputedStyles(this.element[0], styles);
                computedStyles.position = 'absolute';
                computedStyles.visibility = 'hidden';
                computedStyles.whiteSpace = 'pre';
                computedStyles.top = -3333;
                computedStyles.left = -3333;
                this._span = $('<span style=\'white-space: pre\'/>').css(computedStyles).insertAfter(this.element);
            },
            _tooltip: function () {
                this._cellTooltip = $('<div class="k-widget k-tooltip" style="position:absolute; display:none">A1</div>').insertAfter(this.element);
            },
            tooltip: function (value) {
                this._cellTooltip.text(value);
            },
            toggleTooltip: function (show) {
                this._cellTooltip.toggle(show);
            },
            isActive: function () {
                return this.element[0] === kendo._activeElement();
            },
            filter: function (value) {
                if (!value || value.length < this.options.minLength) {
                    return;
                }
                this._mute = true;
                this.list.select(-1);
                this._mute = false;
                this.formulaSource.filter({
                    field: this.list.options.dataValueField,
                    operator: this.options.filterOperator,
                    value: value
                });
            },
            hide: function () {
                this.enable(false);
                this.element.hide();
                this._cellTooltip.hide();
            },
            show: function () {
                this.enable(true);
                this.element.show();
            },
            row: function () {
                if (this.activeCell) {
                    return this.activeCell.row;
                }
            },
            col: function () {
                if (this.activeCell) {
                    return this.activeCell.col;
                }
            },
            position: function (rectangle) {
                if (!rectangle) {
                    return;
                }
                this.show();
                this.element.css({
                    'top': rectangle.top + 1 + 'px',
                    'left': rectangle.left + 1 + 'px'
                });
                this._cellTooltip.css({
                    'top': rectangle.top - this._cellTooltip.height() - 10 + 'px',
                    'left': rectangle.left
                });
            },
            resize: function (rectangle) {
                if (!rectangle) {
                    return;
                }
                this.element.css({
                    width: rectangle.width - 1,
                    height: rectangle.height - 1
                });
            },
            canInsertRef: function (isKeyboardAction) {
                var result = this._canInsertRef(isKeyboardAction);
                var token = result && result.token;
                var idx;
                if (token) {
                    for (idx = 0; idx < this._staticTokens.length; idx++) {
                        if (isEqualToken(token, this._staticTokens[idx])) {
                            return null;
                        }
                    }
                }
                return result;
            },
            _canInsertRef: function (isKeyboardAction) {
                if (this.popup.visible()) {
                    return null;
                }
                var strictMode = isKeyboardAction;
                var point = this.getPos();
                var tokens, tok;
                if (point && this._isFormula()) {
                    if (point.begin === 0) {
                        return null;
                    }
                    tokens = kendo.spreadsheet.calc.tokenize(this.value(), this.row(), this.col());
                    for (var i = 0; i < tokens.length; ++i) {
                        tok = tokens[i];
                        if (touches(tok, point)) {
                            return canReplace(tok);
                        }
                        if (afterPoint(tok)) {
                            return canInsertBetween(tokens[i - 1], tok);
                        }
                    }
                    return canInsertBetween(tok, null);
                }
                return null;
                function afterPoint(tok) {
                    return tok.begin > point.begin;
                }
                function canReplace(tok) {
                    if (tok) {
                        if (/^(?:num|str|bool|sym|ref)$/.test(tok.type)) {
                            return {
                                replace: true,
                                token: tok,
                                end: tok.end
                            };
                        }
                        if (/^(?:op|punc|startexp)$/.test(tok.type)) {
                            if (tok.end == point.end) {
                                return canInsertBetween(tok, tokens[i + 1]);
                            }
                            return canInsertBetween(tokens[i - 1], tok);
                        }
                    }
                }
                function canInsertBetween(left, right) {
                    if (left == null) {
                        return null;
                    }
                    if (right == null) {
                        if (/^(?:op|startexp)$/.test(left.type) || isOpenParen(left.value)) {
                            return {
                                token: left,
                                end: point.end
                            };
                        }
                        return null;
                    }
                    if (strictMode) {
                        if (left.type == 'op' && /^(?:punc|op)$/.test(right.type)) {
                            return {
                                token: left,
                                end: point.end
                            };
                        }
                    } else {
                        if (left.type == 'startexp') {
                            return {
                                token: left,
                                end: point.end
                            };
                        }
                        if (/^(?:op|punc)$/.test(left.type) && /^[,;({]$/.test(left.value)) {
                            return {
                                token: left,
                                end: point.end
                            };
                        }
                        if (/^(?:ref|sym)/.test(left.type)) {
                            return {
                                token: left,
                                replace: true,
                                end: left.end
                            };
                        }
                        if (/^(?:ref|sym)/.test(right.type)) {
                            return {
                                token: right,
                                replace: true,
                                end: right.end
                            };
                        }
                    }
                    return false;
                }
            },
            refAtPoint: function (sheet) {
                var x = this._canInsertRef();
                if (x) {
                    var ref = sheet.selection()._ref.simplify().clone().relative(0, 0, 3);
                    if (sheet !== this.activeSheet) {
                        ref = ref.setSheet(sheet.name(), true);
                    }
                    this._replaceAt(x, ref.print(0, 0));
                }
            },
            _replaceAt: function (ctx, newValue) {
                var value = this.value();
                var tok = ctx.token;
                var rest = value.substr(ctx.end);
                value = value.substr(0, ctx.replace ? tok.begin : ctx.end) + newValue;
                var point = value.length;
                value += rest;
                this._value(value);
                this.setPos(point);
                this.scale();
                this._syntaxHighlight();
            },
            syncWith: function (formulaInput) {
                var self = this;
                var eventName = 'input' + ns;
                var handler = self._sync.bind(self), iehandler;
                if (kendo.support.browser.msie) {
                    eventName = 'keydown' + ns;
                    iehandler = function () {
                        setTimeout(handler);
                    };
                }
                self._editorToSync = formulaInput;
                self.element.off(eventName).on(eventName, iehandler || handler);
            },
            scale: function () {
                var element = this.element;
                var width, height;
                if (!this._span) {
                    this._textContainer();
                }
                this._span.html(element.html());
                width = this._span.width() + this.options.scalePadding;
                height = this._span.height();
                if (width > element.width()) {
                    element.width(width);
                }
                if (height > element.height()) {
                    element.height(height);
                }
                this._sync();
            },
            _value: function (value) {
                this.element.text(value);
            },
            value: function (value) {
                if (value === undefined) {
                    var txt = this.element[0].innerText;
                    return txt.replace(/\n$/, '');
                }
                this._value(value);
                this._syntaxHighlight();
            },
            highlightedRefs: function () {
                return this._highlightedRefs.slice();
            },
            _syntaxHighlight: function () {
                var pos = this.getPos();
                var value = this.value();
                var refClasses = kendo.spreadsheet.Pane.classNames.series;
                var highlightedRefs = [];
                var refIndex = 0;
                var parens = [];
                var tokens = [];
                var activeToken;
                if (pos && !pos.collapsed) {
                    return;
                }
                if (!/^=/.test(value)) {
                    if (this._staticTokens.length || this._highlightedRefs.length) {
                        this._staticTokens = [];
                        this._highlightedRefs = [];
                        this.element.text(value);
                    }
                    if (this.popup) {
                        this.popup.close();
                    }
                    return;
                } else {
                    tokens = kendo.spreadsheet.calc.tokenize(value, this.row(), this.col());
                    tokens.forEach(function (tok) {
                        tok.active = false;
                        tok.cls = ['k-syntax-' + tok.type];
                        if (tok.type == 'ref') {
                            tok.colorClass = refClasses[refIndex++ % refClasses.length];
                            tok.cls.push(tok.colorClass);
                            highlightedRefs.push(tok);
                        }
                        if (pos && tok.type == 'punc') {
                            if (isOpenParen(tok.value)) {
                                parens.unshift(tok);
                            } else if (isCloseParen(tok.value)) {
                                var open = parens.shift();
                                if (open) {
                                    if (isMatchingParen(tok.value, open.value)) {
                                        if (touches(tok, pos) || touches(open, pos)) {
                                            tok.cls.push('k-syntax-paren-match');
                                            open.cls.push('k-syntax-paren-match');
                                        }
                                    } else {
                                        tok.cls.push('k-syntax-error');
                                        open.cls.push('k-syntax-error');
                                    }
                                } else {
                                    tok.cls.push('k-syntax-error');
                                }
                            }
                        }
                        if (pos && touches(tok, pos)) {
                            tok.cls.push('k-syntax-at-point');
                            tok.active = true;
                            activeToken = tok;
                        }
                        if (tok.type == 'func' && !knownFunction(tok.value) && (!pos || !touches(tok, pos))) {
                            tok.cls.push('k-syntax-error');
                        }
                    });
                    tokens.reverse().forEach(function (tok) {
                        var begin = tok.begin, end = tok.end;
                        var text = kendo.htmlEncode(value.substring(begin, end));
                        value = value.substr(0, begin) + '<span class=\'' + tok.cls.join(' ') + '\'>' + text + '</span>' + value.substr(end);
                    });
                    this.element.html(value);
                }
                if (pos) {
                    this.setPos(pos.begin, pos.end);
                }
                if (activeToken && /^(?:startexp|op|punc)$/.test(activeToken.type)) {
                    this._setStaticTokens(tokens);
                }
                this._highlightedRefs = highlightedRefs;
            },
            _setStaticTokens: function (tokens) {
                var idx, tok;
                this._staticTokens = [];
                for (idx = 0; idx < tokens.length; idx++) {
                    tok = tokens[idx];
                    if (/^(?:num|str|bool|sym|ref)$/.test(tok.type)) {
                        this._staticTokens.push(tok);
                    }
                }
            },
            destroy: function () {
                this._editorToSync = null;
                this.element.off(ns);
                clearTimeout(this._focusTimeout);
                clearTimeout(this._keyDownTimeout);
                this._cellTooltip = null;
                this._span = null;
                this.popup.destroy();
                this.popup = null;
                Widget.fn.destroy.call(this);
            },
            insertNewline: function () {
                var val = this.value();
                var pos = this.getPos();
                var eof = pos.end == val.length;
                val = val.substr(0, pos.begin) + (eof ? '\n\n' : '\n' + val.substr(pos.end));
                this.value(val);
                this.setPos(pos.begin + 1);
            }
        });
        function isOpenParen(ch) {
            return ch == '(' || ch == '[' || ch == '{';
        }
        function isCloseParen(ch) {
            return ch == ')' || ch == ']' || ch == '}';
        }
        function isMatchingParen(close, open) {
            return open == '(' ? close == ')' : open == '[' ? close == ']' : open == '{' ? close == '}' : false;
        }
        function touches(pos, target) {
            return pos.begin <= target.begin && pos.end >= target.end;
        }
        function knownFunction(name) {
            return kendo.spreadsheet.calc.runtime.FUNCS[name.toLowerCase()];
        }
        function isEqualToken(tok1, tok2) {
            if (!tok1 || !tok2) {
                return false;
            }
            if (tok1.type == 'ref' && tok2.type == 'ref') {
                return tok1.ref.eq(tok2.ref);
            } else {
                return tok1.value === tok2.value;
            }
        }
        kendo.spreadsheet.FormulaInput = FormulaInput;
        $.extend(true, FormulaInput, { classNames: classNames });
    }(kendo, window));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/eventlistener', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var KEY_NAMES = {
            8: 'backspace',
            9: 'tab',
            13: 'enter',
            27: 'esc',
            37: 'left',
            38: 'up',
            39: 'right',
            40: 'down',
            35: 'end',
            36: 'home',
            32: 'spacebar',
            33: 'pageup',
            34: 'pagedown',
            46: 'delete',
            113: ':edit'
        };
        var Mac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
        var isAlphaNum = function (keyCode) {
            if (keyCode > 47 && keyCode < 58 || keyCode > 64 && keyCode < 91 || keyCode > 95 && keyCode < 112 || keyCode > 185 && keyCode < 193 || keyCode > 218 && keyCode < 223 || keyCode === 229) {
                return true;
            }
            return false;
        };
        var keyName = function (event) {
            var keyCode = event.keyCode;
            var name = KEY_NAMES[keyCode];
            if (!name && isAlphaNum(keyCode)) {
                name = ':alphanum';
            }
            if (!name && event.key && event.key.length == 1) {
                name = ':alphanum';
            }
            return name;
        };
        var EventListener = kendo.Class.extend({
            init: function (target, observer, handlers) {
                this._handlers = {};
                this.target = target;
                this._observer = observer || window;
                this.keyDownProxy = this.keyDown.bind(this);
                this.mouseProxy = this.mouse.bind(this);
                this.touchProxy = this.touch.bind(this);
                this.threshold = 5;
                this._pressLocation = null;
                target.on('keydown', this.keyDownProxy);
                target.on('contextmenu mousedown cut copy paste scroll wheel click dblclick focus', this.mouseProxy);
                target.on('touchmove touchend', this.touchProxy);
                $(document.documentElement).on('mousemove mouseup', this.mouseProxy);
                $(document.documentElement).on('touchmove touchend', this.touchProxy);
                if (handlers) {
                    for (var key in handlers) {
                        this.on(key, handlers[key]);
                    }
                }
            },
            keyDown: function (e) {
                this.handleEvent(e, keyName(e.originalEvent));
            },
            touch: function (e) {
                this.handleEvent(e, e.type);
            },
            mouse: function (e) {
                var rightClick;
                if (e.which) {
                    rightClick = e.which == 3;
                } else if (e.button) {
                    rightClick = e.button == 2;
                }
                var type = e.type;
                if (type === 'mousedown') {
                    if (rightClick) {
                        type = 'rightmousedown';
                    } else {
                        this._pressLocation = {
                            x: e.pageX,
                            y: e.pageY
                        };
                    }
                }
                if (type === 'mouseup') {
                    if (!rightClick) {
                        this._pressLocation = null;
                    }
                }
                if (type === 'mousemove' && this._pressLocation) {
                    var dx = this._pressLocation.x - e.pageX;
                    var dy = this._pressLocation.y - e.pageY;
                    var distance = Math.sqrt(dx * dx + dy * dy);
                    if (distance > this.threshold) {
                        type = 'mousedrag';
                    }
                }
                this.handleEvent(e, type);
            },
            handleEvent: function (e, name) {
                var eventKey = '';
                e.mod = Mac ? e.metaKey : e.ctrlKey && !e.altKey;
                if (e.altKey) {
                    eventKey += 'alt+';
                }
                if (e.shiftKey) {
                    eventKey += 'shift+';
                }
                if (e.ctrlKey) {
                    eventKey += 'ctrl+';
                }
                eventKey += name;
                var catchAllHandler = this._handlers['*+' + name];
                if (catchAllHandler) {
                    catchAllHandler.call(this._observer, e, eventKey);
                }
                var handler = this._handlers[eventKey];
                if (handler) {
                    handler.call(this._observer, e, eventKey);
                }
            },
            on: function (event, callback) {
                var handlers = this._handlers;
                if (typeof callback === 'string') {
                    callback = this._observer[callback];
                }
                if (typeof event === 'string') {
                    event = event.split(',');
                }
                event.forEach(function (e) {
                    handlers[e] = callback;
                });
            },
            destroy: function () {
                this.target.off('keydown', this.keyDownProxy);
                this.target.off('keydown', this.mouseProxy);
                $(document.documentElement).off('mousemove mouseup', this.mouseProxy);
            }
        });
        kendo.spreadsheet.EventListener = EventListener;
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/rangelist', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var RangeTreeNode = kendo.Class.extend({
            init: function Node(level, value, left, right) {
                this.level = level;
                this.value = value;
                this.left = left;
                this.right = right;
            }
        });
        var NilNode = new function NIL() {
            this.left = this;
            this.right = this;
            this.level = 0;
        }();
        function skew(node) {
            if (node.left.level === node.level) {
                var temp = node;
                node = node.left;
                temp.left = node.right;
                node.right = temp;
            }
            return node;
        }
        function split(node) {
            if (node.right.right.level === node.level) {
                var temp = node;
                node = node.right;
                temp.right = node.left;
                node.left = temp;
                node.level += 1;
            }
            return node;
        }
        function insert(node, value) {
            if (node === NilNode) {
                return new RangeTreeNode(1, value, NilNode, NilNode);
            } else if (node.value.start > value.start) {
                node.left = insert(node.left, value);
            } else {
                node.right = insert(node.right, value);
            }
            return split(skew(node));
        }
        function remove(node, value) {
            if (node === NilNode) {
                return node;
            }
            var diff = node.value.start - value.start;
            if (diff === 0) {
                if (node.left !== NilNode && node.right !== NilNode) {
                    var heir = node.left;
                    while (heir.right !== NilNode) {
                        heir = heir.right;
                    }
                    node.value = heir.value;
                    node.left = remove(node.left, node.value);
                } else if (node.left === NilNode) {
                    node = node.right;
                } else {
                    node = node.left;
                }
            } else if (diff > 0) {
                node.left = remove(node.left, value);
            } else {
                node.right = remove(node.right, value);
            }
            if (node.left.level < node.level - 1 || node.right.level < node.level - 1) {
                node.level -= 1;
                if (node.right.level > node.level) {
                    node.right.level = node.level;
                }
                node = skew(node);
                node.right = skew(node.right);
                node.right.right = skew(node.right.right);
                node = split(node);
                node.right = split(node.right);
            }
            return node;
        }
        var Range = kendo.Class.extend({
            init: function ValueRange(start, end, value) {
                this.start = start;
                this.end = end;
                this.value = value;
            },
            intersects: function (range) {
                return range.start <= this.end && range.end >= this.start;
            },
            clone: function () {
                return new Range(this.start, this.end, this.value);
            }
        });
        var RangeTree = kendo.Class.extend({
            init: function () {
                this.root = NilNode;
            },
            insert: function (value) {
                this.root = insert(this.root, value);
            },
            remove: function (value) {
                this.root = remove(this.root, value);
            },
            findrange: function (value) {
                var node = this.root;
                while (node != NilNode) {
                    if (value < node.value.start) {
                        node = node.left;
                    } else if (value > node.value.end) {
                        node = node.right;
                    } else {
                        return node.value;
                    }
                }
                return null;
            },
            values: function () {
                var result = [];
                values(this.root, result);
                return result;
            },
            intersecting: function (start, end) {
                var ranges = [];
                intersecting(this.root, new Range(start, end), ranges);
                return ranges;
            },
            map: function (callback) {
                var tree = new RangeTree();
                map(tree, this.root, callback);
                return tree;
            },
            clone: function () {
                return this.map(function (value) {
                    return value.clone();
                });
            },
            first: function () {
                var first = this.root;
                while (first.left != NilNode) {
                    first = first.left;
                }
                return first;
            },
            last: function () {
                var last = this.root;
                while (last.right != NilNode) {
                    last = last.right;
                }
                return last;
            }
        });
        function values(node, result) {
            if (node === NilNode) {
                return;
            }
            values(node.left, result);
            result.push(node.value);
            values(node.right, result);
        }
        function intersecting(node, range, ranges) {
            if (node === NilNode) {
                return;
            }
            var value = node.value;
            if (range.start < value.start) {
                intersecting(node.left, range, ranges);
            }
            if (value.intersects(range)) {
                ranges.push(value);
            }
            if (range.end > value.end) {
                intersecting(node.right, range, ranges);
            }
        }
        function map(tree, root, callback) {
            if (root === NilNode) {
                return;
            }
            map(tree, root.left, callback);
            tree.insert(callback(root.value));
            map(tree, root.right, callback);
        }
        var RangeList = kendo.Class.extend({
            init: function (start, end, value) {
                if (end === undefined) {
                    this.tree = start;
                } else {
                    this.tree = new RangeTree();
                    this.tree.insert(new Range(start, end, value));
                }
            },
            values: function () {
                return this.tree.values();
            },
            map: function (callback) {
                return new RangeList(this.tree.map(callback));
            },
            intersecting: function (start, end) {
                return this.tree.intersecting(start, end);
            },
            first: function () {
                return this.tree.first().value;
            },
            last: function () {
                return this.tree.last().value;
            },
            insert: function (start, end, value) {
                return this.tree.insert(new Range(start, end, value));
            },
            value: function (start, end, value) {
                if (value === undefined) {
                    if (end === undefined) {
                        end = start;
                    }
                    return this.intersecting(start, end)[0].value;
                }
                var ranges = this.tree.intersecting(start - 1, end + 1);
                if (ranges.length) {
                    var firstRange = ranges[0], lastRange = ranges[ranges.length - 1];
                    if (firstRange.end < start) {
                        if (firstRange.value === value) {
                            start = firstRange.start;
                        } else {
                            ranges.shift();
                        }
                    }
                    if (lastRange.start > end) {
                        if (lastRange.value === value) {
                            end = lastRange.end;
                        } else {
                            ranges.pop();
                        }
                    }
                    for (var i = 0, length = ranges.length; i < length; i++) {
                        var range = ranges[i];
                        var rangeValue = range.value;
                        var rangeStart = range.start;
                        var rangeEnd = range.end;
                        this.tree.remove(range);
                        if (rangeStart < start) {
                            if (rangeValue !== value) {
                                this.insert(rangeStart, start - 1, rangeValue);
                            } else {
                                start = rangeStart;
                            }
                        }
                        if (rangeEnd > end) {
                            if (rangeValue !== value) {
                                this.insert(end + 1, rangeEnd, rangeValue);
                            } else {
                                end = rangeEnd;
                            }
                        }
                    }
                }
                this.insert(start, end, value);
            },
            expandedValues: function (start, end) {
                var ranges = this.intersecting(start, end);
                var result = [];
                var rangeIndex = 0;
                for (var i = start; i <= end; i++) {
                    if (ranges[rangeIndex].end < i) {
                        rangeIndex++;
                    }
                    result.push({
                        index: i - start,
                        value: ranges[rangeIndex].value
                    });
                }
                return result;
            },
            sortedIndices: function (start, end, valueComparer, indices) {
                var result = this.expandedValues(start, end);
                var comparer = function (a, b) {
                    if (a.value === b.value) {
                        return a.index - b.index;
                    }
                    return valueComparer(a.value, b.value);
                };
                if (indices) {
                    comparer = function (a, b) {
                        var x = indices[a.index];
                        var y = indices[b.index];
                        if (x.value === y.value) {
                            return valueComparer(a.value, b.value);
                        }
                        return a.index - b.index;
                    };
                }
                result.sort(comparer);
                return result;
            },
            sort: function (start, end, indices) {
                if (this.intersecting(start, end).length === 1) {
                    return;
                }
                var values = this.expandedValues(start, end);
                for (var i = 0, len = indices.length; i < len; i++) {
                    this.value(i + start, i + start, values[indices[i].index].value);
                }
            },
            copy: function (sourceStart, sourceEnd, targetStart) {
                var values = this.intersecting(sourceStart, sourceEnd);
                var start = targetStart;
                var end;
                for (var i = 0, len = values.length; i < len; i++) {
                    var rangeStart = values[i].start;
                    if (rangeStart < sourceStart) {
                        rangeStart = sourceStart;
                    }
                    var rangeEnd = values[i].end;
                    if (rangeEnd > sourceEnd) {
                        rangeEnd = sourceEnd;
                    }
                    end = start + (rangeEnd - rangeStart);
                    this.value(start, end, values[i].value);
                    start = ++end;
                }
            },
            iterator: function (start, end) {
                return new Iterator(start, end, this.intersecting(start, end));
            },
            getState: function () {
                return this.tree.clone();
            },
            setState: function (state) {
                this.tree = state.clone();
            },
            toJSON: function () {
                return this.values();
            },
            fromJSON: function (values) {
                values.forEach(function (v) {
                    this.value(v.start, v.end, v.value);
                }, this);
            }
        });
        var Iterator = kendo.Class.extend({
            init: function (start, end, ranges) {
                this.start = start;
                this.end = end;
                this.index = 0;
                this.ranges = ranges;
            },
            unique: function () {
                return this.ranges.map(function (range) {
                    return range.value;
                });
            },
            at: function (index) {
                while (this.ranges[this.index] && this.ranges[this.index].end < index) {
                    this.index++;
                }
                return this.ranges[this.index] && this.ranges[this.index].value;
            },
            forEach: function (callback) {
                for (var i = this.start; i <= this.end; i++) {
                    callback(this.at(i), i);
                }
                this.index = 0;
            }
        });
        var SparseRangeList = RangeList.extend({
            init: function (start, end, value) {
                this.tree = new RangeTree();
                this.range = new Range(start, end, value);
            },
            intersecting: function (start, end) {
                var ranges = this.tree.intersecting(start, end);
                var result = [];
                var range;
                if (!ranges.length) {
                    return [this.range];
                }
                for (var i = 0, len = ranges.length; i < len; i++) {
                    range = ranges[i];
                    if (range.start > start) {
                        result.push(new Range(start, range.start - 1, this.range.value));
                    }
                    result.push(range);
                    start = range.end + 1;
                }
                if (range.end < end) {
                    result.push(new Range(range.end + 1, end, this.range.value));
                }
                return result;
            },
            insert: function (start, end, value) {
                if (value !== this.range.value) {
                    this.tree.insert(new Range(start, end, value));
                }
            },
            lastRangeStart: function () {
                var node = this.tree.root;
                if (node === NilNode) {
                    return this.range.start;
                }
                while (node.right !== NilNode) {
                    node = node.right;
                }
                return node.value.end + 1;
            }
        });
        kendo.spreadsheet.RangeTree = RangeTree;
        kendo.spreadsheet.RangeList = RangeList;
        kendo.spreadsheet.SparseRangeList = SparseRangeList;
        kendo.spreadsheet.ValueRange = Range;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/propertybag', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var Property = kendo.Class.extend({
            init: function (list) {
                this.list = list;
            },
            get: function (index) {
                return this.parse(this.list.value(index, index));
            },
            set: function (start, end, value) {
                if (value === undefined) {
                    value = end;
                    end = start;
                }
                this.list.value(start, end, value);
            },
            parse: function (value) {
                return value;
            },
            copy: function (start, end, dst) {
                this.list.copy(start, end, dst);
            },
            iterator: function (start, end) {
                return this.list.iterator(start, end);
            }
        });
        var JsonProperty = Property.extend({
            set: function (start, end, value) {
                this.list.value(start, end, JSON.stringify(value));
            },
            parse: function (value) {
                return JSON.parse(value);
            }
        });
        var ValueProperty = Property.extend({
            init: function (values, formats) {
                Property.prototype.init.call(this, values);
                this.formats = formats;
            },
            set: function (start, end, value) {
                if (value instanceof Date) {
                    value = kendo.spreadsheet.dateToNumber(value);
                    if (!this.formats.value(start, end)) {
                        this.formats.value(start, end, toExcelFormat(kendo.culture().calendar.patterns.d));
                    }
                } else if (typeof value == 'number') {
                    value = kendo.spreadsheet.calc.runtime.limitPrecision(value);
                }
                this.list.value(start, end, value);
            }
        });
        function toExcelFormat(format) {
            return format.replace(/M/g, 'm').replace(/'/g, '"').replace(/tt/, 'am/pm');
        }
        kendo.spreadsheet.PropertyBag = kendo.Class.extend({
            specs: [
                {
                    property: Property,
                    name: 'format',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: ValueProperty,
                    name: 'value',
                    value: null,
                    sortable: true,
                    serializable: true,
                    depends: 'format'
                },
                {
                    property: Property,
                    name: 'formula',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'background',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: JsonProperty,
                    name: 'vBorders',
                    value: null,
                    sortable: false,
                    serializable: false
                },
                {
                    property: JsonProperty,
                    name: 'hBorders',
                    value: null,
                    sortable: false,
                    serializable: false
                },
                {
                    property: Property,
                    name: 'color',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'fontFamily',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'underline',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'fontSize',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'italic',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'bold',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'textAlign',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'indent',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'verticalAlign',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'wrap',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'validation',
                    value: null,
                    sortable: false,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'enable',
                    value: null,
                    sortable: false,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'link',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'editor',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'comment',
                    value: null,
                    sortable: true,
                    serializable: true
                }
            ],
            init: function (rowCount, columnCount, defaultValues) {
                defaultValues = defaultValues || {};
                var cellCount = rowCount * columnCount - 1;
                this.rowCount = rowCount;
                this.columnCount = columnCount;
                this.cellCount = cellCount;
                this.properties = {};
                this.lists = {};
                this.specs.forEach(function (spec) {
                    var name = spec.name;
                    var value = defaultValues[name];
                    if (value === undefined) {
                        value = spec.value;
                    }
                    this.lists[name] = new kendo.spreadsheet.SparseRangeList(0, cellCount, value);
                    var prop = this.properties[name] = new spec.property(this.lists[name], this.lists[spec.depends]);
                    prop.spec = spec;
                }, this);
                this.lists.formula.tree.clone = cloneFormulaTree;
                this.lists.validation.tree.clone = cloneFormulaTree;
            },
            getState: function () {
                var state = {};
                this.specs.forEach(function (spec) {
                    state[spec.name] = this.lists[spec.name].getState();
                }, this);
                return state;
            },
            setState: function (state) {
                this.specs.forEach(function (spec) {
                    this.lists[spec.name].setState(state[spec.name]);
                }, this);
            },
            get: function (name, index) {
                if (index === undefined) {
                    return this.lists[name];
                }
                switch (name) {
                case 'borderRight':
                    index += this.rowCount;
                case 'borderLeft':
                    name = 'vBorders';
                    break;
                case 'borderBottom':
                    index++;
                case 'borderTop':
                    name = 'hBorders';
                    break;
                }
                return index > this.cellCount ? null : this.properties[name].get(index);
            },
            set: function (name, start, end, value) {
                switch (name) {
                case 'borderRight':
                    start += this.rowCount;
                    end += this.rowCount;
                case 'borderLeft':
                    name = 'vBorders';
                    break;
                case 'borderBottom':
                    start++;
                    end++;
                case 'borderTop':
                    name = 'hBorders';
                    break;
                }
                if (start <= end && end <= this.cellCount) {
                    this.properties[name].set(start, end, value);
                }
            },
            fromJSON: function (index, value) {
                for (var si = 0; si < this.specs.length; si++) {
                    var spec = this.specs[si];
                    if (spec.serializable) {
                        if (value[spec.name] !== undefined) {
                            this.set(spec.name, index, index, value[spec.name], false);
                        }
                    }
                }
                [
                    'borderLeft',
                    'borderRight',
                    'borderTop',
                    'borderBottom'
                ].forEach(function (b) {
                    if (value[b] !== undefined) {
                        this.set(b, index, index, value[b]);
                    }
                }, this);
            },
            copy: function (sourceStart, sourceEnd, targetStart) {
                this.specs.forEach(function (spec) {
                    this.properties[spec.name].copy(sourceStart, sourceEnd, targetStart);
                }, this);
            },
            iterator: function (name, start, end) {
                var prop = this.properties[name];
                var iter = prop.iterator(start, end), at = iter.at;
                var cellCount = this.cellCount;
                iter.at = function (index) {
                    return index > cellCount ? null : prop.parse(at.call(iter, index));
                };
                iter.name = name;
                iter.value = prop.spec.value;
                return iter;
            },
            sortable: function () {
                return this.specs.filter(function (spec) {
                    return spec.sortable;
                }).map(function (spec) {
                    return this.lists[spec.name];
                }, this);
            },
            iterators: function (start, end) {
                return this.specs.reduce(function (ret, spec) {
                    if (spec.serializable) {
                        ret.push(this.iterator(spec.name, start, end));
                    }
                    return ret;
                }.bind(this), []);
            },
            forEach: function (start, end, callback) {
                var iterators = this.iterators(start, end);
                var hBorders = this.iterator('hBorders', start, end + 1);
                var leftBorders = this.iterator('vBorders', start, end);
                var rightBorders = this.iterator('vBorders', start + this.rowCount, end + this.rowCount);
                var values, index;
                function addBorder(name, iterator, index) {
                    var val = iterator.at(index);
                    if (val !== iterator.value) {
                        values[name] = val;
                    }
                }
                for (index = start; index <= end; index++) {
                    values = {};
                    for (var i = 0; i < iterators.length; i++) {
                        var iterator = iterators[i];
                        var value = iterator.at(index);
                        if (value !== iterator.value) {
                            values[iterator.name] = value;
                        }
                    }
                    addBorder('borderLeft', leftBorders, index);
                    addBorder('borderRight', rightBorders, index + this.rowCount);
                    addBorder('borderTop', hBorders, index);
                    if ((index + 1) % this.rowCount) {
                        addBorder('borderBottom', hBorders, index + 1);
                    }
                    callback(values);
                }
            },
            forEachProperty: function (callback) {
                for (var name in this.properties) {
                    callback(this.properties[name]);
                }
            }
        });
        function cloneFormulaValue(x) {
            x = x.clone();
            x.value = x.value.deepClone();
            return x;
        }
        function cloneFormulaTree() {
            var tree = this.map(cloneFormulaValue);
            tree.clone = cloneFormulaTree;
            return tree;
        }
        kendo.spreadsheet.ALL_PROPERTIES = kendo.spreadsheet.PropertyBag.prototype.specs.reduce(function (a, spec) {
            if (spec.serializable) {
                a.push(spec.name);
            }
            return a;
        }, [
            'borderTop',
            'borderRight',
            'borderBottom',
            'borderLeft'
        ]);
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/references', ['kendo.core'], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var spreadsheet = kendo.spreadsheet;
    var Class = kendo.Class;
    function columnName(colIndex) {
        var letter = Math.floor(colIndex / 26) - 1;
        return (letter >= 0 ? columnName(letter) : '') + String.fromCharCode(65 + colIndex % 26);
    }
    function displaySheet(sheet) {
        if (/^[a-z_][a-z0-9_]*$/i.test(sheet)) {
            return sheet;
        }
        return '\'' + sheet.replace(/\x27/g, '\\\'') + '\'';
    }
    function displayRef(sheet, row, col, rel) {
        var aa = '';
        ++row;
        if (!isFinite(row)) {
            row = '';
        } else if (rel != null && !(rel & 2)) {
            row = '$' + row;
        }
        if (!isFinite(col)) {
            col = '';
        } else {
            aa = columnName(col);
            if (rel != null && !(rel & 1)) {
                aa = '$' + aa;
            }
        }
        if (sheet) {
            return displaySheet(sheet) + '!' + aa + row;
        } else {
            return aa + row;
        }
    }
    var Ref = Class.extend({
        type: 'ref',
        sheet: '',
        clone: function () {
            return this;
        },
        hasSheet: function () {
            return this._hasSheet;
        },
        simplify: function () {
            return this;
        },
        setSheet: function (sheet, hasSheet) {
            this.sheet = sheet;
            if (hasSheet != null) {
                this._hasSheet = hasSheet;
            }
            return this;
        },
        absolute: function () {
            return this;
        },
        relative: function () {
            return this;
        },
        adjust: function () {
            return this;
        },
        toString: function () {
            return this.relative(0, 0, 3, 3).print(0, 0);
        },
        forEach: function (callback, obj) {
            callback.call(obj, this);
        },
        map: function (callback, obj) {
            return callback.call(obj, this);
        },
        intersects: function (ref) {
            return this.intersect(ref) !== NULL;
        },
        isCell: function () {
            return false;
        },
        toRow: function () {
            return this;
        },
        toColumn: function () {
            return this;
        },
        first: function () {
            return this;
        },
        lastRange: function () {
            return this;
        },
        size: function () {
            return 1;
        },
        rangeAt: function () {
            return this;
        },
        nextRangeIndex: function () {
            return 0;
        },
        previousRangeIndex: function () {
            return 0;
        },
        eq: function (reference) {
            var r1 = this;
            var r2 = reference;
            if (r1 === NULL || r2 === NULL) {
                return r1 === r2;
            }
            if (r2 instanceof CellRef || r2 instanceof RangeRef && !(r1 instanceof CellRef)) {
                r1 = reference;
                r2 = this;
            }
            if (r1 instanceof CellRef) {
                r2 = r2.simplify();
                return r2 instanceof CellRef && r1.row == r2.row && r1.col == r2.col && r1.sheet == r2.sheet;
            } else if (r1 instanceof RangeRef) {
                if (r2 instanceof RangeRef) {
                    return r2.topLeft.eq(r1.topLeft) && r2.bottomRight.eq(r1.bottomRight);
                }
                if (r2 instanceof UnionRef) {
                    return r2.single() && r1.eq(r2.refs[0]);
                }
            } else if (r1 instanceof UnionRef && r2 instanceof UnionRef) {
                var refs1 = r1.refs;
                var refs2 = r2.refs;
                if (refs1.length != refs2.length) {
                    return false;
                }
                for (var i = 0, len = refs1.length; i < len; i++) {
                    if (!refs1[i].eq(refs2[i])) {
                        return false;
                    }
                }
                return true;
            }
            return r1 === r2;
        },
        concat: function (ref) {
            return new UnionRef([
                this,
                ref
            ]);
        },
        replaceAt: function (index, ref) {
            return ref;
        },
        forEachColumnIndex: function (callback) {
            this.forEachAxisIndex('col', callback);
        },
        forEachRowIndex: function (callback) {
            this.forEachAxisIndex('row', callback);
        },
        forEachAxisIndex: function (axis, callback) {
            var sorted = [];
            var method = axis === 'row' ? 'forEachRow' : 'forEachColumn';
            this[method](function (ref) {
                var index = ref.first()[axis];
                if (sorted.indexOf(index) === -1) {
                    sorted.push(index);
                }
            });
            sorted.sort(function (a, b) {
                return a > b ? 1 : a < b ? -1 : 0;
            }).forEach(callback);
        },
        valid: function () {
            return false;
        },
        renameSheet: function (oldSheetName, newSheetName) {
            if (this.sheet && this.sheet.toLowerCase() == oldSheetName.toLowerCase()) {
                this.sheet = newSheetName;
                return true;
            }
        }
    });
    Ref.display = displayRef;
    var NULL = new (Ref.extend({
        init: function NullRef() {
        },
        print: function () {
            return '#NULL!';
        },
        eq: function (ref) {
            return ref === this;
        },
        forEach: function () {
        }
    }))();
    var NameRef = Ref.extend({
        ref: 'name',
        init: function NameRef(name) {
            this.name = name;
        },
        clone: function () {
            return new NameRef(this.name).setSheet(this.sheet, this.hasSheet());
        },
        print: function () {
            var ret = displaySheet(this.name);
            if (this.hasSheet()) {
                ret = displaySheet(this.sheet) + '!' + ret;
            }
            return ret;
        }
    });
    var CellRef = Ref.extend({
        ref: 'cell',
        init: function CellRef(row, col, rel) {
            this.row = row;
            this.col = col;
            this.rel = rel || 0;
        },
        clone: function () {
            return new CellRef(this.row, this.col, this.rel).setSheet(this.sheet, this.hasSheet());
        },
        intersect: function (ref) {
            if (ref instanceof CellRef) {
                if (this.eq(ref)) {
                    return this;
                } else {
                    return NULL;
                }
            }
            return ref.intersect(this);
        },
        print: function (trow, tcol, mod) {
            var col = this.col, row = this.row, rel = this.rel, abs;
            if (trow == null && rel) {
                var sheet = this.hasSheet() ? displaySheet(this.sheet) + '!' : '';
                if (isFinite(col)) {
                    col = rel & 1 ? 'C[' + col + ']' : 'C' + (col + 1);
                } else {
                    col = '';
                }
                if (isFinite(row)) {
                    row = rel & 2 ? 'R[' + row + ']' : 'R' + (row + 1);
                } else {
                    row = '';
                }
                return sheet + row + col;
            } else {
                abs = this.absolute(trow, tcol);
                if (mod) {
                    row = abs.row % 1048576;
                    col = abs.col % 16384;
                    if (row < 0) {
                        row += 1048576;
                    }
                    if (col < 0) {
                        col += 16384;
                    }
                    return displayRef(this._hasSheet && this.sheet, row, col, rel);
                }
                return abs.valid() ? displayRef(this._hasSheet && this.sheet, abs.row, abs.col, rel) : '#REF!';
            }
        },
        absolute: function (arow, acol) {
            var ret = this.clone();
            if (ret.rel & 3 === 0) {
                return ret;
            }
            if (ret.rel & 1) {
                ret.col = (ret.col + acol) % 16384;
            }
            if (ret.rel & 2) {
                ret.row = (ret.row + arow) % 1048576;
            }
            ret.rel = 0;
            return ret;
        },
        toRangeRef: function () {
            return new RangeRef(this, this);
        },
        relative: function (arow, acol, rel) {
            if (rel == null) {
                rel = this.rel;
            }
            var row = rel & 2 ? this.row - arow : this.row;
            var col = rel & 1 ? this.col - acol : this.col;
            return new CellRef(row, col, rel).setSheet(this.sheet, this.hasSheet());
        },
        height: function () {
            return 1;
        },
        width: function () {
            return 1;
        },
        toString: function () {
            return displayRef(null, this.row, this.col, 3);
        },
        isCell: function () {
            return true;
        },
        leftColumn: function () {
            return this;
        },
        rightColumn: function () {
            return this;
        },
        topRow: function () {
            return this;
        },
        bottomRow: function () {
            return this;
        },
        forEachRow: function (callback) {
            callback(this.toRangeRef());
        },
        forEachColumn: function (callback) {
            callback(this.toRangeRef());
        },
        adjust: function (row, col, trow, tcol, forRow, start, delta) {
            var ref = this.absolute(row, col);
            if (forRow) {
                if (ref.row >= start) {
                    if (delta < 0 && ref.row < start - delta) {
                        return NULL;
                    }
                    ref.row += delta;
                }
            } else {
                if (ref.col >= start) {
                    if (delta < 0 && ref.col < start - delta) {
                        return NULL;
                    }
                    ref.col += delta;
                }
            }
            if (trow != null && tcol != null) {
                ref = ref.relative(trow, tcol, this.rel);
            }
            return ref;
        },
        valid: function () {
            if (this.rel) {
                throw new Error('valid() called on relative reference');
            }
            var col = this.col, row = this.row;
            return !(isFinite(col) && col < 0 || isFinite(row) && row < 0);
        }
    });
    var RangeRef = Ref.extend({
        ref: 'range',
        init: function RangeRef(tl, br) {
            if (tl._hasSheet && br._hasSheet && tl.sheet.toLowerCase() != br.sheet.toLowerCase()) {
                this.endSheet = br.sheet;
            }
            this.topLeft = new CellRef(tl.row, tl.col, tl.rel);
            this.bottomRight = new CellRef(br.row, br.col, br.rel);
            this.normalize();
        },
        clone: function () {
            return new RangeRef(this.topLeft.clone(), this.bottomRight.clone()).setSheet(this.sheet, this.hasSheet());
        },
        _containsRange: function (range) {
            return this._containsCell(range.topLeft) && this._containsCell(range.bottomRight);
        },
        _containsCell: function (cell) {
            return cell.sheet == this.sheet && cell.row >= this.topLeft.row && cell.col >= this.topLeft.col && cell.row <= this.bottomRight.row && cell.col <= this.bottomRight.col;
        },
        contains: function (ref) {
            if (ref instanceof Array) {
                var that = this;
                return ref.some(function (_ref) {
                    return that.contains(_ref);
                });
            }
            if (ref instanceof CellRef) {
                return this._containsCell(ref);
            }
            if (ref instanceof RangeRef) {
                return this._containsRange(ref);
            }
            return false;
        },
        _intersectRange: function (ref) {
            if (this.sheet != ref.sheet) {
                return NULL;
            }
            var a_left = this.topLeft.col;
            var a_top = this.topLeft.row;
            var a_right = this.bottomRight.col;
            var a_bottom = this.bottomRight.row;
            var b_left = ref.topLeft.col;
            var b_top = ref.topLeft.row;
            var b_right = ref.bottomRight.col;
            var b_bottom = ref.bottomRight.row;
            if (a_left <= b_right && b_left <= a_right && a_top <= b_bottom && b_top <= a_bottom) {
                return new RangeRef(new CellRef(Math.max(a_top, b_top), Math.max(a_left, b_left)), new CellRef(Math.min(a_bottom, b_bottom), Math.min(a_right, b_right))).setSheet(this.sheet, this.hasSheet());
            } else {
                return NULL;
            }
        },
        intersect: function (ref) {
            if (ref instanceof CellRef) {
                return this._containsCell(ref) ? ref : NULL;
            }
            if (ref instanceof RangeRef) {
                return this._intersectRange(ref).simplify();
            }
            if (ref instanceof UnionRef) {
                return ref.intersect(this);
            }
            return NULL;
        },
        simplify: function () {
            if (this.isCell()) {
                return new CellRef(this.topLeft.row, this.topLeft.col, this.topLeft.rel).setSheet(this.sheet, this.hasSheet());
            }
            return this;
        },
        normalize: function () {
            var a = this.topLeft, b = this.bottomRight;
            var r1 = a.row, c1 = a.col, r2 = b.row, c2 = b.col;
            var rr1 = a.rel & 2, rc1 = a.rel & 1;
            var rr2 = b.rel & 2, rc2 = b.rel & 1;
            var tmp, changes = false;
            if (rr1 === rr2 && rc1 === rc2) {
                if (r1 > r2) {
                    changes = true;
                    tmp = r1;
                    r1 = r2;
                    r2 = tmp;
                    tmp = rr1;
                    rr1 = rr2;
                    rr2 = tmp;
                }
                if (c1 > c2) {
                    changes = true;
                    tmp = c1;
                    c1 = c2;
                    c2 = tmp;
                    tmp = rc1;
                    rc1 = rc2;
                    rc2 = tmp;
                }
                if (changes) {
                    this.topLeft = new CellRef(r1, c1, rc1 | rr1);
                    this.bottomRight = new CellRef(r2, c2, rc2 | rr2);
                }
            }
            return this;
        },
        print: function (trow, tcol, mod) {
            if (mod || this.absolute(trow, tcol).valid()) {
                var ret = this.topLeft.print(trow, tcol, mod) + ':' + this.bottomRight.print(trow, tcol, mod);
                if (this.hasSheet()) {
                    ret = displaySheet(this.sheet) + (this.endSheet ? ':' + displaySheet(this.endSheet) : '') + '!' + ret;
                }
                return ret;
            }
            return '#REF!';
        },
        absolute: function (arow, acol) {
            return new RangeRef(this.topLeft.absolute(arow, acol), this.bottomRight.absolute(arow, acol)).setSheet(this.sheet, this.hasSheet());
        },
        relative: function (arow, acol, relTL, relBR) {
            if (relBR == null) {
                relBR = relTL;
            }
            return new RangeRef(this.topLeft.relative(arow, acol, relTL), this.bottomRight.relative(arow, acol, relBR)).setSheet(this.sheet, this.hasSheet());
        },
        height: function () {
            if (this.topLeft.rel != this.bottomRight.rel) {
                throw new Error('Mixed relative/absolute references');
            }
            return this.bottomRight.row - this.topLeft.row + 1;
        },
        width: function () {
            if (this.topLeft.rel != this.bottomRight.rel) {
                throw new Error('Mixed relative/absolute references');
            }
            return this.bottomRight.col - this.topLeft.col + 1;
        },
        collapse: function () {
            return this.topLeft.toRangeRef();
        },
        leftColumn: function () {
            return new RangeRef(this.topLeft, new CellRef(this.bottomRight.row, this.topLeft.col));
        },
        rightColumn: function () {
            return new RangeRef(new CellRef(this.topLeft.row, this.bottomRight.col), this.bottomRight);
        },
        topRow: function () {
            return new RangeRef(this.topLeft, new CellRef(this.topLeft.row, this.bottomRight.col));
        },
        bottomRow: function () {
            return new RangeRef(new CellRef(this.bottomRight.row, this.topLeft.col), this.bottomRight);
        },
        toRangeRef: function () {
            return this;
        },
        toRow: function (row) {
            row += Math.max(0, this.topLeft.row);
            return new RangeRef(new CellRef(row, this.topLeft.col), new CellRef(row, this.bottomRight.col)).setSheet(this.sheet, this.hasSheet());
        },
        toColumn: function (col) {
            col += Math.max(0, this.topLeft.col);
            return new RangeRef(new CellRef(this.topLeft.row, col), new CellRef(this.bottomRight.row, col)).setSheet(this.sheet, this.hasSheet());
        },
        toCell: function (row, col) {
            row += Math.max(0, this.topLeft.row);
            col += Math.max(0, this.topLeft.col);
            return new CellRef(row, col, 0).setSheet(this.sheet, this.hasSheet());
        },
        forEachRow: function (callback) {
            var startRow = this.topLeft.row;
            var endRow = this.bottomRight.row;
            var startCol = this.topLeft.col;
            var endCol = this.bottomRight.col;
            for (var i = startRow; i <= endRow; i++) {
                callback(new RangeRef(new CellRef(i, startCol), new CellRef(i, endCol)));
            }
        },
        forEachColumn: function (callback) {
            var startRow = this.topLeft.row;
            var endRow = this.bottomRight.row;
            var startCol = this.topLeft.col;
            var endCol = this.bottomRight.col;
            for (var i = startCol; i <= endCol; i++) {
                callback(new RangeRef(new CellRef(startRow, i), new CellRef(endRow, i)));
            }
        },
        intersecting: function (refs) {
            return refs.filter(function (ref) {
                return ref.toRangeRef().intersects(this);
            }, this);
        },
        union: function (refs, callback) {
            var intersecting = this.intersecting(refs);
            var topLeftRow = this.topLeft.row;
            var topLeftCol = this.topLeft.col;
            var bottomRightRow = this.bottomRight.row;
            var bottomRightCol = this.bottomRight.col;
            var modified = false;
            intersecting.forEach(function (ref) {
                ref = ref.toRangeRef();
                if (ref.topLeft.row < topLeftRow) {
                    modified = true;
                    topLeftRow = ref.topLeft.row;
                }
                if (ref.topLeft.col < topLeftCol) {
                    modified = true;
                    topLeftCol = ref.topLeft.col;
                }
                if (ref.bottomRight.row > bottomRightRow) {
                    modified = true;
                    bottomRightRow = ref.bottomRight.row;
                }
                if (ref.bottomRight.col > bottomRightCol) {
                    modified = true;
                    bottomRightCol = ref.bottomRight.col;
                }
                if (callback) {
                    callback(ref);
                }
            });
            var result = new RangeRef(new CellRef(topLeftRow, topLeftCol), new CellRef(bottomRightRow, bottomRightCol));
            if (modified) {
                return result.union(refs, callback);
            } else {
                return result;
            }
        },
        resize: function (options) {
            var limit = Math.max.bind(Math, 0);
            function num(value) {
                return value || 0;
            }
            var top = this.topLeft.row + num(options.top);
            var left = this.topLeft.col + num(options.left);
            var bottom = this.bottomRight.row + num(options.bottom);
            var right = this.bottomRight.col + num(options.right);
            if (left < 0 && right < 0 || top < 0 && bottom < 0) {
                return NULL;
            } else if (top <= bottom && left <= right) {
                return new RangeRef(new CellRef(limit(top), limit(left)), new CellRef(limit(bottom), limit(right)));
            } else {
                return NULL;
            }
        },
        move: function (rows, cols) {
            return new RangeRef(new CellRef(this.topLeft.row + rows, this.topLeft.col + cols), new CellRef(this.bottomRight.row + rows, this.bottomRight.col + cols));
        },
        first: function () {
            return this.topLeft.clone().setSheet(this.sheet, this.hasSheet());
        },
        isCell: function () {
            return !this.endSheet && this.topLeft.eq(this.bottomRight);
        },
        toString: function () {
            return this.topLeft + ':' + this.bottomRight;
        },
        adjust: function (row, col, trow, tcol, forRow, start, delta) {
            var tl = this.topLeft.adjust(row, col, trow, tcol, forRow, start, delta);
            var tr = this.bottomRight.adjust(row, col, trow, tcol, forRow, start, delta);
            if (tl === NULL && tr === NULL) {
                return NULL;
            }
            if (tl === NULL) {
                tl = this.topLeft.absolute(row, col);
                if (forRow) {
                    tl.row = start;
                } else {
                    tl.col = start;
                }
                if (trow != null && tcol != null) {
                    tl = tl.relative(trow, tcol, this.topLeft.rel);
                }
            } else if (tr === NULL) {
                tr = this.bottomRight.absolute(row, col);
                if (forRow) {
                    tr.row = start - 1;
                } else {
                    tr.col = start - 1;
                }
                if (trow != null && tcol != null) {
                    tr = tr.relative(trow, tcol, this.bottomRight.rel);
                }
            }
            return new RangeRef(tl, tr).setSheet(this.sheet, this.hasSheet()).simplify();
        },
        valid: function () {
            return this.topLeft.valid() && this.bottomRight.valid();
        }
    });
    var UnionRef = Ref.extend({
        init: function UnionRef(refs) {
            this.refs = refs;
            this.length = refs.length;
        },
        clone: function () {
            return new UnionRef(this.refs.slice());
        },
        intersect: function (ref) {
            var a = [];
            for (var i = 0; i < this.length; ++i) {
                var x = ref.intersect(this.refs[i]);
                if (x !== NULL) {
                    a.push(x);
                }
            }
            if (a.length > 0) {
                return new UnionRef(a).simplify();
            }
            return NULL;
        },
        simplify: function () {
            var u = new UnionRef(this.refs.reduce(function (a, ref) {
                ref = ref.simplify();
                if (ref !== NULL) {
                    a.push(ref);
                }
                return a;
            }, []));
            if (u.empty()) {
                return NULL;
            }
            if (u.single()) {
                return u.refs[0];
            }
            return u;
        },
        absolute: function (arow, acol) {
            return new UnionRef(this.refs.map(function (ref) {
                return ref.absolute(arow, acol);
            }));
        },
        forEach: function (callback, obj) {
            this.refs.forEach(function (ref) {
                if (ref instanceof UnionRef) {
                    ref.forEach(callback, obj);
                } else {
                    callback.call(obj, ref);
                }
            }, obj);
        },
        toRangeRef: function () {
            return this.refs[0].toRangeRef();
        },
        contains: function (theRef) {
            return this.refs.some(function (ref) {
                return ref.contains(theRef);
            });
        },
        map: function (callback, obj) {
            var refs = [];
            this.forEach(function (ref) {
                refs.push(callback.call(obj, ref));
            });
            return new UnionRef(refs);
        },
        first: function () {
            return this.refs[0].first();
        },
        lastRange: function () {
            return this.refs[this.length - 1];
        },
        size: function () {
            return this.length;
        },
        single: function () {
            return this.length == 1;
        },
        empty: function () {
            return this.length === 0;
        },
        isCell: function () {
            return this.single() && this.refs[0].isCell();
        },
        rangeAt: function (index) {
            return this.refs[index];
        },
        nextRangeIndex: function (index) {
            if (index === this.length - 1) {
                return 0;
            } else {
                return index + 1;
            }
        },
        previousRangeIndex: function (index) {
            if (index === 0) {
                return this.length - 1;
            } else {
                return index - 1;
            }
        },
        concat: function (ref) {
            return new UnionRef(this.refs.concat([ref]));
        },
        print: function (row, col, mod) {
            return this.refs.map(function (ref) {
                return ref.print(row, col, mod);
            }).join(',');
        },
        replaceAt: function (index, ref) {
            var newRefs = this.refs.slice();
            newRefs.splice(index, 1, ref);
            return new UnionRef(newRefs);
        },
        leftColumn: function () {
            return this.map(function (ref) {
                return ref.leftColumn();
            });
        },
        rightColumn: function () {
            return this.map(function (ref) {
                return ref.rightColumn();
            });
        },
        topRow: function () {
            return this.map(function (ref) {
                return ref.topRow();
            });
        },
        bottomRow: function () {
            return this.map(function (ref) {
                return ref.bottomRow();
            });
        },
        forEachRow: function (callback) {
            this.forEach(function (ref) {
                ref.forEachRow(callback);
            });
        },
        forEachColumn: function (callback) {
            this.forEach(function (ref) {
                ref.forEachColumn(callback);
            });
        },
        adjust: function (row, col, trow, tcol, forRow, start, delta) {
            return this.map(function (ref) {
                return ref.adjust(row, col, trow, tcol, forRow, start, delta);
            }).simplify();
        },
        toString: function () {
            return this.refs.map(function (ref) {
                return ref.toString();
            }).join(', ');
        },
        valid: function () {
            for (var i = this.refs.length; --i >= 0;) {
                if (this.refs[i].valid()) {
                    return false;
                }
            }
            return true;
        },
        renameSheet: function (oldSheetName, newSheetName) {
            this.refs.forEach(function (ref) {
                ref.renameSheet(oldSheetName, newSheetName);
            });
        }
    });
    spreadsheet.NULLREF = NULL;
    spreadsheet.SHEETREF = new RangeRef(new CellRef(0, 0), new CellRef(Infinity, Infinity));
    spreadsheet.FIRSTREF = new CellRef(0, 0);
    spreadsheet.Ref = Ref;
    spreadsheet.NameRef = NameRef;
    spreadsheet.CellRef = CellRef;
    spreadsheet.RangeRef = RangeRef;
    spreadsheet.UnionRef = UnionRef;
    spreadsheet.SHEETREF.print = function () {
        return '#SHEET';
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/autofillcalculator', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var RangeRef = kendo.spreadsheet.RangeRef;
        var CellRef = kendo.spreadsheet.CellRef;
        var AutoFillCalculator = kendo.Class.extend({
            init: function (grid) {
                this._grid = grid;
            },
            rectIsVertical: function (start, end, x, y) {
                var startRect = this._grid.rectangle(start.toRangeRef());
                var endRect = this._grid.rectangle(end.toRangeRef());
                return Math.abs(endRect[y] - startRect[y]) > Math.abs(startRect[x] - endRect[x]);
            },
            autoFillDest: function (selection, cursor) {
                var topLeft = selection.topLeft;
                var bottomRight = selection.bottomRight;
                var quadrant;
                var lower = cursor.row >= topLeft.row;
                var further = cursor.col >= topLeft.col;
                if (lower) {
                    quadrant = further ? 4 : 3;
                } else {
                    quadrant = further ? 2 : 1;
                }
                var pivot, opposite, cornerResult, expanding;
                if (quadrant === 4) {
                    pivot = topLeft;
                    opposite = bottomRight;
                    expanding = cursor.row > opposite.row || cursor.col > opposite.col;
                    if (expanding) {
                        cursor = new CellRef(Math.max(cursor.row, opposite.row), Math.max(cursor.col, opposite.col));
                    }
                    if (this.rectIsVertical(opposite, cursor, 'right', 'bottom')) {
                        cornerResult = new CellRef(cursor.row, opposite.col);
                    } else {
                        cornerResult = new CellRef(opposite.row, cursor.col);
                    }
                } else if (quadrant === 3) {
                    var bottomLeft = new CellRef(topLeft.col, bottomRight.row);
                    if (cursor.row > bottomRight.row && this.rectIsVertical(bottomLeft, cursor, 'left', 'bottom')) {
                        pivot = topLeft;
                        cornerResult = new CellRef(cursor.row, bottomRight.col);
                    } else {
                        pivot = bottomRight;
                        cornerResult = new CellRef(topLeft.row, cursor.col);
                    }
                } else if (quadrant === 2) {
                    var topRight = new CellRef(topLeft.row, bottomRight.col);
                    if (cursor.col > bottomRight.col && !this.rectIsVertical(topRight, cursor, 'right', 'top')) {
                        pivot = topLeft;
                        cornerResult = new CellRef(bottomRight.row, cursor.col);
                    } else {
                        pivot = bottomRight;
                        cornerResult = new CellRef(cursor.row, topLeft.col);
                    }
                } else {
                    pivot = bottomRight;
                    if (this.rectIsVertical(topLeft, cursor, 'left', 'top')) {
                        cornerResult = new CellRef(cursor.row, topLeft.col);
                    } else {
                        cornerResult = new CellRef(topLeft.row, cursor.col);
                    }
                }
                return this._grid.normalize(new RangeRef(pivot, cornerResult));
            }
        });
        kendo.spreadsheet.AutoFillCalculator = AutoFillCalculator;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/navigator', [
        'kendo.core',
        'spreadsheet/autofillcalculator'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var RangeRef = kendo.spreadsheet.RangeRef;
        var CellRef = kendo.spreadsheet.CellRef;
        var EdgeNavigator = kendo.Class.extend({
            init: function (field, axis, rangeGetter, union) {
                this.rangeGetter = rangeGetter;
                this.prevLeft = function (index) {
                    var current = union(this.range(index));
                    var range = this.range(axis.prevVisible(current.topLeft[field]));
                    return union(range).topLeft[field];
                };
                this.nextRight = function (index) {
                    var current = union(this.range(index));
                    var range = this.range(axis.nextVisible(current.bottomRight[field]));
                    return union(range).bottomRight[field];
                };
                this.nextLeft = function (index) {
                    var range = union(this.range(index));
                    return axis.nextVisible(range.bottomRight[field]);
                };
                this.prevRight = function (index) {
                    var range = union(this.range(index));
                    return axis.prevVisible(range.topLeft[field]);
                };
            },
            boundary: function (top, bottom) {
                this.top = top;
                this.bottom = bottom;
            },
            range: function (index) {
                return this.rangeGetter(index, this.top, this.bottom);
            }
        });
        var SheetNavigator = kendo.Class.extend({
            init: function (sheet) {
                this._sheet = sheet;
                this.columns = this._sheet._grid._columns;
                this.autoFillCalculator = new kendo.spreadsheet.AutoFillCalculator(sheet._grid);
                this.colEdge = new EdgeNavigator('col', this._sheet._grid._columns, this.columnRange.bind(this), this.union.bind(this));
                this.rowEdge = new EdgeNavigator('row', this._sheet._grid._rows, this.rowRange.bind(this), this.union.bind(this));
            },
            height: function (height) {
                this._viewPortHeight = height;
            },
            union: function (ref) {
                return this._sheet.unionWithMerged(ref);
            },
            columnRange: function (col, topRow, bottomRow) {
                return this._sheet._ref(topRow, col, bottomRow - topRow, 1);
            },
            rowRange: function (row, leftCol, rightCol) {
                return this._sheet._ref(row, leftCol, 1, rightCol - leftCol);
            },
            selectionIncludesMergedCells: function () {
                return this._sheet.select().contains(this._sheet._mergedCells);
            },
            setSelectionValue: function (value) {
                var selection = this._sheet.selection();
                setTimeout(function () {
                    selection.value(value());
                });
            },
            selectAll: function () {
                this._sheet.select(this._sheet._sheetRef);
            },
            select: function (ref, mode, addToExisting) {
                ref = this.refForMode(ref, mode);
                if (addToExisting) {
                    ref = this._sheet.select().concat(ref);
                }
                this._sheet.select(ref);
            },
            refForMode: function (ref, mode) {
                var grid = this._sheet._grid;
                switch (mode) {
                case 'range':
                    ref = grid.normalize(ref);
                    break;
                case 'row':
                    ref = grid.rowRef(ref.row);
                    break;
                case 'column':
                    ref = grid.colRef(ref.col);
                    break;
                case 'sheet':
                    ref = this._sheet._sheetRef;
                    break;
                }
                return ref;
            },
            startSelection: function (ref, mode, addToExisting, shiftKey) {
                if (mode == 'autofill') {
                    this._sheet.startAutoFill();
                } else if (shiftKey && mode == 'range') {
                    var range = new RangeRef(this._sheet.activeCell().first(), ref);
                    this._sheet.select(range, false, false);
                    this._sheet.startSelection();
                } else {
                    this._sheet.startSelection();
                    this.select(ref, mode, addToExisting);
                }
            },
            completeSelection: function () {
                this._sheet.completeSelection();
            },
            selectForContextMenu: function (ref, mode) {
                var sheet = this._sheet;
                sheet._activeDrawing = null;
                if (!sheet.select().contains(this.refForMode(ref, mode))) {
                    this.select(ref, mode);
                }
            },
            selectDrawingForContextMenu: function (drawing) {
                var sheet = this._sheet;
                sheet._activeDrawing = drawing;
                sheet.triggerChange({ selection: true });
            },
            modifySelection: function (action) {
                var direction = this.determineDirection(action);
                var sheet = this._sheet;
                var viewPortHeight = this._viewPortHeight;
                var rows = sheet._grid._rows;
                var columns = sheet._grid._columns;
                var originalSelection = sheet.currentOriginalSelectionRange();
                var selection = sheet.select().toRangeRef();
                var activeCell = sheet.activeCell();
                var topLeft = originalSelection.topLeft.clone();
                var bottomRight = originalSelection.bottomRight.clone();
                var scrollInto;
                this.colEdge.boundary(selection.topLeft.row, selection.bottomRight.row);
                this.rowEdge.boundary(selection.topLeft.col, selection.bottomRight.col);
                switch (direction) {
                case 'expand-left':
                    topLeft.col = this.colEdge.prevLeft(topLeft.col);
                    scrollInto = topLeft;
                    break;
                case 'shrink-right':
                    topLeft.col = this.colEdge.nextLeft(topLeft.col);
                    scrollInto = topLeft;
                    break;
                case 'expand-right':
                    bottomRight.col = this.colEdge.nextRight(bottomRight.col);
                    scrollInto = bottomRight;
                    break;
                case 'shrink-left':
                    bottomRight.col = this.colEdge.prevRight(bottomRight.col);
                    scrollInto = bottomRight;
                    break;
                case 'expand-up':
                    topLeft.row = this.rowEdge.prevLeft(topLeft.row);
                    scrollInto = topLeft;
                    break;
                case 'shrink-down':
                    topLeft.row = this.rowEdge.nextLeft(topLeft.row);
                    scrollInto = topLeft;
                    break;
                case 'expand-down':
                    bottomRight.row = this.rowEdge.nextRight(bottomRight.row);
                    scrollInto = bottomRight;
                    break;
                case 'shrink-up':
                    bottomRight.row = this.rowEdge.prevRight(bottomRight.row);
                    scrollInto = bottomRight;
                    break;
                case 'expand-page-up':
                    topLeft.row = rows.prevPage(topLeft.row, viewPortHeight);
                    break;
                case 'shrink-page-up':
                    bottomRight.row = rows.prevPage(bottomRight.row, viewPortHeight);
                    break;
                case 'expand-page-down':
                    bottomRight.row = rows.nextPage(bottomRight.row, viewPortHeight);
                    break;
                case 'shrink-page-down':
                    topLeft.row = rows.nextPage(topLeft.row, viewPortHeight);
                    break;
                case 'first-col':
                    topLeft.col = columns.firstVisible();
                    bottomRight.col = activeCell.bottomRight.col;
                    scrollInto = topLeft;
                    break;
                case 'last-col':
                    bottomRight.col = columns.lastVisible();
                    topLeft.col = activeCell.topLeft.col;
                    scrollInto = bottomRight;
                    break;
                case 'first-row':
                    topLeft.row = rows.firstVisible();
                    bottomRight.row = activeCell.bottomRight.row;
                    scrollInto = topLeft;
                    break;
                case 'last-row':
                    bottomRight.row = rows.lastVisible();
                    topLeft.row = activeCell.topLeft.row;
                    scrollInto = bottomRight;
                    break;
                case 'last':
                    bottomRight.row = rows.lastVisible();
                    bottomRight.col = columns.lastVisible();
                    topLeft = activeCell.topLeft;
                    scrollInto = bottomRight;
                    break;
                case 'first':
                    topLeft.row = rows.firstVisible();
                    topLeft.col = columns.firstVisible();
                    bottomRight = activeCell.bottomRight;
                    scrollInto = topLeft;
                    break;
                }
                var newSelection = new RangeRef(topLeft, bottomRight);
                if (!this.union(newSelection).intersects(activeCell)) {
                    this.modifySelection(direction.replace('shrink', 'expand'));
                    return;
                }
                if (scrollInto) {
                    sheet.focus(scrollInto);
                }
                this.updateCurrentSelectionRange(newSelection);
            },
            moveActiveCell: function (direction) {
                var sheet = this._sheet;
                var activeCell = sheet.activeCell();
                var topLeft = activeCell.topLeft;
                var bottomRight = activeCell.bottomRight;
                var cell = sheet.originalActiveCell();
                var rows = sheet._grid._rows;
                var columns = sheet._grid._columns;
                var row = cell.row;
                var column = cell.col;
                switch (direction) {
                case 'left':
                    column = columns.prevVisible(topLeft.col);
                    break;
                case 'up':
                    row = rows.prevVisible(topLeft.row);
                    break;
                case 'right':
                    column = columns.nextVisible(bottomRight.col);
                    break;
                case 'down':
                    row = rows.nextVisible(bottomRight.row);
                    break;
                case 'first-col':
                    column = columns.firstVisible();
                    break;
                case 'last-col':
                    column = columns.lastVisible();
                    break;
                case 'first-row':
                    row = rows.firstVisible();
                    break;
                case 'last-row':
                    row = rows.lastVisible();
                    break;
                case 'last':
                    row = rows.lastVisible();
                    column = columns.lastVisible();
                    break;
                case 'first':
                    row = rows.firstVisible();
                    column = columns.firstVisible();
                    break;
                case 'next-page':
                    row = rows.nextPage(bottomRight.row, this._viewPortHeight);
                    break;
                case 'prev-page':
                    row = rows.prevPage(bottomRight.row, this._viewPortHeight);
                    break;
                }
                sheet.select(new CellRef(row, column));
            },
            navigateInSelection: function (direction) {
                var sheet = this._sheet;
                var activeCell = sheet.activeCell();
                var topLeft = activeCell.topLeft;
                var cell = sheet.originalActiveCell();
                var rows = sheet._grid._rows;
                var columns = sheet._grid._columns;
                var row = cell.row;
                var column = cell.col;
                var selTopLeft, selBottomRight;
                var topLeftCol = topLeft.col;
                var topLeftRow = topLeft.row;
                var tmp;
                function setSelection(sel) {
                    selTopLeft = sel.topLeft;
                    selBottomRight = sel.bottomRight;
                }
                setSelection(sheet.currentNavigationRange());
                var done = false;
                while (!done) {
                    var current = new CellRef(row, column);
                    switch (direction) {
                    case 'next':
                        if (selBottomRight.eq(current)) {
                            setSelection(sheet.nextNavigationRange());
                            row = selTopLeft.row;
                            column = selTopLeft.col;
                        } else {
                            column = columns.nextVisible(topLeftCol);
                            if (column == topLeftCol || column > selBottomRight.col) {
                                column = selTopLeft.col;
                                tmp = rows.nextVisible(row);
                                if (tmp == row || tmp > selBottomRight.row) {
                                    row = selTopLeft.row;
                                } else {
                                    row = tmp;
                                }
                            }
                        }
                        break;
                    case 'previous':
                        if (selTopLeft.eq(current)) {
                            setSelection(sheet.previousNavigationRange());
                            row = selBottomRight.row;
                            column = selBottomRight.col;
                        } else {
                            column = columns.prevVisible(topLeftCol);
                            if (column == topLeftCol || column < selTopLeft.col) {
                                column = selBottomRight.col;
                                tmp = rows.prevVisible(row);
                                if (tmp == row || tmp < selTopLeft.row) {
                                    row = selBottomRight.row;
                                } else {
                                    row = tmp;
                                }
                            }
                        }
                        break;
                    case 'lower':
                        if (selBottomRight.eq(current)) {
                            setSelection(sheet.nextNavigationRange());
                            row = selTopLeft.row;
                            column = selTopLeft.col;
                        } else {
                            row = rows.nextVisible(topLeftRow);
                            if (row == topLeftRow || row > selBottomRight.row) {
                                row = selTopLeft.row;
                                tmp = columns.nextVisible(column);
                                if (tmp == column || tmp > selBottomRight.col) {
                                    column = selTopLeft.col;
                                } else {
                                    column = tmp;
                                }
                            }
                        }
                        break;
                    case 'upper':
                        if (selTopLeft.eq(current)) {
                            setSelection(sheet.previousNavigationRange());
                            row = selBottomRight.row;
                            column = selBottomRight.col;
                        } else {
                            row = rows.prevVisible(topLeftRow);
                            if (row == topLeftRow || row < selTopLeft.row) {
                                row = selBottomRight.row;
                                tmp = columns.prevVisible(column);
                                if (tmp == column || tmp < selTopLeft.col) {
                                    column = selBottomRight.col;
                                } else {
                                    column = tmp;
                                }
                            }
                        }
                        break;
                    default:
                        throw new Error('Unknown entry navigation: ' + direction);
                    }
                    done = !this.shouldSkip(row, column);
                    topLeftCol = column;
                    topLeftRow = row;
                }
                if (sheet.singleCellSelection()) {
                    sheet.select(new CellRef(row, column));
                } else {
                    sheet.activeCell(new CellRef(row, column));
                }
            },
            extendSelection: function (ref, mode) {
                var sheet = this._sheet;
                var grid = sheet._grid;
                if (mode === 'autofill') {
                    this.resizeAutoFill(ref);
                    return;
                }
                if (mode === 'range') {
                    ref = grid.normalize(ref);
                } else if (mode === 'row') {
                    ref = grid.rowRef(ref.row).bottomRight;
                } else if (mode === 'column') {
                    ref = grid.colRef(ref.col).bottomRight;
                }
                var activeCell = sheet.originalActiveCell().toRangeRef();
                this.updateCurrentSelectionRange(new RangeRef(activeCell.topLeft, ref));
            },
            shouldSkip: function (row, col) {
                if (this._sheet.isHiddenRow(row) || this._sheet.isHiddenColumn(col)) {
                    return true;
                }
                var ref = new CellRef(row, col);
                var isMerged = false;
                this._sheet.forEachMergedCell(function (merged) {
                    if (merged.intersects(ref) && !merged.collapse().eq(ref)) {
                        isMerged = true;
                    }
                });
                return isMerged;
            },
            resizeAutoFill: function (ref) {
                var sheet = this._sheet;
                var selection = sheet.select();
                var origin = sheet._autoFillOrigin;
                var dest = this.autoFillCalculator.autoFillDest(selection, ref);
                var punch = this.punch(selection, dest);
                var hint, direction;
                if (!punch) {
                    var preview = sheet.range(dest)._previewFillFrom(sheet.range(origin));
                    if (preview) {
                        direction = preview.direction;
                        hint = preview.hint;
                    }
                }
                sheet.updateAutoFill(dest, punch, hint, direction);
            },
            determineDirection: function (action) {
                var selection = this._sheet.currentSelectionRange();
                var activeCell = this._sheet.activeCell();
                var leftMode = activeCell.topLeft.col == selection.topLeft.col;
                var rightMode = activeCell.bottomRight.col == selection.bottomRight.col;
                var topMode = activeCell.topLeft.row == selection.topLeft.row;
                var bottomMode = activeCell.bottomRight.row == selection.bottomRight.row;
                switch (action) {
                case 'left':
                    action = rightMode ? 'expand-left' : 'shrink-left';
                    break;
                case 'right':
                    action = leftMode ? 'expand-right' : 'shrink-right';
                    break;
                case 'up':
                    action = bottomMode ? 'expand-up' : 'shrink-up';
                    break;
                case 'down':
                    action = topMode ? 'expand-down' : 'shrink-down';
                    break;
                case 'prev-page':
                    action = bottomMode ? 'expand-page-up' : 'shrink-page-up';
                    break;
                case 'next-page':
                    action = topMode ? 'expand-page-down' : 'shrink-page-down';
                    break;
                }
                return action;
            },
            updateCurrentSelectionRange: function (ref) {
                var sheet = this._sheet;
                sheet.select(sheet.originalSelect().replaceAt(sheet.selectionRangeIndex(), ref), false);
            },
            punch: function (selection, subset) {
                var punch;
                if (subset.topLeft.eq(selection.topLeft)) {
                    if (subset.bottomRight.row < selection.bottomRight.row) {
                        var bottomRow = this.rowEdge.nextRight(subset.bottomRight.row);
                        punch = new RangeRef(new CellRef(bottomRow, selection.topLeft.col), selection.bottomRight);
                    } else if (subset.bottomRight.col < selection.bottomRight.col) {
                        var bottomCol = this.colEdge.nextRight(subset.bottomRight.col);
                        punch = new RangeRef(new CellRef(selection.topLeft.row, bottomCol), selection.bottomRight);
                    }
                }
                return punch;
            }
        });
        kendo.spreadsheet.SheetNavigator = SheetNavigator;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/axismanager', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var AxisManager = kendo.Class.extend({
            init: function (sheet) {
                this._sheet = sheet;
            },
            forEachSelectedColumn: function (callback) {
                var sheet = this._sheet;
                sheet.batch(function () {
                    sheet.select().forEachColumnIndex(function (index, i) {
                        callback(sheet, index, i);
                    });
                }, {
                    layout: true,
                    recalc: true
                });
            },
            forEachSelectedRow: function (callback) {
                var sheet = this._sheet;
                sheet.batch(function () {
                    sheet.select().forEachRowIndex(function (index, i) {
                        callback(sheet, index, i);
                    });
                }, {
                    layout: true,
                    recalc: true
                });
            },
            includesHiddenColumns: function (ref) {
                return this._sheet._grid._columns.includesHidden(ref.topLeft.col, ref.bottomRight.col);
            },
            includesHiddenRows: function (ref) {
                return this._sheet._grid._rows.includesHidden(ref.topLeft.row, ref.bottomRight.row);
            },
            selectionIncludesHiddenColumns: function () {
                return this.includesHiddenColumns(this._sheet.select());
            },
            selectionIncludesHiddenRows: function () {
                return this.includesHiddenRows(this._sheet.select());
            },
            deleteSelectedColumns: function () {
                var indexes = [], delta = 0;
                this.forEachSelectedColumn(function (sheet, index) {
                    index -= delta;
                    if (sheet.isHiddenColumn(index)) {
                        return;
                    }
                    delta++;
                    var formulas = [];
                    indexes.unshift({
                        index: index,
                        formulas: formulas,
                        width: sheet.columnWidth(index)
                    });
                    sheet._saveModifiedFormulas(formulas, function () {
                        sheet.deleteColumn(index);
                    });
                });
                return indexes;
            },
            deleteSelectedRows: function () {
                var indexes = [], delta = 0;
                this.forEachSelectedRow(function (sheet, index) {
                    index -= delta;
                    if (sheet.isHiddenRow(index)) {
                        return;
                    }
                    delta++;
                    var formulas = [];
                    indexes.unshift({
                        index: index,
                        formulas: formulas,
                        height: sheet.rowHeight(index)
                    });
                    sheet._saveModifiedFormulas(formulas, function () {
                        sheet.deleteRow(index);
                    });
                });
                return indexes;
            },
            hideSelectedColumns: function () {
                this.forEachSelectedColumn(function (sheet, index) {
                    sheet.hideColumn(index);
                });
                var sheet = this._sheet;
                var ref = sheet.select().toRangeRef();
                var left = ref.topLeft.col;
                var right = ref.bottomRight.col;
                var sel = null;
                while (true) {
                    var hasRight = right < sheet._columns._count;
                    var hasLeft = left >= 0;
                    if (!hasLeft && !hasRight) {
                        break;
                    }
                    if (hasRight && !sheet.isHiddenColumn(right)) {
                        sel = right;
                        break;
                    }
                    if (hasLeft && !sheet.isHiddenColumn(left)) {
                        sel = left;
                        break;
                    }
                    left--;
                    right++;
                }
                if (sel !== null) {
                    ref = new kendo.spreadsheet.RangeRef(new kendo.spreadsheet.CellRef(0, sel), new kendo.spreadsheet.CellRef(sheet._rows._count - 1, sel));
                    sheet.range(ref).select();
                }
            },
            hideSelectedRows: function () {
                this.forEachSelectedRow(function (sheet, index) {
                    sheet.hideRow(index);
                });
                var sheet = this._sheet;
                var ref = sheet.select().toRangeRef();
                var top = ref.topLeft.row;
                var bottom = ref.bottomRight.row;
                var sel = null;
                while (true) {
                    var hasBottom = bottom < sheet._rows._count;
                    var hasTop = top >= 0;
                    if (!hasTop && !hasBottom) {
                        break;
                    }
                    if (hasBottom && !sheet.isHiddenRow(bottom)) {
                        sel = bottom;
                        break;
                    }
                    if (hasTop && !sheet.isHiddenRow(top)) {
                        sel = top;
                        break;
                    }
                    top--;
                    bottom++;
                }
                if (sel !== null) {
                    ref = new kendo.spreadsheet.RangeRef(new kendo.spreadsheet.CellRef(sel, 0), new kendo.spreadsheet.CellRef(sel, sheet._columns._count - 1));
                    sheet.range(ref).select();
                }
            },
            unhideSelectedColumns: function () {
                this.forEachSelectedColumn(function (sheet, index) {
                    sheet.unhideColumn(index);
                });
            },
            unhideSelectedRows: function () {
                this.forEachSelectedRow(function (sheet, index) {
                    sheet.unhideRow(index);
                });
            },
            preventAddRow: function () {
                var range = this._sheet.select().toRangeRef();
                var rowCount = range.height();
                return this._sheet.preventInsertRow(0, rowCount);
            },
            preventAddColumn: function () {
                var range = this._sheet.select().toRangeRef();
                var columnCount = range.width();
                return this._sheet.preventInsertColumn(0, columnCount);
            },
            addColumnLeft: function () {
                var sheet = this._sheet;
                var base, count = 0;
                sheet.batch(function () {
                    sheet.select().forEachColumnIndex(function (index) {
                        if (!base) {
                            base = index;
                        }
                        sheet.insertColumn(base);
                        ++count;
                    });
                }, {
                    recalc: true,
                    layout: true
                });
                return {
                    base: base,
                    count: count
                };
            },
            addColumnRight: function () {
                var sheet = this._sheet;
                var base, count = 0;
                sheet.batch(function () {
                    sheet.select().forEachColumnIndex(function (index) {
                        base = index + 1;
                        ++count;
                    });
                    for (var i = 0; i < count; ++i) {
                        sheet.insertColumn(base);
                    }
                }, {
                    recalc: true,
                    layout: true
                });
                return {
                    base: base,
                    count: count
                };
            },
            addRowAbove: function () {
                var sheet = this._sheet;
                var base, count = 0;
                sheet.batch(function () {
                    sheet.select().forEachRowIndex(function (index) {
                        if (!base) {
                            base = index;
                        }
                        sheet.insertRow(base);
                        ++count;
                    });
                }, {
                    recalc: true,
                    layout: true
                });
                return {
                    base: base,
                    count: count
                };
            },
            addRowBelow: function () {
                var sheet = this._sheet;
                var base, count = 0;
                sheet.batch(function () {
                    sheet.select().forEachRowIndex(function (index) {
                        base = index + 1;
                        ++count;
                    });
                    for (var i = 0; i < count; ++i) {
                        sheet.insertRow(base);
                    }
                }, {
                    recalc: true,
                    layout: true
                });
                return {
                    base: base,
                    count: count
                };
            }
        });
        kendo.spreadsheet.AxisManager = AxisManager;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/clipboard', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var CellRef = kendo.spreadsheet.CellRef;
        var Clipboard = kendo.Class.extend({
            init: function (workbook) {
                this._content = {};
                this._externalContent = {};
                this._internalContent = {};
                this.workbook = workbook;
                this.origin = kendo.spreadsheet.NULLREF;
                this.iframe = document.createElement('iframe');
                this.iframe.className = 'k-spreadsheet-clipboard-paste';
                this.menuInvoked = false;
                this._uid = kendo.guid();
                document.body.appendChild(this.iframe);
            },
            destroy: function () {
                document.body.removeChild(this.iframe);
            },
            canCopy: function () {
                var status = { canCopy: true };
                var selection = this.workbook.activeSheet().select();
                if (selection === kendo.spreadsheet.NULLREF) {
                    status.canCopy = false;
                }
                if (selection instanceof kendo.spreadsheet.UnionRef) {
                    status.canCopy = false;
                    status.multiSelection = true;
                }
                if (this.menuInvoked) {
                    status.canCopy = false;
                    status.menuInvoked = true;
                }
                return status;
            },
            canPaste: function () {
                var sheet = this.workbook.activeSheet();
                var ref = this.pasteRef();
                var range = sheet.range(ref);
                var status = {
                    canPaste: true,
                    pasteOnMerged: false,
                    pasteOnDisabled: false
                };
                if (!range.enable()) {
                    status.canPaste = false;
                    status.pasteOnDisabled = true;
                }
                if (!ref.eq(sheet.unionWithMerged(ref))) {
                    status.canPaste = false;
                    status.pasteOnMerged = true;
                }
                if (this.menuInvoked) {
                    status.canPaste = false;
                    status.menuInvoked = true;
                }
                if (ref.bottomRight.row >= sheet._rows._count || ref.bottomRight.col >= sheet._columns._count) {
                    status.canPaste = false;
                    status.overflow = true;
                }
                return status;
            },
            intersectsMerged: function () {
                var sheet = this.workbook.activeSheet();
                this.parse();
                this.origin = this._content.origRef;
                var ref = this.pasteRef();
                return !ref.eq(sheet.unionWithMerged(ref));
            },
            copy: function () {
                var sheet = this.workbook.activeSheet();
                this.origin = sheet.select();
                this._internalContent = sheet.selection().getState();
                delete this._externalContent.html;
                delete this._externalContent.plain;
            },
            cut: function () {
                var sheet = this.workbook.activeSheet();
                this.copy();
                sheet.range(sheet.select()).clear();
            },
            pasteRef: function () {
                var sheet = this.workbook.activeSheet();
                if (this.origin === kendo.spreadsheet.NULLREF) {
                    return sheet.select();
                }
                var destination = sheet.activeCell().first();
                var originActiveCell = this.origin.first();
                var rowDelta = originActiveCell.row - destination.row;
                var colDelta = originActiveCell.col - destination.col;
                return this.origin.relative(rowDelta, colDelta, 3);
            },
            paste: function () {
                var sheet = this.workbook.activeSheet();
                var pasteRef = this.pasteRef();
                sheet.range(pasteRef).setState(this._content, this);
                sheet.triggerChange({
                    recalc: true,
                    ref: pasteRef
                });
            },
            external: function (data) {
                if (data && (data.html || data.plain)) {
                    this._externalContent = data;
                } else {
                    return this._externalContent;
                }
            },
            isExternal: function () {
                return !this._isInternal();
            },
            parse: function () {
                var state = newState();
                if (this._isInternal()) {
                    state = this._internalContent;
                } else {
                    var data = this._externalContent;
                    if (data.html) {
                        var doc = this.iframe.contentWindow.document;
                        doc.open();
                        doc.write(data.html);
                        doc.close();
                        var table = doc.querySelector('table');
                        if (table) {
                            state = parseHTML(table);
                        } else {
                            state = parseTSV(data.plain);
                        }
                    } else {
                        state = parseTSV(data.plain);
                    }
                    this.origin = state.origRef;
                }
                this._content = state;
            },
            _isInternal: function () {
                if (this._externalContent.html === undefined) {
                    return true;
                }
                var internalHTML = $('<div/>').html(this._externalContent.html).find('table.kendo-clipboard-' + this._uid).length ? true : false;
                var internalPlain = $('<div/>').html(this._externalContent.plain).find('table.kendo-clipboard-' + this._uid).length ? true : false;
                return internalHTML || internalPlain;
            }
        });
        kendo.spreadsheet.Clipboard = Clipboard;
        function newState() {
            var ref = new CellRef(0, 0, 0);
            return {
                ref: ref,
                mergedCells: [],
                data: [],
                foreign: true,
                origRef: ref.toRangeRef()
            };
        }
        function setStateData(state, row, col, value) {
            var data = state.data || (state.data = []);
            if (!data[row]) {
                data[row] = [];
            }
            data[row][col] = value;
            var br = state.origRef.bottomRight;
            br.row = Math.max(br.row, row);
            br.col = Math.max(br.col, col);
        }
        function stripStyle(style) {
            return style.replace(/^-(?:ms|moz|webkit)-/, '');
        }
        function borderObject(styles) {
            var obj = {};
            [
                'borderBottom',
                'borderRight',
                'borderLeft',
                'borderTop'
            ].forEach(function (key) {
                obj[key] = styles[key + 'Style'] == 'none' ? null : {
                    size: 1,
                    color: styles[key + 'Color']
                };
            });
            return obj;
        }
        function cellState(row, col, element, hBorders, vBorders) {
            var styles = window.getComputedStyle(element);
            var text = element.innerText.replace(/\t$/, '');
            var borders = borderObject(styles);
            var state = {
                value: text === '' ? null : text,
                borderTop: borders.borderTop || hBorders.get(row, col) || null,
                borderBottom: borders.borderBottom || hBorders.get(row + 1, col) || null,
                borderLeft: borders.borderLeft || vBorders.get(row, col) || null,
                borderRight: borders.borderRight || vBorders.get(row, col + 1) || null,
                fontSize: parseInt(styles['font-size'], 10)
            };
            hBorders.set(row, col, state.borderTop);
            hBorders.set(row + 1, col, state.borderBottom);
            vBorders.set(row, col, state.borderLeft);
            vBorders.set(row, col + 1, state.borderRight);
            if (styles['background-color'] !== 'rgb(0, 0, 0)' && styles['background-color'] !== 'rgba(0, 0, 0, 0)') {
                state.background = styles['background-color'];
            }
            if (styles.color !== 'rgb(0, 0, 0)' && styles.color !== 'rgba(0, 0, 0, 0)') {
                state.color = styles.color;
            }
            if (styles['text-decoration'] == 'underline') {
                state.underline = true;
            }
            if (styles['font-style'] == 'italic') {
                state.italic = true;
            }
            if (styles['font-weight'] == 'bold') {
                state.bold = true;
            }
            if (stripStyle(styles['text-align']) !== 'right') {
                state.textAlign = stripStyle(styles['text-align']);
            }
            if (styles['vertical-align'] !== 'middle') {
                state.verticalAlign = styles['vertical-align'];
            }
            if (styles['word-wrap'] !== 'normal') {
                state.wrap = true;
            }
            return state;
        }
        function parseHTML(table) {
            var state = newState();
            var done = [], row = 0, col = 0;
            for (var i = 0; i < table.rows.length; ++i) {
                done.push([]);
            }
            var hBorders = new kendo.spreadsheet.calc.runtime.Matrix();
            var vBorders = new kendo.spreadsheet.calc.runtime.Matrix();
            for (var ri = 0; ri < table.rows.length; ++ri, ++row) {
                var tr = table.rows[ri];
                col = 0;
                for (var ci = 0; ci < tr.cells.length; ++ci) {
                    var td = tr.cells[ci];
                    var rowSpan = td.rowSpan;
                    var colSpan = td.colSpan;
                    while (done[row][col]) {
                        col++;
                    }
                    var style = td.getAttribute('style');
                    var ignoreColspan = /mso-ignore:colspan/.test(style);
                    setStateData(state, row, col, cellState(row, col, td, hBorders, vBorders));
                    if (rowSpan > 1 || colSpan > 1 && !ignoreColspan) {
                        state.mergedCells.push(new kendo.spreadsheet.RangeRef(new CellRef(row, col), new CellRef(row + rowSpan - 1, col + colSpan - 1)).toString());
                    }
                    for (var dr = row + rowSpan; --dr >= row;) {
                        for (var dc = col + colSpan; --dc >= col;) {
                            if (dr < done.length) {
                                done[dr][dc] = true;
                                if (!(dr == row && dc == col)) {
                                    setStateData(state, dr, dc, {});
                                }
                            }
                        }
                    }
                }
            }
            return state;
        }
        function parseTSV(data) {
            var state = newState();
            if (data.indexOf('\t') === -1 && data.indexOf('\n') == -1) {
                setStateData(state, 0, 0, { value: data });
            } else {
                var rows = data.split('\n');
                for (var ri = 0; ri < rows.length; ri++) {
                    var cols = rows[ri].split('\t');
                    for (var ci = 0; ci < cols.length; ci++) {
                        setStateData(state, ri, ci, { value: cols[ci] });
                    }
                }
            }
            return state;
        }
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/range', [
        'kendo.core',
        'util/text-metrics',
        'util/main'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var UnionRef = kendo.spreadsheet.UnionRef;
        var CellRef = kendo.spreadsheet.CellRef;
        var RangeRef = kendo.spreadsheet.RangeRef;
        var PROPERTIES = [
            'color',
            'fontFamily',
            'underline',
            'italic',
            'bold',
            'textAlign',
            'indent',
            'verticalAlign',
            'background',
            'format',
            'link',
            'editor',
            'borderTop',
            'borderRight',
            'borderBottom',
            'borderLeft',
            'comment'
        ];
        var Range = kendo.Class.extend({
            init: function (ref, sheet) {
                this._sheet = sheet;
                this._ref = ref;
            },
            clone: function () {
                return new Range(this._ref.clone(), this._sheet);
            },
            skipHiddenCells: function () {
                var refs = [];
                var self = this, sheet = self._sheet;
                var skipHiddenRows = sheet.isHiddenRow.bind(sheet);
                var skipHiddenCols = sheet.isHiddenColumn.bind(sheet);
                self._ref.forEach(function (ref) {
                    ref = self._normalize(ref.toRangeRef());
                    var tl = ref.topLeft, br = ref.bottomRight;
                    var rows = partition(tl.row, br.row, skipHiddenRows);
                    var cols = partition(tl.col, br.col, skipHiddenCols);
                    for (var i = 0; i < rows.length; ++i) {
                        for (var j = 0; j < cols.length; ++j) {
                            refs.push(new RangeRef(new CellRef(rows[i].begin, cols[j].begin), new CellRef(rows[i].end, cols[j].end)));
                        }
                    }
                });
                return sheet.range(refs.length > 1 ? new UnionRef(refs) : refs[0]);
            },
            _normalize: function (ref) {
                return this._sheet._grid.normalize(ref);
            },
            _set: function (name, value, noTrigger) {
                var self = this;
                var sheet = self._sheet;
                self._ref.forEach(function (ref) {
                    sheet._set(ref.toRangeRef(), name, value);
                });
                if (!noTrigger) {
                    sheet.triggerChange({
                        recalc: name == 'formula' || name == 'value' || name == 'validation',
                        value: value,
                        range: self,
                        ref: self._ref
                    });
                }
                return self;
            },
            _get: function (name) {
                return this._sheet._get(this._ref.toRangeRef(), name);
            },
            _property: function (name, value) {
                if (value === undefined) {
                    return this._get(name);
                } else {
                    return this._set(name, value);
                }
            },
            value: function (value) {
                if (value !== undefined) {
                    this._set('formula', null, true);
                }
                return this._property('value', value);
            },
            resize: function (direction) {
                var ref = this._resizedRef(direction);
                return new Range(ref, this._sheet);
            },
            _resizedRef: function (direction) {
                return this._ref.map(function (ref) {
                    return ref.toRangeRef().resize(direction);
                });
            },
            input: function (value, options) {
                options = $.extend({ arrayFormula: false }, options);
                var existingFormat = this._get('format'), x;
                if (value !== undefined) {
                    var tl = this._ref.toRangeRef().topLeft;
                    x = kendo.spreadsheet.calc.parse(this._sheet.name(), tl.row, tl.col, value, existingFormat);
                    this._sheet.batch(function () {
                        var formula = null;
                        if (x.type == 'exp') {
                            formula = kendo.spreadsheet.calc.compile(x);
                        } else if (existingFormat != '@') {
                            var existingFormatType = existingFormat && kendo.spreadsheet.formatting.type(x.value, existingFormat);
                            if (x.type == 'date' && existingFormatType != 'date') {
                                this.format(x.format || toExcelFormat(kendo.culture().calendar.patterns.d));
                            } else if (x.type == 'percent' && existingFormatType != 'percent') {
                                this.format(x.value * 100 == (x.value * 100 | 0) ? '0%' : '0.00%');
                            } else if (x.format) {
                                if (!existingFormat || x.currency || existingFormatType == 'number' && x.type == 'number' && x.format.length > existingFormat.length) {
                                    this.format(x.format);
                                }
                            }
                        } else if (x.type != 'string') {
                            x.value = value;
                        }
                        this.formula(formula, options.arrayFormula);
                        if (!formula) {
                            this.value(x.value);
                        }
                    }.bind(this), {
                        recalc: true,
                        value: value,
                        ref: this._ref,
                        editorChange: this._sheet.isInEditMode()
                    });
                    return this;
                } else {
                    value = this._get('value');
                    var formula = this._get('formula');
                    var type = existingFormat && !formula && kendo.spreadsheet.formatting.type(value, existingFormat);
                    if (formula) {
                        value = '=' + formula;
                    } else
                        OUT: {
                            if (existingFormat && type == 'date') {
                                var t1 = kendo.spreadsheet.formatting.text(value, existingFormat);
                                x = kendo.spreadsheet.calc.parse(null, null, null, t1, existingFormat);
                                var t2 = kendo.spreadsheet.formatting.text(x.value, existingFormat);
                                if (t1 == t2) {
                                    value = t1;
                                    break OUT;
                                }
                            }
                            if (type === 'date') {
                                value = kendo.toString(kendo.spreadsheet.numberToDate(value), kendo.culture().calendar.patterns.d);
                            } else if (type === 'percent') {
                                value = kendo.spreadsheet.calc.runtime.limitPrecision(value * 100) + '%';
                            } else if (typeof value == 'string' && (/^[=']/.test(value) || /^(?:true|false)$/i.test(value) || looksLikeANumber(value))) {
                                value = '\'' + value;
                            } else if (this._sheet._useCultureDecimals() && typeof value == 'number' && value != Math.floor(value)) {
                                value = String(value).replace('.', kendo.culture().numberFormat['.']);
                            }
                        }
                    return value;
                }
            },
            enable: function (value) {
                if (value === undefined) {
                    return !kendo.util.withExit(function (exit) {
                        this._sheet.forEach(this._ref, function (_, __, data) {
                            if (data.enable === false) {
                                exit(true);
                            }
                        });
                    }, this);
                }
                return this._property('enable', value);
            },
            formula: function (value, arrayFormula) {
                var self = this;
                if (value === undefined) {
                    var f = self._get('formula');
                    return f ? '' + f : null;
                }
                if (arrayFormula) {
                    var ref = this._ref.toRangeRef();
                    value = self._sheet.range(ref.topLeft)._set('formula', value)._get('formula');
                    if (value) {
                        value.setArrayFormulaRange(ref);
                    }
                } else {
                    self._set('formula', value);
                }
                return self;
            },
            intersectingArrayFormula: function () {
                var ref = this._ref.clone().simplify().setSheet(this._sheet.name());
                return kendo.util.withExit(function (exit) {
                    this._sheet._forFormulas(function (f) {
                        var r = f.arrayFormulaRange;
                        if (r && (r = ref.intersect(r)) !== kendo.spreadsheet.NULLREF) {
                            exit({
                                formula: f,
                                intersection: r
                            });
                        }
                    });
                }, this);
            },
            canEditArrayFormula: function () {
                var x = this.intersectingArrayFormula();
                if (x) {
                    return x.formula.arrayFormulaRange.eq(x.intersection);
                }
                return true;
            },
            validation: function (value) {
                if (value === undefined) {
                    var f = this._get('validation');
                    return f ? f.toJSON() : null;
                }
                return this._property('validation', value);
            },
            _getValidationState: function () {
                var ref = this._ref.toRangeRef();
                var topLeftRow = ref.topLeft.row;
                var topLeftCol = ref.topLeft.col;
                var bottomRightRow = ref.bottomRight.row;
                var bottomRightCol = ref.bottomRight.col;
                var ci, ri;
                for (ci = topLeftCol; ci <= bottomRightCol; ci++) {
                    for (ri = topLeftRow; ri <= bottomRightRow; ri++) {
                        var validation = this._sheet._validation(ri, ci);
                        if (validation && validation.type === 'reject' && validation.value === false) {
                            return validation;
                        }
                    }
                }
                return false;
            },
            merge: function () {
                this._ref = this._sheet._merge(this._ref);
                return this;
            },
            unmerge: function () {
                var mergedCells = this._sheet._mergedCells;
                this._ref.forEach(function (ref) {
                    ref.toRangeRef().intersecting(mergedCells).forEach(function (mergedRef) {
                        mergedCells.splice(mergedCells.indexOf(mergedRef), 1);
                    });
                });
                this._sheet.triggerChange({});
                return this;
            },
            select: function () {
                this._sheet.select(this._ref);
                return this;
            },
            values: function (values) {
                if (this._ref instanceof UnionRef) {
                    throw new Error('Unsupported for multiple ranges.');
                }
                if (this._ref === kendo.spreadsheet.NULLREF) {
                    if (values !== undefined) {
                        throw new Error('Unsupported for NULLREF.');
                    } else {
                        return [];
                    }
                }
                var ref = this._ref.toRangeRef();
                var topLeftRow = ref.topLeft.row;
                var topLeftCol = ref.topLeft.col;
                var bottomRightRow = ref.bottomRight.row;
                var bottomRightCol = ref.bottomRight.col;
                var ci, ri;
                if (values === undefined) {
                    values = new Array(ref.height());
                    for (var vi = 0; vi < values.length; vi++) {
                        values[vi] = new Array(ref.width());
                    }
                    for (ci = topLeftCol; ci <= bottomRightCol; ci++) {
                        for (ri = topLeftRow; ri <= bottomRightRow; ri++) {
                            values[ri - topLeftRow][ci - topLeftCol] = this._sheet._value(ri, ci);
                        }
                    }
                    return values;
                } else {
                    this._sheet._set(ref, 'formula', null);
                    for (ci = topLeftCol; ci <= bottomRightCol; ci++) {
                        for (ri = topLeftRow; ri <= bottomRightRow; ri++) {
                            var row = values[ri - topLeftRow];
                            if (row) {
                                var value = row[ci - topLeftCol];
                                if (value !== undefined) {
                                    this._sheet._value(ri, ci, value);
                                }
                            }
                        }
                    }
                    this._sheet.triggerChange({
                        recalc: true,
                        ref: ref
                    });
                    return this;
                }
            },
            _properties: function (props, isAutofill) {
                if (this._ref instanceof UnionRef) {
                    throw new Error('Unsupported for multiple ranges.');
                }
                if (this._ref === kendo.spreadsheet.NULLREF) {
                    if (props !== undefined) {
                        throw new Error('Unsupported for NULLREF.');
                    } else {
                        return [];
                    }
                }
                var ref = this._ref.toRangeRef();
                var topLeftRow = ref.topLeft.row;
                var topLeftCol = ref.topLeft.col;
                var bottomRightRow = ref.bottomRight.row;
                var bottomRightCol = ref.bottomRight.col;
                var ci, ri;
                var sheet = this._sheet;
                if (props === undefined) {
                    props = new Array(ref.height());
                    sheet.forEach(ref, function (row, col, data) {
                        row -= topLeftRow;
                        col -= topLeftCol;
                        var line = props[row] || (props[row] = []);
                        line[col] = data;
                    });
                    return props;
                } else {
                    var data;
                    ref = ref.clone();
                    var setProp = function (propName) {
                        var propValue = data[propName];
                        ref.topLeft.row = ref.bottomRight.row = ri;
                        ref.topLeft.col = ref.bottomRight.col = ci;
                        if (propName == 'value') {
                            sheet._set(ref, 'formula', null);
                        }
                        sheet._set(ref, propName, propValue);
                    };
                    for (ci = topLeftCol; ci <= bottomRightCol; ci++) {
                        if (!isAutofill && sheet.isHiddenColumn(ci)) {
                            continue;
                        }
                        for (ri = topLeftRow; ri <= bottomRightRow; ri++) {
                            if (!isAutofill && sheet.isHiddenRow(ri)) {
                                continue;
                            }
                            if (isAutofill && sheet.isFilteredRow(ri)) {
                                continue;
                            }
                            var row = props[ri - topLeftRow];
                            if (row) {
                                data = row[ci - topLeftCol];
                                if (data) {
                                    Object.keys(data).forEach(setProp);
                                }
                            }
                        }
                    }
                    sheet.triggerChange({
                        recalc: true,
                        ref: this._ref
                    });
                    return this;
                }
            },
            clear: function (options) {
                options = options || {};
                var clearAll = options.clearAll || !Object.keys(options).length;
                var sheet = this._sheet;
                var reason = {
                    recalc: clearAll || options.contentsOnly,
                    ref: this._ref
                };
                sheet.batch(function () {
                    if (reason.recalc) {
                        this.formula(null);
                    }
                    if (clearAll) {
                        this.validation(null);
                    }
                    if (clearAll || options.formatOnly) {
                        PROPERTIES.forEach(function (x) {
                            if (!(options.keepBorders && /^border/i.test(x))) {
                                this[x](null);
                            }
                        }.bind(this));
                        this.fontSize(null);
                        this.wrap(null);
                        this.unmerge();
                    }
                }.bind(this), reason);
                return this;
            },
            clearContent: function () {
                return this.clear({ contentsOnly: true });
            },
            clearFormat: function () {
                return this.clear({ formatOnly: true });
            },
            isSortable: function () {
                return !this.cantSort();
            },
            cantSort: function () {
                if (this._ref instanceof UnionRef) {
                    return {
                        code: 'cantSortMultipleSelection',
                        message: 'Unsupported for multiple ranges.'
                    };
                }
                if (this._ref === kendo.spreadsheet.NULLREF) {
                    return {
                        code: 'cantSortNullRef',
                        message: 'Unsupported for NULLREF.'
                    };
                }
                var mc = this._sheet._getMergedCells(this._ref.toRangeRef());
                var primary = mc.primary;
                var secondary = mc.secondary;
                var width = null, height = null;
                var cant = {};
                try {
                    this._sheet.forEach(this, function (row, col) {
                        var id = new CellRef(row, col).print();
                        var merged = primary[id];
                        if (merged) {
                            if (width === null) {
                                width = merged.width();
                                height = merged.height();
                            } else if (!(width == merged.width() && height == merged.height())) {
                                throw cant;
                            }
                        } else if (!secondary[id] && mc.hasMerged) {
                            throw cant;
                        }
                    });
                } catch (ex) {
                    if (ex !== cant) {
                        throw ex;
                    }
                    return {
                        code: 'cantSortMixedCells',
                        message: 'Unsupported for range containing cells of different shapes.'
                    };
                }
                return false;
            },
            sort: function (spec) {
                var reason = this.cantSort();
                if (reason) {
                    throw new Error(reason.message);
                }
                if (spec === undefined) {
                    spec = { column: 0 };
                }
                spec = spec instanceof Array ? spec : [spec];
                this._sheet._sortBy(this._ref.toRangeRef(), spec.map(function (spec, index) {
                    if (typeof spec === 'number') {
                        spec = { column: spec };
                    }
                    return {
                        index: spec.column === undefined ? index : spec.column,
                        ascending: spec.ascending === undefined ? true : spec.ascending
                    };
                }));
                return this;
            },
            isFilterable: function () {
                return !(this._ref instanceof UnionRef);
            },
            filter: function (spec) {
                if (this._ref instanceof UnionRef) {
                    throw new Error('Unsupported for multiple ranges.');
                }
                if (spec === false) {
                    this.clearFilters();
                } else {
                    spec = spec === true ? [] : spec instanceof Array ? spec : [spec];
                    this._sheet._filterBy(this._ref.toRangeRef(), spec.map(function (spec, index) {
                        return {
                            index: spec.column === undefined ? index : spec.column,
                            filter: spec.filter
                        };
                    }));
                }
                return this;
            },
            clearFilter: function (spec) {
                this._sheet.clearFilter(spec);
            },
            clearFilters: function () {
                var filter = this._sheet.filter();
                var spec = [];
                if (filter) {
                    for (var i = 0; i < filter.columns.length; i++) {
                        spec.push(filter.columns[i].index);
                    }
                    this._sheet.batch(function () {
                        this.clearFilter(spec);
                        this._filter = null;
                    }, {
                        layout: true,
                        filter: true
                    });
                }
            },
            hasFilter: function () {
                var filter = this._sheet.filter();
                return !!filter;
            },
            leftColumn: function () {
                return new Range(this._ref.leftColumn(), this._sheet);
            },
            rightColumn: function () {
                return new Range(this._ref.rightColumn(), this._sheet);
            },
            topRow: function () {
                return new Range(this._ref.topRow(), this._sheet);
            },
            bottomRow: function () {
                return new Range(this._ref.bottomRow(), this._sheet);
            },
            column: function (column) {
                return new Range(this._ref.toColumn(column), this._sheet);
            },
            row: function (row) {
                return new Range(this._ref.toRow(row), this._sheet);
            },
            forEachRow: function (callback) {
                this._ref.forEachRow(function (ref) {
                    callback(new Range(ref, this._sheet));
                }.bind(this));
            },
            forEachColumn: function (callback) {
                this._ref.forEachColumn(function (ref) {
                    callback(new Range(ref, this._sheet));
                }.bind(this));
            },
            sheet: function () {
                return this._sheet;
            },
            topLeft: function () {
                return this._ref.toRangeRef().topLeft;
            },
            intersectingMerged: function () {
                var sheet = this._sheet;
                var mergedCells = [];
                sheet._mergedCells.forEach(function (ref) {
                    if (ref.intersects(this._ref)) {
                        mergedCells.push(ref.toString());
                    }
                }.bind(this));
                return mergedCells;
            },
            getState: function (propertyName) {
                var topLeft = this._ref.first();
                var state = {
                    ref: topLeft,
                    data: [],
                    origRef: this._ref,
                    rows: this._sheet._rows.getState()
                };
                var properties;
                if (!propertyName) {
                    properties = kendo.spreadsheet.ALL_PROPERTIES;
                    state.mergedCells = this.intersectingMerged();
                } else if (propertyName === 'input') {
                    properties = [
                        'value',
                        'formula'
                    ];
                } else if (propertyName === 'border') {
                    properties = [
                        'borderLeft',
                        'borderTop',
                        'borderRight',
                        'borderBottom'
                    ];
                } else {
                    properties = [propertyName];
                }
                var data = state.data;
                this.forEachCell(function (row, col, cell) {
                    var cellState = {};
                    var dr = row - topLeft.row;
                    var dc = col - topLeft.col;
                    if (!data[dr]) {
                        data[dr] = [];
                    }
                    data[dr][dc] = cellState;
                    properties.forEach(function (property) {
                        var value = typeof cell[property] == 'undefined' ? null : cell[property];
                        if (value instanceof kendo.spreadsheet.calc.runtime.Formula || value instanceof kendo.spreadsheet.validation.Validation) {
                            value = value.deepClone();
                        }
                        cellState[property] = value;
                    });
                });
                return state;
            },
            setState: function (state, clipboard) {
                var sheet = this._sheet;
                var origin = this._ref.first();
                var rowDelta = state.ref.row - origin.row;
                var colDelta = state.ref.col - origin.col;
                var internalClipboard = clipboard && !clipboard.isExternal();
                var externalClipboard = clipboard && !internalClipboard;
                sheet.batch(function () {
                    if (state.mergedCells) {
                        this.unmerge();
                    }
                    if (!clipboard) {
                        this._sheet._rows.setState(state.rows);
                    }
                    var row = origin.row;
                    var hasFilter = this.hasFilter();
                    state.data.forEach(function (data, dr) {
                        if (hasFilter && internalClipboard && sheet.isHiddenRow(state.ref.row + dr)) {
                            return;
                        }
                        var col = origin.col;
                        data.forEach(function (cellState, dc) {
                            if (hasFilter && internalClipboard && sheet.isHiddenColumn(state.ref.col + dc)) {
                                return;
                            }
                            var range = clipboard ? sheet.range(row, col) : sheet.range(origin.row + dr, origin.col + dc);
                            if (range.enable()) {
                                for (var property in cellState) {
                                    if (property != 'value') {
                                        if (!(clipboard && property == 'enable')) {
                                            range._set(property, cellState[property]);
                                        }
                                    }
                                }
                                if (!cellState.formula) {
                                    if (externalClipboard) {
                                        try {
                                            if (cellState.value == null) {
                                                range._set('value', null);
                                            } else {
                                                range.input(cellState.value);
                                            }
                                        } catch (ex) {
                                            range._set('value', cellState.value);
                                        }
                                    } else {
                                        range._set('value', cellState.value);
                                    }
                                }
                            }
                            col++;
                        });
                        row++;
                    });
                    if (state.mergedCells) {
                        state.mergedCells.forEach(function (merged) {
                            merged = sheet._ref(merged).relative(rowDelta, colDelta, 3);
                            sheet.range(merged).merge();
                        }, this);
                    }
                }.bind(this), {
                    recalc: true,
                    ref: this._ref
                });
            },
            _adjustRowHeight: function () {
                var that = this;
                var sheet = that._sheet;
                var mc = sheet._getMergedCells(that._ref.toRangeRef());
                var primary = mc.primary;
                var secondary = mc.secondary;
                sheet.batch(function () {
                    that.forEachRow(function (rowRange) {
                        var row = rowRange._ref.topLeft.row;
                        var height = sheet.rowHeight(row);
                        rowRange.forEachCell(function (row, col, cell) {
                            var id = new CellRef(row, col).print();
                            if (secondary[id]) {
                                return;
                            }
                            var merged = primary[id];
                            var width;
                            if (merged) {
                                width = sheet._columns.sum(merged.topLeft.col, merged.bottomRight.col);
                            } else {
                                width = sheet.columnWidth(col);
                            }
                            var data = cell.value;
                            if (cell.format && data != null) {
                                data = kendo.spreadsheet.formatting.format(data, cell.format);
                            }
                            var textHeight = kendo.spreadsheet.util.getTextHeight(data, width, cell.fontFamily, cell.fontSize, cell.wrap);
                            height = Math.max(height, textHeight);
                        });
                        sheet.rowHeight(row, height);
                    });
                }, { layout: true });
            },
            forEachCell: function (callback) {
                this._ref.forEach(function (ref) {
                    this._sheet.forEach(ref.toRangeRef(), callback.bind(this));
                }.bind(this));
            },
            hasValue: function () {
                var defStyle = this._sheet._defaultCellStyle;
                return kendo.util.withExit(function (exit) {
                    this.forEachCell(function (row, col, cell) {
                        for (var key in cell) {
                            var val = cell[key];
                            if (val !== undefined && val !== null && val !== defStyle[key]) {
                                exit(true);
                            }
                        }
                    });
                }, this);
            },
            wrap: function (flag) {
                if (flag === undefined) {
                    return !!this._property('wrap');
                }
                this._property('wrap', flag);
                if (flag !== null) {
                    this._adjustRowHeight();
                }
                return this;
            },
            fontSize: function (size) {
                if (size === undefined) {
                    return this._property('fontSize');
                }
                this._property('fontSize', size);
                if (size !== null) {
                    this._adjustRowHeight();
                }
                return this;
            },
            draw: function (options, callback) {
                this._sheet.draw(this, options, callback);
            },
            insideBorders: function (value) {
                return this.insideVerticalBorders(value).insideHorizontalBorders(value);
            },
            insideVerticalBorders: function (value) {
                this._ref.forEach(function (ref) {
                    if (ref instanceof RangeRef && ref.width() > 1) {
                        ref = ref.clone();
                        ref.topLeft.col++;
                        this._sheet.range(ref)._set('vBorders', value);
                    }
                }, this);
                return this;
            },
            insideHorizontalBorders: function (value) {
                this._ref.forEach(function (ref) {
                    if (ref instanceof RangeRef && ref.height() > 1) {
                        ref = ref.clone();
                        ref.topLeft.row++;
                        this._sheet.range(ref)._set('hBorders', value);
                    }
                }, this);
                return this;
            }
        });
        function partition(begin, end, predicate) {
            while (begin <= end && predicate(begin)) {
                begin++;
            }
            if (begin > end) {
                return [];
            }
            for (var i = begin + 1; i <= end; ++i) {
                if (predicate(i)) {
                    return [{
                            begin: begin,
                            end: i - 1
                        }].concat(partition(i + 1, end, predicate));
                }
            }
            return [{
                    begin: begin,
                    end: end
                }];
        }
        $.each(PROPERTIES, function (i, property) {
            Range.prototype[property] = function (value) {
                return this._property(property, value);
            };
        });
        function toExcelFormat(format) {
            return format.replace(/M/g, 'm').replace(/'/g, '"').replace(/tt/, 'am/pm');
        }
        function looksLikeANumber(str) {
            return !/^=/.test(str) && /number|percent/.test(kendo.spreadsheet.calc.parse(null, 0, 0, str).type);
        }
        var measureBox = $('<div style="position: absolute !important; top: -4000px !important; height: auto !important;' + 'padding: 1px 3px !important; box-sizing: border-box; margin: 0 !important; border: 1px solid black !important;' + 'line-height: normal !important; visibility: hidden !important;' + 'white-space: pre-wrap;" />')[0];
        function getTextHeight(text, width, fontFamily, fontSize, wrap) {
            var styles = {
                'baselineMarkerSize': 0,
                'width': wrap === true ? width + 'px' : 'auto',
                'font-size': (fontSize || 12) + 'px',
                'font-family': fontFamily || 'Arial',
                'white-space': wrap === true ? 'pre-wrap' : 'pre',
                'overflow-wrap': wrap === true ? 'break-word' : 'normal',
                'word-wrap': wrap === true ? 'break-word' : 'normal'
            };
            return kendo.util.measureText(text, styles, {
                box: measureBox,
                normalizeText: false
            }).height;
        }
        kendo.spreadsheet.util = { getTextHeight: getTextHeight };
        kendo.spreadsheet.Range = Range;
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/runtime', ['spreadsheet/references'], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var calc = {};
    var spreadsheet = kendo.spreadsheet;
    spreadsheet.calc = calc;
    var exports = calc.runtime = {};
    var Class = kendo.Class;
    var Ref = spreadsheet.Ref;
    var CellRef = spreadsheet.CellRef;
    var RangeRef = spreadsheet.RangeRef;
    var UnionRef = spreadsheet.UnionRef;
    var NULL = spreadsheet.NULLREF;
    function CalcError(code) {
        if (code instanceof CalcError) {
            return code;
        }
        this.code = code;
    }
    CalcError.prototype.toString = function () {
        return '#' + this.code + (this.code == 'NAME' ? '?' : '!');
    };
    var Context = Class.extend({
        init: function Context(callback, formula, ss, parent) {
            this.callback = callback;
            this.formula = formula;
            this.ss = ss;
            this.parent = parent;
        },
        resolve: function (val) {
            var self = this;
            if (val instanceof Ref) {
                self.resolveCells([val], function () {
                    self._resolve(val);
                });
            } else {
                self._resolve(val);
            }
        },
        error: function (val) {
            return new CalcError(val);
        },
        _resolve: function (val) {
            if (val === undefined) {
                val = null;
            } else if (Array.isArray(val)) {
                val = this.asMatrix(val);
            } else {
                val = maybeRoundFloatErrors(val);
            }
            var f = this.formula;
            if (f.arrayFormulaRange) {
                val = this.asMatrix(val) || this.asMatrix([[val]]);
            } else if (val instanceof RangeRef) {
                val = this._arrayArg(val);
            }
            f.value = val;
            if (this.ss.onFormula(f) && this.callback) {
                this.callback.call(f, val);
            }
        },
        resolveCells: function (a, f) {
            var context = this, formulas = [];
            (function loop(a) {
                for (var i = 0; i < a.length; ++i) {
                    var x = a[i];
                    if (x instanceof Ref) {
                        add(context.getRefCells(x));
                    }
                    if (Array.isArray(x)) {
                        loop(x);
                    }
                }
            }(a));
            if (!formulas.length) {
                return f.call(context);
            }
            for (var pending = formulas.length, i = 0; i < formulas.length; ++i) {
                fetch(formulas[i]);
            }
            function fetch(formula) {
                formula.exec(context.ss, function () {
                    if (!--pending) {
                        f.call(context);
                    }
                }, context);
            }
            function add(a) {
                for (var i = 0; i < a.length; ++i) {
                    var cell = a[i];
                    if (cell.formula) {
                        formulas.push(cell.formula);
                    }
                }
                return true;
            }
        },
        cellValues: function (a, wantNulls) {
            var ret = [];
            for (var i = 0; i < a.length; ++i) {
                var val = a[i];
                if (val instanceof Ref) {
                    val = this.getRefData(val, wantNulls);
                    ret = ret.concat(val);
                } else if (Array.isArray(val)) {
                    ret = ret.concat(this.cellValues(val, wantNulls));
                } else if (val instanceof Matrix) {
                    ret = ret.concat(this.cellValues(val.data, wantNulls));
                } else {
                    ret.push(val);
                }
            }
            return ret;
        },
        fetchName: function (ref, callback) {
            var f = this.formula;
            var val = this.ss.nameValue(ref, f.sheet, f.row, f.col);
            if (val instanceof Formula) {
                val = val.clone(f.sheet, f.row, f.col, true);
                var ss = new spreadsheet.ValidationFormulaContext(this.ss.workbook);
                val.exec(ss, callback, this);
            } else {
                if (val instanceof Ref) {
                    val = val.absolute(f.row, f.col);
                    if (!val.sheet) {
                        val.sheet = f.sheet;
                    }
                }
                callback(val == null ? new CalcError('NAME') : val);
            }
        },
        force: function (val) {
            if (val instanceof Ref) {
                return this.getRefData(val);
            }
            return val;
        },
        func: function (fname, callback, args) {
            fname = fname.toLowerCase();
            var f = FUNCS[fname];
            if (f) {
                return f.call(this, callback, args);
            }
            callback(new CalcError('NAME'));
        },
        bool: function (val) {
            if (val instanceof Ref) {
                val = this.getRefData(val);
            }
            if (typeof val == 'string') {
                return val.toLowerCase() == 'true';
            }
            if (typeof val == 'number') {
                return val !== 0;
            }
            if (typeof val == 'boolean') {
                return val;
            }
            return val != null;
        },
        _arrayArg: function (ref) {
            var f = this.formula;
            if (!f.arrayFormulaRange && ref instanceof RangeRef) {
                if (ref.height() == 1 && f.col >= ref.topLeft.col && f.col <= ref.bottomRight.col) {
                    return this.getRefData(new CellRef(ref.topLeft.row, f.col).setSheet(ref.sheet));
                }
                if (ref.width() == 1 && f.row >= ref.topLeft.row && f.row <= ref.bottomRight.row) {
                    return this.getRefData(new CellRef(f.row, ref.topLeft.col).setSheet(ref.sheet));
                }
                return new CalcError('VALUE');
            } else {
                return this.asMatrix(ref);
            }
        },
        asMatrix: function (range) {
            if (range instanceof Matrix) {
                return range;
            }
            var self = this;
            if (range instanceof RangeRef) {
                var tl = range.topLeft;
                var top = tl.row, left = tl.col;
                var cells = self.getRefCells(range);
                var m = new Matrix(self);
                if (isFinite(range.width())) {
                    m.width = range.width();
                }
                if (isFinite(range.height())) {
                    m.height = range.height();
                }
                if (!isFinite(top)) {
                    top = 0;
                }
                if (!isFinite(left)) {
                    left = 0;
                }
                cells.forEach(function (cell) {
                    m.set(cell.row - top, cell.col - left, cell.value);
                });
                return m;
            }
            if (Array.isArray(range) && range.length > 0) {
                var m = new Matrix(self), row = 0;
                range.forEach(function (line) {
                    var col = 0;
                    var h = 1;
                    line.forEach(function (el) {
                        var isRange = el instanceof RangeRef;
                        if (el instanceof Ref && !isRange) {
                            el = self.getRefData(el);
                        }
                        if (isRange || Array.isArray(el)) {
                            el = self.asMatrix(el);
                        }
                        if (el instanceof Matrix) {
                            el.each(function (el, r, c) {
                                m.set(row + r, col + c, el);
                            });
                            h = Math.max(h, el.height);
                            col += el.width;
                        } else {
                            m.set(row, col++, el);
                        }
                    });
                    row += h;
                });
                return m;
            }
        },
        getRefCells: function (refs, hiddenInfo, wantNulls) {
            var f = this.formula;
            return this.ss.getRefCells(refs, hiddenInfo, f.sheet, f.row, f.col, wantNulls);
        },
        getRefData: function (ref, wantNulls) {
            var f = this.formula;
            return this.ss.getData(ref, f.sheet, f.row, f.col, wantNulls);
        },
        workbook: function () {
            return this.ss.workbook;
        }
    });
    var Matrix = Class.extend({
        init: function Matrix(context) {
            this.context = context;
            this.height = 0;
            this.width = 0;
            this.data = [];
        },
        clone: function () {
            var m = new Matrix(this.context);
            m.height = this.height;
            m.width = this.width;
            m.data = this.data.map(function (row) {
                return row.slice();
            });
            return m;
        },
        get: function (row, col) {
            var line = this.data[row];
            var val = line ? line[col] : null;
            return val instanceof Ref ? this.context.getRefData(val) : val;
        },
        getNA: function (row, col) {
            if (row < this.height && col < this.width) {
                return this.get(row, col);
            }
            return new CalcError('N/A');
        },
        set: function (row, col, data) {
            var line = this.data[row];
            if (line == null) {
                line = this.data[row] = [];
            }
            line[col] = data;
            if (row >= this.height) {
                this.height = row + 1;
            }
            if (col >= this.width) {
                this.width = col + 1;
            }
        },
        each: function (f, includeEmpty) {
            for (var row = 0; row < this.height; ++row) {
                for (var col = 0; col < this.width; ++col) {
                    var val = this.get(row, col);
                    if (includeEmpty || val != null) {
                        val = f.call(this.context, val, row, col);
                        if (val !== undefined) {
                            return val;
                        }
                    }
                }
            }
        },
        map: function (f, includeEmpty) {
            var m = new Matrix(this.context);
            this.each(function (el, row, col) {
                m.set(row, col, f.call(this, el, row, col));
            }, includeEmpty);
            return m;
        },
        eachRow: function (f) {
            for (var row = 0; row < this.height; ++row) {
                var val = f.call(this.context, row);
                if (val !== undefined) {
                    return val;
                }
            }
        },
        eachCol: function (f) {
            for (var col = 0; col < this.width; ++col) {
                var val = f.call(this.context, col);
                if (val !== undefined) {
                    return val;
                }
            }
        },
        mapRow: function (f) {
            var m = new Matrix(this.context);
            this.eachRow(function (row) {
                m.set(row, 0, f.call(this.context, row));
            });
            return m;
        },
        mapCol: function (f) {
            var m = new Matrix(this.context);
            this.eachCol(function (col) {
                m.set(0, col, f.call(this.context, col));
            });
            return m;
        },
        toString: function () {
            return JSON.stringify(this.data);
        },
        transpose: function () {
            var m = new Matrix(this.context);
            this.each(function (el, row, col) {
                m.set(col, row, el);
            });
            return m;
        },
        unit: function (n) {
            this.width = this.height = n;
            var a = this.data = new Array(n);
            for (var i = n; --i >= 0;) {
                var row = a[i] = new Array(n);
                for (var j = n; --j >= 0;) {
                    row[j] = i == j ? 1 : 0;
                }
            }
            return this;
        },
        multiply: function (b) {
            var a = this, m = new Matrix(a.context);
            for (var row = 0; row < a.height; ++row) {
                for (var col = 0; col < b.width; ++col) {
                    var s = 0;
                    for (var i = 0; i < a.width; ++i) {
                        var va = a.get(row, i);
                        var vb = b.get(i, col);
                        if (typeof va != 'number' || typeof vb != 'number') {
                            throw new CalcError('VALUE');
                        }
                        s += va * vb;
                    }
                    m.set(row, col, s);
                }
            }
            return m;
        },
        adds: function (b, s) {
            var a = this, m = new Matrix(a.context);
            var sign = s ? -1 : 1;
            for (var row = 0; row < a.height; ++row) {
                for (var col = 0; col < a.width; ++col) {
                    var x = a.get(row, col), y = b.get(row, col);
                    m.set(row, col, x + sign * y);
                }
            }
            return m;
        },
        determinant: function () {
            var a = this.clone().data;
            var n = a.length;
            var d = 1, C, L, i, k;
            for (C = 0; C < n; C++) {
                for (L = C; L < n && !a[L][C]; L++) {
                }
                if (L == n) {
                    return 0;
                }
                if (L != C) {
                    d = -d;
                    for (k = C; k < n; k++) {
                        var t = a[C][k];
                        a[C][k] = a[L][k];
                        a[L][k] = t;
                    }
                }
                for (i = C + 1; i < n; i++) {
                    for (k = C + 1; k < n; k++) {
                        a[i][k] -= a[C][k] * a[i][C] / a[C][C];
                    }
                }
                d *= a[C][C];
            }
            return d;
        },
        inverse: function () {
            var n = this.width;
            var m = this.augment(new Matrix(this.context).unit(n));
            var a = m.data;
            var tmp;
            for (var k = 0; k < n; ++k) {
                var imax = argmax(k, n, function (i) {
                    return a[i][k];
                });
                if (!a[imax][k]) {
                    return null;
                }
                if (k != imax) {
                    tmp = a[k];
                    a[k] = a[imax];
                    a[imax] = tmp;
                }
                for (var i = k + 1; i < n; ++i) {
                    for (var j = k + 1; j < 2 * n; ++j) {
                        a[i][j] -= a[k][j] * a[i][k] / a[k][k];
                    }
                    a[i][k] = 0;
                }
            }
            for (var i = 0; i < n; ++i) {
                for (var f = a[i][i], j = 0; j < 2 * n; ++j) {
                    a[i][j] /= f;
                }
            }
            for (var k = n; --k >= 0;) {
                for (var i = k; --i >= 0;) {
                    if (a[i][k]) {
                        for (var j = 2 * n; --j >= n;) {
                            a[i][j] -= a[k][j] * a[i][k];
                        }
                    }
                }
            }
            return m.slice(0, n, n, n);
        },
        augment: function (m) {
            var ret = this.clone(), n = ret.width;
            m.each(function (val, row, col) {
                ret.set(row, col + n, val);
            });
            return ret;
        },
        slice: function (row, col, height, width) {
            var m = new Matrix(this.context);
            for (var i = 0; i < height; ++i) {
                for (var j = 0; j < width; ++j) {
                    m.set(i, j, this.get(row + i, col + j));
                }
            }
            return m;
        }
    });
    function argmax(i, end, f) {
        var max = f(i), pos = i;
        while (++i < end) {
            var v = f(i);
            if (v > max) {
                max = v;
                pos = i;
            }
        }
        return pos;
    }
    var Formula = Class.extend({
        init: function Formula(refs, handler, printer, sheet, row, col, arrayFormulaRange) {
            this.refs = refs;
            this.handler = handler;
            this.print = printer;
            this.absrefs = null;
            this.sheet = sheet;
            this.row = row;
            this.col = col;
            this.onReady = [];
            this.pending = false;
            this.arrayFormulaRange = arrayFormulaRange;
        },
        setArrayFormulaRange: function (ref) {
            this.arrayFormulaRange = ref.clone().setSheet(this.sheet);
        },
        clone: function (sheet, row, col, forceRefs) {
            var lcsheet = sheet.toLowerCase();
            var refs = this.refs;
            var range = this.arrayFormulaRange;
            if (forceRefs || lcsheet != this.sheet.toLowerCase()) {
                refs = refs.map(function (ref) {
                    if (!ref.hasSheet() && (!ref.sheet || ref.sheet.toLowerCase() != lcsheet)) {
                        ref = ref.clone().setSheet(sheet);
                    }
                    return ref;
                });
                if (range) {
                    range = range.clone().setSheet(sheet);
                }
            }
            return new Formula(refs, this.handler, this.print, sheet, row, col, range);
        },
        deepClone: function () {
            var refs = this.refs.map(function (ref) {
                return ref.clone();
            });
            return new Formula(refs, this.handler, this.print, this.sheet, this.row, this.col, this.arrayFormulaRange);
        },
        resolve: function (val) {
            this.pending = false;
            this.onReady.forEach(function (callback) {
                callback(val);
            });
        },
        exec: function (ss, callback, parentContext) {
            if ('value' in this) {
                if (callback) {
                    callback(this.value);
                }
            } else {
                if (callback) {
                    this.onReady.push(callback);
                }
                var ctx = new Context(this.resolve, this, ss, parentContext);
                var level = 0;
                while (parentContext) {
                    if (parentContext.formula === this) {
                        this.pending = false;
                        ctx.resolve(new CalcError('CIRCULAR'));
                        return;
                    }
                    parentContext = parentContext.parent;
                    ++level;
                }
                if (this.pending) {
                    return;
                }
                this.pending = true;
                var next = function () {
                    if (!this.absrefs) {
                        this.absrefs = this.refs.map(function (ref) {
                            return ref.absolute(this.row, this.col);
                        }, this);
                    }
                    this.handler.call(ctx);
                }.bind(this);
                if (level < 20) {
                    next();
                } else {
                    setTimeout(next, 0);
                }
            }
        },
        reset: function () {
            this.onReady = [];
            this.pending = false;
            delete this.value;
        },
        renameSheet: function (oldSheetName, newSheetName) {
            oldSheetName = oldSheetName.toLowerCase();
            this.absrefs = null;
            if (this.sheet.toLowerCase() == oldSheetName) {
                this.sheet = newSheetName;
            }
            this.refs.forEach(function (ref) {
                ref.renameSheet(oldSheetName, newSheetName);
            });
        },
        adjust: function (affectedSheet, operation, start, delta) {
            affectedSheet = affectedSheet.toLowerCase();
            var formulaRow = this.row;
            var formulaCol = this.col;
            var formulaSheet = this.sheet.toLowerCase();
            var formulaMoves = false;
            if (formulaSheet == affectedSheet) {
                if (operation == 'row' && formulaRow >= start) {
                    this.row += delta;
                    formulaMoves = true;
                }
                if (operation == 'col' && formulaCol >= start) {
                    this.col += delta;
                    formulaMoves = true;
                }
            }
            var newFormulaRow = this.row;
            var newFormulaCol = this.col;
            this.absrefs = null;
            var prevRefs = this.refs;
            var modified = formulaMoves;
            this.refs = prevRefs.map(function (ref) {
                var newRef = adjust(ref);
                if (!modified && !sameRef(newRef, ref)) {
                    modified = true;
                }
                return newRef;
            });
            var prevRange = this.arrayFormulaRange;
            if (prevRange) {
                this.arrayFormulaRange = adjust(prevRange);
                if (!modified && !sameRef(prevRange, this.arrayFormulaRange)) {
                    modified = true;
                }
            }
            if (modified) {
                return new Formula(prevRefs, this.handler, this.print, this.sheet, formulaRow, formulaCol, prevRange);
            }
            function adjust(ref) {
                if (ref === NULL) {
                    return ref;
                }
                if (ref.sheet.toLowerCase() != affectedSheet) {
                    if (formulaMoves) {
                        if (operation == 'row' && formulaRow >= start) {
                            ref = ref.relative(delta, 0);
                        }
                        if (operation == 'col' && formulaCol >= start) {
                            ref = ref.relative(0, delta);
                        }
                    }
                    return ref;
                }
                return ref.adjust(formulaRow, formulaCol, newFormulaRow, newFormulaCol, operation == 'row', start, delta);
            }
        },
        toString: function () {
            return this.print(this.row, this.col);
        }
    });
    function sameRef(r1, r2) {
        if (r1.constructor !== r2.constructor) {
            return false;
        }
        if (r1 instanceof CellRef) {
            return r1.sheet == r2.sheet && r1.row == r2.row && r1.col == r2.col && r1.rel == r2.rel;
        }
        if (r1 instanceof RangeRef) {
            return sameRef(r1.topLeft, r2.topLeft) && sameRef(r1.bottomRight, r2.bottomRight) && r1.endSheet == r2.endSheet;
        }
        if (r1 instanceof UnionRef) {
            var i = r1.refs.length;
            if (i != r2.refs.length) {
                return false;
            }
            while (--i >= 0) {
                if (!sameRef(r1.refs[i], r2.refs[i])) {
                    return false;
                }
            }
        }
        return true;
    }
    var FUNCS = Object.create(null);
    FUNCS['if'] = function (callback, args) {
        var self = this;
        var co = args[0], th = args[1], el = args[2];
        this.resolveCells([co], function () {
            var comatrix = self.asMatrix(co);
            if (comatrix) {
                th(function (th) {
                    el(function (el) {
                        var thmatrix = self.asMatrix(th);
                        var elmatrix = self.asMatrix(el);
                        callback(comatrix.map(function (val, row, col) {
                            if (val instanceof CalcError) {
                                return val;
                            } else if (self.bool(val)) {
                                return thmatrix ? thmatrix.get(row, col) : th;
                            } else {
                                return elmatrix ? elmatrix.get(row, col) : el;
                            }
                        }));
                    });
                });
            } else {
                co = this.force(co);
                if (co instanceof CalcError) {
                    callback(co);
                } else if (self.bool(co)) {
                    th(callback);
                } else {
                    el(callback);
                }
            }
        });
    };
    FUNCS['φ'] = function (callback) {
        callback((1 + Math.sqrt(5)) / 2);
    };
    function compileArgumentChecks(functionName, args) {
        var arrayArgs = 'function arrayArgs(args) { var xargs = [], width = 0, height = 0, arrays = [], i = 0; ';
        var resolve = 'function resolve(args, callback) { var toResolve = [], i = 0; ';
        var name, forced, main = '\'use strict\'; function check(args) { var stack = [], tmp, xargs = [], i = 0, m, err = \'VALUE\'; ', haveForced = false;
        var canBeArrayArg = false, hasArrayArgs = false;
        main += args.map(comp).join('');
        main += 'if (i < args.length) return new CalcError(\'N/A\'); ';
        main += 'return xargs; } ';
        arrayArgs += 'return { args: xargs, width: width, height: height, arrays: arrays }; } ';
        var f;
        if (haveForced) {
            resolve += 'this.resolveCells(toResolve, callback); } ';
            f = new Function('CalcError', 'round', main + resolve + arrayArgs + ' return { resolve: resolve, check: check, arrayArgs: arrayArgs };');
        } else {
            f = new Function('CalcError', 'round', main + ' return { check: check };');
        }
        f = f(CalcError, limitPrecision);
        if (!hasArrayArgs) {
            delete f.arrayArgs;
        }
        return f;
        function comp(x) {
            name = x[0];
            var code = '{ ';
            if (Array.isArray(name)) {
                arrayArgs += 'while (i < args.length) { ';
                resolve += 'while (i < args.length) { ';
                code += 'xargs.push(tmp = []); stack.push(xargs); xargs = tmp; ';
                code += 'while (i < args.length) { ';
                code += x.map(comp).join('');
                code += '} ';
                code += 'xargs = stack.pop(); ';
                resolve += '} ';
                arrayArgs += '} ';
            } else if (name == '+') {
                arrayArgs += 'while (i < args.length) { ';
                resolve += 'while (i < args.length) { ';
                code += 'if (i >= args.length) return new CalcError(\'N/A\'); ';
                code += 'xargs.push(tmp = []); stack.push(xargs); xargs = tmp; ';
                code += 'do { ';
                code += x.slice(1).map(comp).join('');
                code += '} while (i < args.length); ';
                code += 'xargs = stack.pop(); ';
                resolve += '} ';
                arrayArgs += '} ';
            } else if (name == '?') {
                code += 'if (!(' + cond(x[1]) + ')) return new CalcError(err); ';
            } else {
                var type = x[1];
                if (Array.isArray(type) && /^#?collect/.test(type[0])) {
                    var wantNulls = /!$/.test(type[0]);
                    var n = type[2];
                    force();
                    code += 'try {' + 'var $' + name + ' = this.cellValues(args.slice(i';
                    if (n) {
                        code += ', i + ' + n;
                    }
                    code += ')' + (wantNulls ? ',true' : '') + ').reduce(function(ret, $' + name + '){ ';
                    if (type[0].charAt(0) != '#') {
                        code += 'if ($' + name + ' instanceof CalcError) throw $' + name + '; ';
                    }
                    code += 'if (' + cond(type[1]) + ') ret.push($' + name + '); ';
                    code += 'return ret; ';
                    code += '}.bind(this), []); ';
                    if (n) {
                        code += 'i += ' + n + '; ';
                    } else {
                        code += 'i = args.length; ';
                    }
                    code += 'xargs.push($' + name + ')' + '} catch(ex) { if (ex instanceof CalcError) return ex; throw ex; } ';
                    resolve += 'toResolve.push(args.slice(i)); ';
                } else if (type == 'rest') {
                    code += 'xargs.push(args.slice(i)); i = args.length; ';
                } else {
                    if (canBeArrayArg = /^\*/.test(name)) {
                        hasArrayArgs = true;
                        name = name.substr(1);
                    }
                    code += 'var $' + name + ' = args[i++]; ';
                    var allowError = false;
                    if (/!$/.test(type)) {
                        type = type.substr(0, type.length - 1);
                        allowError = true;
                    } else {
                        code += 'if ($' + name + ' instanceof CalcError) return $' + name + '; ';
                    }
                    code += typeCheck(type, allowError) + 'xargs.push($' + name + '); ';
                }
            }
            code += '} ';
            return code;
        }
        function force() {
            if (forced) {
                return '$' + name + '';
            }
            haveForced = true;
            forced = true;
            resolve += 'toResolve.push(args[i++]); ';
            return '($' + name + ' = this.force($' + name + '))';
        }
        function forceNum(round) {
            return '(' + (round ? '(typeof ' + force() + ' == \'number\' ? ($' + name + ' = round($' + name + '), true) : false) || ' : '(typeof ' + force() + ' == \'number\') || ') + '(typeof $' + name + ' == \'boolean\' ? ($' + name + ' = +$' + name + ', true) : false) || ' + '(typeof $' + name + ' == \'string\' && !/^(?:=|true|false)/i.test($' + name + ') ? (' + 'tmp = kendo.spreadsheet.calc.parse(0, 0, 0, $' + name + '), ' + '/^date|number|percent$/.test(tmp.type) ? ($' + name + ' = +tmp.value, true) : false' + ') : false)' + ')';
        }
        function typeCheck(type, allowError) {
            forced = false;
            var ret = 'if (!(' + cond(type) + ')) { ';
            if (forced && !allowError) {
                ret += ' if ($' + name + ' instanceof CalcError) return $' + name + '; ';
            }
            ret += 'return new CalcError(err); } ';
            if (!forced) {
                resolve += 'i++; ';
            }
            if (canBeArrayArg) {
                arrayArgs += 'var $' + name + ' = this._arrayArg(args[i]); ' + 'if ($' + name + ') { ' + 'xargs.push($' + name + '); ' + 'width = Math.max(width, $' + name + '.width); ' + 'height = Math.max(height, $' + name + '.height); ' + 'arrays.push(true) } else { ' + 'xargs.push(args[i]); ' + 'arrays.push(false); } i++; ';
            } else {
                arrayArgs += 'xargs.push(args[i++]); arrays.push(false); ';
            }
            return ret;
        }
        function cond(type) {
            if (Array.isArray(type)) {
                if (type[0] == 'or') {
                    return '(' + type.slice(1).map(cond).join(') || (') + ')';
                }
                if (type[0] == 'and') {
                    return '(' + type.slice(1).map(cond).join(') && (') + ')';
                }
                if (type[0] == 'values') {
                    return '(' + type.slice(1).map(function (val) {
                        return force() + ' === ' + val;
                    }).join(') || (') + ')';
                }
                if (type[0] == 'null') {
                    return '(' + cond('null') + ' ? (($' + name + ' = ' + type[1] + '), true) : false)';
                }
                if (type[0] == 'between' || type[0] == '[between]') {
                    return '(' + force() + ' >= ' + type[1] + ' && ' + '$' + name + ' <= ' + type[2] + ' ? true : ((err = \'NUM\'), false))';
                }
                if (type[0] == '(between)') {
                    return '(' + force() + ' > ' + type[1] + ' && ' + '$' + name + ' < ' + type[2] + ' ? true : ((err = \'NUM\'), false))';
                }
                if (type[0] == '(between]') {
                    return '(' + force() + ' > ' + type[1] + ' && ' + '$' + name + ' <= ' + type[2] + ' ? true : ((err = \'NUM\'), false))';
                }
                if (type[0] == '[between)') {
                    return '(' + force() + ' >= ' + type[1] + ' && ' + '$' + name + ' < ' + type[2] + ' ? true : ((err = \'NUM\'), false))';
                }
                if (type[0] == 'assert') {
                    var err = type[2] || 'N/A';
                    return '((' + type[1] + ') ? true : (err = ' + JSON.stringify(err) + ', false))';
                }
                if (type[0] == 'not') {
                    return '!(' + cond(type[1]) + ')';
                }
                throw new Error('Unknown array type condition: ' + type[0]);
            }
            if (type == 'number' || type == 'datetime') {
                return forceNum(true);
            }
            if (type == 'number!') {
                return '(typeof ' + force() + ' == \'number\' ? ($' + name + ' = round($' + name + '), true) : false)';
            }
            if (type == 'integer' || type == 'date') {
                return '(' + forceNum() + ' && (($' + name + ' |= 0), true))';
            }
            if (type == 'divisor') {
                return '(' + forceNum(true) + ' && ($' + name + ' == 0 ? ((err = \'DIV/0\'), false) : true))';
            }
            if (type == 'number+') {
                return '(' + forceNum(true) + ' && ($' + name + ' >= 0 ? true : ((err = \'NUM\'), false)))';
            }
            if (type == 'integer+') {
                return '(' + forceNum() + ' && (($' + name + ' |= 0) >= 0 ? true : ((err = \'NUM\'), false)))';
            }
            if (type == 'number++') {
                return '(' + forceNum(true) + ' && ($' + name + ' > 0 ? true : ((err = \'NUM\'), false)))';
            }
            if (type == 'integer++') {
                return '(' + forceNum() + ' && (($' + name + ' |= 0) > 0 ? true : ((err = \'NUM\'), false)))';
            }
            if (type == 'string') {
                return '((typeof ' + force() + ' == \'string\' || typeof $' + name + ' == \'boolean\' || typeof $' + name + ' == \'number\') ? ($' + name + ' += \'\', true) : ($' + name + ' === undefined ? (($' + name + ' = \'\'), true) : false))';
            }
            if (type == 'boolean') {
                return '(typeof ' + force() + ' == \'boolean\')';
            }
            if (type == 'logical') {
                return '(typeof ' + force() + ' == \'boolean\' || (typeof $' + name + ' == \'number\' ? ($' + name + ' = !!$' + name + ', true) : false))';
            }
            if (type == 'matrix') {
                force();
                return '((m = this.asMatrix($' + name + ')) ? ($' + name + ' = m) : false)';
            }
            if (type == '#matrix') {
                return '((m = this.asMatrix($' + name + ')) ? ($' + name + ' = m) : false)';
            }
            if (type == 'ref') {
                return '($' + name + ' instanceof kendo.spreadsheet.Ref)';
            }
            if (type == 'area') {
                return '($' + name + ' instanceof kendo.spreadsheet.CellRef || $' + name + ' instanceof kendo.spreadsheet.RangeRef)';
            }
            if (type == 'cell') {
                return '($' + name + ' instanceof kendo.spreadsheet.CellRef)';
            }
            if (type == 'null') {
                return '(' + force() + ' == null)';
            }
            if (type == 'anyvalue') {
                return '(' + force() + ' != null && i <= args.length)';
            }
            if (type == 'forced') {
                return '(' + force() + ', i <= args.length)';
            }
            if (type == 'anything') {
                return '(i <= args.length)';
            }
            if (type == 'blank') {
                return '(' + force() + ' == null || $' + name + ' === \'\')';
            }
            throw new Error('Can\'t check for type: ' + type);
        }
    }
    function limitPrecision(num) {
        return num === parseInt(num, 10) ? num : +num.toPrecision(14);
    }
    function maybeRoundFloatErrors(num) {
        if (typeof num == 'number') {
            return limitPrecision(num);
        } else {
            return num;
        }
    }
    function withErrorHandling(obj, f, args) {
        if (args instanceof CalcError) {
            return args;
        }
        try {
            return f.apply(obj, args);
        } catch (ex) {
            if (ex instanceof CalcError) {
                return ex;
            } else {
                throw ex;
            }
        }
    }
    function makeSyncFunction(handler, resolve, check, arrayArgs) {
        return function (callback, args) {
            function doit() {
                if (arrayArgs) {
                    var x = arrayArgs.call(this, args);
                    args = x.args;
                    if (x.width > 0 && x.height > 0) {
                        var result = new Matrix(this);
                        for (var row = 0; row < x.height; ++row) {
                            for (var col = 0; col < x.width; ++col) {
                                var xargs = [];
                                for (var i = 0; i < args.length; ++i) {
                                    if (x.arrays[i]) {
                                        xargs[i] = args[i].getNA(row, col);
                                    } else {
                                        xargs[i] = args[i];
                                    }
                                }
                                xargs = check.call(this, xargs);
                                result.set(row, col, withErrorHandling(this, handler, xargs));
                            }
                        }
                        return callback(result);
                    }
                }
                var xargs = check.call(this, args);
                callback(withErrorHandling(this, handler, xargs));
            }
            if (resolve) {
                resolve.call(this, args, doit);
            } else {
                doit.call(this);
            }
        };
    }
    function makeAsyncFunction(handler, resolve, check, arrayArgs) {
        return function (callback, args) {
            function doit() {
                if (arrayArgs) {
                    var x = arrayArgs.call(this, args);
                    args = x.args;
                    if (x.width > 0 && x.height > 0) {
                        var result = new Matrix(this);
                        var count = x.width * x.height;
                        var makeCallback = function (row, col) {
                            return function (value) {
                                result.set(row, col, value);
                                --count;
                                if (count === 0) {
                                    return callback(result);
                                }
                            };
                        };
                        for (var row = 0; row < x.height && count > 0; ++row) {
                            for (var col = 0; col < x.width && count > 0; ++col) {
                                var xargs = [];
                                for (var i = 0; i < args.length; ++i) {
                                    if (x.arrays[i]) {
                                        xargs[i] = args[i].getNA(row, col);
                                    } else {
                                        xargs[i] = args[i];
                                    }
                                }
                                xargs = check.call(this, xargs);
                                if (xargs instanceof CalcError) {
                                    result.set(row, col, xargs);
                                    --count;
                                    if (count === 0) {
                                        return callback(result);
                                    }
                                } else {
                                    xargs.unshift(makeCallback(row, col));
                                    handler.apply(this, xargs);
                                }
                            }
                        }
                        return;
                    }
                }
                var x = check.call(this, args);
                if (x instanceof CalcError) {
                    callback(x);
                } else {
                    x.unshift(callback);
                    handler.apply(this, x);
                }
            }
            if (resolve) {
                resolve.call(this, args, doit);
            } else {
                doit.call(this);
            }
        };
    }
    function defineFunction(name, func) {
        name = name.toLowerCase();
        FUNCS[name] = func;
        return {
            args: function (args, log) {
                var code = compileArgumentChecks(name, args);
                if (log) {
                    if (code.arrayArgs) {
                        console.log(code.arrayArgs.toString());
                    }
                    if (code.resolve) {
                        console.log(code.resolve.toString());
                    }
                    if (code.check) {
                        console.log(code.check.toString());
                    }
                }
                var f = FUNCS[name] = makeSyncFunction(func, code.resolve, code.check, code.arrayArgs);
                f.kendoSpreadsheetArgs = args;
                return this;
            },
            argsAsync: function (args, log) {
                var code = compileArgumentChecks(name, args);
                if (log) {
                    if (code.arrayArgs) {
                        console.log(code.arrayArgs.toString());
                    }
                    if (code.resolve) {
                        console.log(code.resolve.toString());
                    }
                    if (code.check) {
                        console.log(code.check.toString());
                    }
                }
                var f = FUNCS[name] = makeAsyncFunction(func, code.resolve, code.check, code.arrayArgs);
                f.kendoSpreadsheetArgs = args;
                return this;
            }
        };
    }
    function dateToJulianDays(y, m, d) {
        m++;
        return (1461 * (y + 4800 + ((m - 14) / 12 | 0)) / 4 | 0) + (367 * (m - 2 - 12 * ((m - 14) / 12 | 0)) / 12 | 0) - (3 * ((y + 4900 + ((m - 14) / 12 | 0)) / 100 | 0) / 4 | 0) + d - 32075;
    }
    function julianDaysToDate(jd) {
        var l, n, j, i, m, d, y;
        l = jd + 68569;
        n = 4 * l / 146097 | 0;
        l = l - ((146097 * n + 3) / 4 | 0);
        i = 4000 * (l + 1) / 1461001 | 0;
        l = l - (1461 * i / 4 | 0) + 31;
        j = 80 * l / 2447 | 0;
        d = l - (2447 * j / 80 | 0);
        l = j / 11 | 0;
        m = j + 2 - 12 * l;
        y = 100 * (n - 49) + i + l;
        m--;
        return {
            year: y,
            month: m,
            date: d,
            day: (jd + 1) % 7,
            ord: ORDINAL_ADD_DAYS[isLeapYear(y)][m] + d
        };
    }
    var BASE_DATE = dateToJulianDays(1900, 0, -1);
    var DAYS_IN_MONTH = [
        31,
        28,
        31,
        30,
        31,
        30,
        31,
        31,
        30,
        31,
        30,
        31
    ];
    var ORDINAL_ADD_DAYS = [
        [
            0,
            31,
            59,
            90,
            120,
            151,
            181,
            212,
            243,
            273,
            304,
            334
        ],
        [
            0,
            31,
            60,
            91,
            121,
            152,
            182,
            213,
            244,
            274,
            305,
            335
        ]
    ];
    function isLeapYear(yr) {
        if (yr % 4) {
            return 0;
        }
        if (yr % 100) {
            return 1;
        }
        if (yr % 400) {
            return 0;
        }
        return 1;
    }
    function daysInYear(yr) {
        return isLeapYear(yr) ? 366 : 365;
    }
    function daysInMonth(yr, mo) {
        return isLeapYear(yr) && mo == 1 ? 29 : DAYS_IN_MONTH[mo];
    }
    function validDate(yr, mo, da) {
        return mo >= 1 && mo <= 12 && da >= 1 && da <= daysInMonth(yr, mo - 1);
    }
    function unpackDate(serial) {
        return julianDaysToDate((serial | 0) + BASE_DATE);
    }
    function packDate(year, month, date) {
        return dateToJulianDays(year, month, date) - BASE_DATE;
    }
    var MS_IN_MIN = 60 * 1000;
    var MS_IN_HOUR = 60 * MS_IN_MIN;
    var MS_IN_DAY = 24 * MS_IN_HOUR;
    function unpackTime(serial) {
        var frac = serial - (serial | 0);
        if (frac < 0) {
            frac++;
        }
        var ms = Math.round(MS_IN_DAY * frac);
        var hours = Math.floor(ms / MS_IN_HOUR);
        ms -= hours * MS_IN_HOUR;
        var minutes = Math.floor(ms / MS_IN_MIN);
        ms -= minutes * MS_IN_MIN;
        var seconds = Math.floor(ms / 1000);
        ms -= seconds * 1000;
        return {
            hours: hours,
            minutes: minutes,
            seconds: seconds,
            milliseconds: ms
        };
    }
    function serialToDate(serial) {
        var d = unpackDate(serial), t = unpackTime(serial);
        return new Date(d.year, d.month, d.date, t.hours, t.minutes, t.seconds, t.milliseconds);
    }
    function packTime(hh, mm, ss, ms) {
        return (hh + (mm + (ss + ms / 1000) / 60) / 60) / 24;
    }
    function dateToSerial(date) {
        var time = packTime(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
        date = packDate(date.getFullYear(), date.getMonth(), date.getDate());
        if (date < 0) {
            return date - 1 + time;
        } else {
            return date + time;
        }
    }
    function parseDate(str, format) {
        if (format) {
            format = kendo.spreadsheet.formatting.makeDateFormat(format);
        }
        return kendo.parseExactDate(str, format) || kendo.parseExactDate(str) || kendo.parseExactDate(str, [
            'MMMM dd yyyy',
            'MMMM dd yy',
            'MMM dd yyyy',
            'MMM dd yy',
            'dd MMMM yyyy',
            'dd MMMM yy',
            'dd MMM yyyy',
            'dd MMM yy',
            'MMMM dd, yyyy',
            'MMMM dd, yy',
            'MMM dd, yyyy',
            'MMM dd, yy',
            'MMMM dd',
            'MMM dd',
            'MMMM yyyy',
            'MMM yyyy',
            'dd MMMM',
            'dd MMM'
        ]);
    }
    exports.CalcError = CalcError;
    exports.Formula = Formula;
    exports.Matrix = Matrix;
    exports.packDate = packDate;
    exports.unpackDate = unpackDate;
    exports.packTime = packTime;
    exports.unpackTime = unpackTime;
    exports.serialToDate = serialToDate;
    exports.dateToSerial = dateToSerial;
    exports.daysInMonth = daysInMonth;
    exports.validDate = validDate;
    exports.isLeapYear = isLeapYear;
    exports.daysInYear = daysInYear;
    exports.parseDate = parseDate;
    exports.limitPrecision = limitPrecision;
    spreadsheet.dateToNumber = dateToSerial;
    spreadsheet.numberToDate = serialToDate;
    spreadsheet.defineFunction = defineFunction;
    spreadsheet.CalcError = CalcError;
    exports.defineFunction = defineFunction;
    exports.defineAlias = function (alias, name) {
        var orig = FUNCS[name];
        if (!orig) {
            throw new Error('Function ' + name + ' is not yet defined');
        }
        if (!orig.kendoSpreadsheetAliases) {
            orig.kendoSpreadsheetAliases = [name];
        }
        orig.kendoSpreadsheetAliases.push(alias);
        FUNCS[alias] = orig;
    };
    exports.FUNCS = FUNCS;
    var NUMBER_OR_ZERO = [
        'or',
        'number',
        [
            'null',
            0
        ]
    ];
    var ARGS_NUMERIC = [
        [
            '*a',
            NUMBER_OR_ZERO
        ],
        [
            '*b',
            NUMBER_OR_ZERO
        ]
    ];
    var ARGS_ANYVALUE = [
        [
            '*a',
            [
                'or',
                'anyvalue',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            '*b',
            [
                'or',
                'anyvalue',
                [
                    'null',
                    0
                ]
            ]
        ]
    ];
    defineFunction('binary+', function (a, b) {
        return a + b;
    }).args(ARGS_NUMERIC);
    defineFunction('binary-', function (a, b) {
        return a - b;
    }).args(ARGS_NUMERIC);
    defineFunction('binary*', function (a, b) {
        return a * b;
    }).args(ARGS_NUMERIC);
    defineFunction('binary/', function (a, b) {
        return a / b;
    }).args([
        [
            '*a',
            NUMBER_OR_ZERO
        ],
        [
            '*b',
            'divisor'
        ]
    ]);
    defineFunction('binary^', function (a, b) {
        return Math.pow(a, b);
    }).args(ARGS_NUMERIC);
    defineFunction('binary&', function (a, b) {
        if (a == null) {
            a = '';
        }
        if (b == null) {
            b = '';
        }
        return '' + a + b;
    }).args([
        [
            '*a',
            [
                'or',
                'number',
                'string',
                'boolean',
                'null'
            ]
        ],
        [
            '*b',
            [
                'or',
                'number',
                'string',
                'boolean',
                'null'
            ]
        ]
    ]);
    defineFunction('binary=', function (a, b) {
        a = typeof a === 'string' ? a.toLowerCase() : a;
        b = typeof b === 'string' ? b.toLowerCase() : b;
        return a === b;
    }).args(ARGS_ANYVALUE);
    defineFunction('binary<>', function (a, b) {
        return a !== b;
    }).args(ARGS_ANYVALUE);
    defineFunction('binary<', binaryCompare(function (a, b) {
        return a < b;
    })).args(ARGS_ANYVALUE);
    defineFunction('binary<=', binaryCompare(function (a, b) {
        return a <= b;
    })).args(ARGS_ANYVALUE);
    defineFunction('binary>', binaryCompare(function (a, b) {
        return a > b;
    })).args(ARGS_ANYVALUE);
    defineFunction('binary>=', binaryCompare(function (a, b) {
        return a >= b;
    })).args(ARGS_ANYVALUE);
    defineFunction('unary+', function (a) {
        return a;
    }).args([[
            '*a',
            NUMBER_OR_ZERO
        ]]);
    defineFunction('unary-', function (a) {
        return -a;
    }).args([[
            '*a',
            NUMBER_OR_ZERO
        ]]);
    defineFunction('unary%', function (a) {
        return a / 100;
    }).args([[
            '*a',
            NUMBER_OR_ZERO
        ]]);
    defineFunction('binary:', function (a, b) {
        return new RangeRef(a, b).setSheet(a.sheet || this.formula.sheet, a.hasSheet());
    }).args([
        [
            'a',
            'cell'
        ],
        [
            'b',
            'cell'
        ]
    ]);
    defineFunction('binary,', function (a, b) {
        return new UnionRef([
            a,
            b
        ]);
    }).args([
        [
            'a',
            'ref'
        ],
        [
            'b',
            'ref'
        ]
    ]);
    defineFunction('binary ', function (a, b) {
        return a.intersect(b);
    }).args([
        [
            'a',
            'ref'
        ],
        [
            'b',
            'ref'
        ]
    ]);
    defineFunction('not', function (a) {
        return !this.bool(a);
    }).args([[
            '*a',
            [
                'or',
                'anyvalue',
                [
                    'null',
                    0
                ]
            ]
        ]]);
    defineFunction('isblank', function (val) {
        if (val instanceof CellRef) {
            val = this.getRefData(val);
            return val == null;
        }
        return false;
    }).args([[
            '*value',
            'anything!'
        ]]);
    defineFunction('iserror', function (val) {
        return val instanceof CalcError;
    }).args([[
            '*value',
            'forced!'
        ]]);
    defineFunction('iserr', function (val) {
        return val instanceof CalcError && val.code != 'N/A';
    }).args([[
            '*value',
            'forced!'
        ]]);
    defineFunction('isna', function (val) {
        return val instanceof CalcError && val.code == 'N/A';
    }).args([[
            '*value',
            'forced!'
        ]]);
    defineFunction('islogical', function (val) {
        return typeof val == 'boolean';
    }).args([[
            '*value',
            'forced!'
        ]]);
    defineFunction('isnontext', function (val) {
        return typeof val != 'string';
    }).args([[
            '*value',
            'forced!'
        ]]);
    defineFunction('istext', function (val) {
        return typeof val == 'string';
    }).args([[
            '*value',
            'forced!'
        ]]);
    defineFunction('isnumber', function (val) {
        return typeof val == 'number';
    }).args([[
            '*value',
            'forced!'
        ]]);
    defineFunction('isref', function (val) {
        return val instanceof CellRef || val instanceof RangeRef;
    }).args([[
            '*value',
            'anything!'
        ]]);
    FUNCS[',getname'] = function (callback, args) {
        this.fetchName(args[0], callback);
    };
    function binaryCompare(func) {
        return function (left, right) {
            if (typeof left == 'string' && typeof right != 'string') {
                right = right == null ? '' : right + '';
            }
            if (typeof left != 'string' && typeof right == 'string') {
                left = left == null ? '' : left + '';
            }
            if (typeof left == 'number' && right == null) {
                right = 0;
            }
            if (typeof right == 'number' && left == null) {
                left = 0;
            }
            if (typeof left == 'string' && typeof right == 'string') {
                left = left.toLowerCase();
                right = right.toLowerCase();
            }
            if (typeof right == typeof left) {
                return func(left, right);
            } else {
                return new CalcError('VALUE');
            }
        };
    }
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/validation', ['spreadsheet/runtime'], f);
}(function () {
    'use strict';
    var $ = kendo.jQuery;
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var spreadsheet = kendo.spreadsheet;
    var exports = {};
    spreadsheet.validation = exports;
    var calc = spreadsheet.calc;
    var Class = kendo.Class;
    var TRANSPOSE_FORMAT = '_matrix({0})';
    var DATE_FORMAT = 'DATEVALUE("{0}")';
    calc.runtime.defineFunction('_matrix', function (m) {
        if (typeof m == 'string') {
            m = this.asMatrix([m.split(/\s*,\s*/)]);
        }
        return m;
    }).args([[
            'm',
            [
                'or',
                'matrix',
                'string'
            ]
        ]]);
    function compileValidation(sheet, row, col, validation) {
        var validationHandler;
        var comparer;
        var parsedFromDate;
        var parsedToDate;
        if (typeof validation === 'string') {
            validation = JSON.parse(validation);
        }
        if (validation.from) {
            if (validation.dataType === 'list' && !validation.fromIsListValue) {
                validation.from = kendo.format(TRANSPOSE_FORMAT, validation.from);
                validation.fromIsListValue = true;
            }
            if (validation.dataType === 'date') {
                parsedFromDate = calc.runtime.parseDate(validation.from);
                if (parsedFromDate) {
                    validation.from = kendo.format(DATE_FORMAT, validation.from);
                    validation.fromIsDateValue = true;
                }
            }
            validation.from = calc.compile(calc.parseFormula(sheet, row, col, validation.from));
        }
        if (validation.to) {
            if (validation.dataType === 'date') {
                parsedToDate = calc.runtime.parseDate(validation.to);
                if (parsedToDate) {
                    validation.to = kendo.format(DATE_FORMAT, validation.to);
                    validation.toIsDateValue = true;
                }
            }
            validation.to = calc.compile(calc.parseFormula(sheet, row, col, validation.to));
        }
        if (validation.dataType == 'custom') {
            comparer = exports.validationComparers.custom;
        } else if (validation.dataType == 'list') {
            comparer = exports.validationComparers.list;
        } else {
            comparer = exports.validationComparers[validation.comparerType];
        }
        if (!comparer) {
            throw kendo.format('\'{0}\' comparer is not implemented.', validation.comparerType);
        }
        validationHandler = function (valueToCompare) {
            var toValue = this.to && (this.to_value || this.to_value === 0) ? this.to_value : undefined;
            if (valueToCompare === null || valueToCompare === '') {
                if (this.allowNulls) {
                    this.value = true;
                } else {
                    this.value = false;
                }
            } else if (this.dataType == 'custom') {
                this.value = comparer(valueToCompare, this.from_value, toValue);
            } else if (this.dataType == 'list') {
                var data = this._getListData();
                this.value = comparer(valueToCompare, data, toValue);
            } else {
                this.value = comparer(valueToCompare, this.from_value, toValue);
            }
            return this.value;
        };
        return new kendo.spreadsheet.validation.Validation($.extend(validation, {
            handler: validationHandler,
            sheet: sheet,
            row: row,
            col: col
        }));
    }
    var Validation = Class.extend({
        init: function Validation(options) {
            this.handler = options.handler;
            this.from = options.from;
            this.to = options.to;
            this.dataType = options.dataType;
            this.comparerType = options.comparerType;
            this.type = options.type ? options.type : 'warning';
            this.allowNulls = options.allowNulls ? true : false;
            this.fromIsDateValue = options.fromIsDateValue ? true : false;
            this.toIsDateValue = options.toIsDateValue ? true : false;
            this.showButton = options.showButton;
            this.fromIsListValue = options.fromIsListValue ? true : false;
            this.sheet = options.sheet;
            this.row = options.row;
            this.col = options.col;
            if (options.tooltipMessageTemplate) {
                this.tooltipMessageTemplate = options.tooltipMessageTemplate;
            }
            if (options.tooltipTitleTemplate) {
                this.tooltipTitleTemplate = options.tooltipTitleTemplate;
            }
            if (options.messageTemplate) {
                this.messageTemplate = options.messageTemplate;
            }
            if (options.titleTemplate) {
                this.titleTemplate = options.titleTemplate;
            }
        },
        _formatMessages: function (format) {
            var from = this.from ? this.from_value : '';
            var to = this.to ? this.to_value : '';
            var fromFormula = this.from ? this.from.toString() : '';
            var toFormula = this.to ? this.to.toString() : '';
            var dataType = this.dataType;
            var type = this.type;
            var comparerType = this.comparerType;
            return kendo.format(format, from, to, fromFormula, toFormula, dataType, type, comparerType);
        },
        _setMessages: function () {
            this.title = '';
            this.message = '';
            if (this.tooltipTitleTemplate) {
                this.tooltipTitle = this._formatMessages(this.tooltipTitleTemplate);
            }
            if (this.tooltipMessageTemplate) {
                this.tooltipMessage = this._formatMessages(this.tooltipMessageTemplate);
            }
            if (this.titleTemplate) {
                this.title = this._formatMessages(this.titleTemplate);
            }
            if (this.messageTemplate) {
                this.message = this._formatMessages(this.messageTemplate);
            }
        },
        _getListData: function () {
            if (!this.from_value || !this.from_value.data) {
                return [];
            }
            var cube = this.from_value.data;
            var i;
            var y;
            var data = [];
            for (i = 0; i < cube.length; i++) {
                var array = cube[i];
                if (array) {
                    for (y = 0; y < array.length; y++) {
                        data.push(array[y]);
                    }
                }
            }
            return data;
        },
        clone: function (sheet, row, col) {
            var options = this._getOptions();
            if (options.from) {
                options.from = options.from.clone(sheet, row, col);
            }
            if (options.to) {
                options.to = options.to.clone(sheet, row, col);
            }
            return new Validation($.extend(options, { handler: this.handler }, {
                sheet: sheet,
                row: row,
                col: col
            }));
        },
        deepClone: function () {
            var v = new Validation(this);
            v.from = v.from.deepClone();
            if (v.to) {
                v.to = v.to.deepClone();
            }
            return v;
        },
        exec: function (ss, compareValue, compareFormat, callback) {
            var self = this;
            function getValue(val) {
                if (val instanceof kendo.spreadsheet.Ref) {
                    val = ss.getData(val);
                    if (Array.isArray(val)) {
                        val = val[0];
                    }
                }
                return val;
            }
            var calculateFromCallBack = function (val) {
                self.from_value = getValue(val);
                self.value = self.handler.call(self, compareValue, compareFormat);
                self._setMessages();
                if (callback) {
                    callback(self.value);
                }
            };
            if (self.to) {
                self.to.exec(ss, function (val) {
                    self.to_value = getValue(val);
                    self.from.exec(ss, calculateFromCallBack);
                });
            } else {
                self.from.exec(ss, calculateFromCallBack);
            }
        },
        reset: function () {
            if (this.from) {
                this.from.reset();
            }
            if (this.to) {
                this.to.reset();
            }
            delete this.value;
        },
        adjust: function (affectedSheet, operation, start, delta) {
            var prevFrom, prevTo, modified;
            var formulaRow = this.row;
            var formulaCol = this.col;
            if (this.from) {
                prevFrom = this.from.adjust(affectedSheet, operation, start, delta);
            }
            if (this.to) {
                prevTo = this.to.adjust(affectedSheet, operation, start, delta);
            }
            if (this.sheet.toLowerCase() == affectedSheet.toLowerCase()) {
                switch (operation) {
                case 'row':
                    if (formulaRow >= start) {
                        modified = true;
                        this.row += delta;
                    }
                    break;
                case 'col':
                    if (formulaCol >= start) {
                        modified = true;
                        this.col += delta;
                    }
                    break;
                }
            }
            if (modified || prevFrom || prevTo) {
                var v = new Validation(this);
                v.from = prevFrom;
                v.to = prevTo;
                v.row = formulaRow;
                v.col = formulaCol;
                return v;
            }
        },
        toJSON: function () {
            var options = this._getOptions();
            if (options.from) {
                options.from = options.from.toString();
                if (options.dataType === 'list') {
                    options.from = options.from.replace(/^_matrix\((.*)\)$/i, '$1');
                    delete options.fromIsListValue;
                }
                if (options.dataType === 'date') {
                    if (this.fromIsDateValue) {
                        options.from = options.from.replace(/^DATEVALUE\("(.*)"\)$/i, '$1');
                        delete options.fromIsDateValue;
                    }
                }
            }
            if (options.to) {
                options.to = options.to.toString();
                if (options.dataType === 'date') {
                    if (this.toIsDateValue) {
                        options.to = options.to.replace(/^DATEVALUE\("(.*)"\)$/i, '$1');
                        delete options.toIsDateValue;
                    }
                }
            }
            return options;
        },
        _getOptions: function () {
            return {
                from: this.from,
                to: this.to,
                dataType: this.dataType,
                type: this.type,
                comparerType: this.comparerType,
                row: this.row,
                col: this.col,
                sheet: this.sheet,
                allowNulls: this.allowNulls,
                fromIsListValue: this.fromIsListValue,
                fromIsDateValue: this.fromIsDateValue,
                toIsDateValue: this.toIsDateValue,
                tooltipMessageTemplate: this.tooltipMessageTemplate,
                tooltipTitleTemplate: this.tooltipTitleTemplate,
                messageTemplate: this.messageTemplate,
                titleTemplate: this.titleTemplate,
                showButton: this.showButton
            };
        }
    });
    exports.compile = compileValidation;
    exports.validationComparers = {
        greaterThan: function (valueToCompare, from) {
            return valueToCompare > from;
        },
        lessThan: function (valueToCompare, from) {
            return valueToCompare < from;
        },
        between: function (valueToCompare, from, to) {
            return valueToCompare >= from && valueToCompare <= to;
        },
        equalTo: function (valueToCompare, from) {
            return valueToCompare == from;
        },
        notEqualTo: function (valueToCompare, from) {
            return valueToCompare != from;
        },
        greaterThanOrEqualTo: function (valueToCompare, from) {
            return valueToCompare >= from;
        },
        lessThanOrEqualTo: function (valueToCompare, from) {
            return valueToCompare <= from;
        },
        notBetween: function (valueToCompare, from, to) {
            return valueToCompare < from || valueToCompare > to;
        },
        custom: function (valueToCompare, from) {
            return from;
        },
        list: function (valueToCompare, data) {
            return data.indexOf(valueToCompare) > -1;
        }
    };
    exports.Validation = Validation;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/sheet', [
        'kendo.core',
        'kendo.color',
        'spreadsheet/runtime',
        'spreadsheet/validation',
        'spreadsheet/references'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var RangeRef = kendo.spreadsheet.RangeRef;
        var UnionRef = kendo.spreadsheet.UnionRef;
        var CellRef = kendo.spreadsheet.CellRef;
        var Range = kendo.spreadsheet.Range;
        var MODIFIED_FORMULAS;
        var Selection = kendo.Class.extend({
            init: function (sheet) {
                this._sheet = sheet;
                this.selection = kendo.spreadsheet.FIRSTREF.toRangeRef();
                this.originalSelection = kendo.spreadsheet.FIRSTREF.toRangeRef();
                this._activeCell = kendo.spreadsheet.FIRSTREF.toRangeRef();
                this.originalActiveCell = kendo.spreadsheet.FIRSTREF;
            },
            currentSelectionRange: function () {
                return this.selection.rangeAt(this.selectionRangeIndex).toRangeRef();
            },
            currentOriginalNavigationRange: function () {
                return this.originalSelection.rangeAt(this.selectionRangeIndex).toRangeRef();
            },
            currentNavigationRange: function () {
                if (this.singleCellSelection()) {
                    return this._sheet._sheetRef;
                } else {
                    return this.selection.rangeAt(this.selectionRangeIndex).toRangeRef();
                }
            },
            nextNavigationRange: function () {
                if (!this.singleCellSelection()) {
                    this.selectionRangeIndex = this.selection.nextRangeIndex(this.selectionRangeIndex);
                }
                return this.currentNavigationRange();
            },
            previousNavigationRange: function () {
                if (!this.singleCellSelection()) {
                    this.selectionRangeIndex = this.selection.previousRangeIndex(this.selectionRangeIndex);
                }
                return this.currentNavigationRange();
            },
            activeCell: function (ref) {
                if (ref) {
                    this.originalActiveCell = ref.first();
                    this._activeCell = this._sheet.unionWithMerged(ref.toRangeRef());
                    this._sheet.focus(ref);
                    this._sheet.triggerChange({
                        activeCell: true,
                        selection: true
                    });
                }
                return this._activeCell;
            },
            select: function (ref, expanded, changeActiveCell) {
                if (ref) {
                    if (ref.eq(this.originalSelection)) {
                        return;
                    }
                    this._sheet.triggerSelect(new Range(ref, this._sheet));
                    this.originalSelection = ref;
                    this.selection = expanded;
                    if (changeActiveCell !== false) {
                        if (ref.isCell()) {
                            this._sheet.forEachMergedCell(ref, function (merged) {
                                ref = merged.topLeft;
                            });
                            this.activeCell(ref);
                        } else {
                            this.activeCell(this.selection.lastRange().first());
                        }
                        this.selectionRangeIndex = this.selection.size() - 1;
                    } else {
                        this._sheet.triggerChange({ selection: true });
                    }
                }
                return this.selection;
            },
            singleCellSelection: function () {
                return this._activeCell.eq(this.selection);
            }
        });
        var Sheet = kendo.Observable.extend({
            init: function () {
                kendo.Observable.prototype.init.call(this);
                this._reinit.apply(this, arguments);
            },
            events: [
                'changing',
                'commandRequest',
                'afterInsertRow',
                'afterDeleteRow',
                'insertRow',
                'insertColumn',
                'deleteRow',
                'deleteColumn',
                'hideRow',
                'hideColumn',
                'unhideRow',
                'unhideColumn',
                'select',
                'dataBinding',
                'dataBound'
            ],
            _reinit: function (rowCount, columnCount, rowHeight, columnWidth, headerHeight, headerWidth, defaultCellStyle) {
                defaultCellStyle = defaultCellStyle || {};
                this._defaultCellStyle = {
                    background: defaultCellStyle.background,
                    color: defaultCellStyle.color,
                    fontFamily: defaultCellStyle.fontFamily,
                    fontSize: defaultCellStyle.fontSize,
                    italic: defaultCellStyle.italic,
                    bold: defaultCellStyle.bold,
                    underline: defaultCellStyle.underline,
                    wrap: defaultCellStyle.wrap,
                    verticalAlign: defaultCellStyle.verticalAlign,
                    textAlign: defaultCellStyle.textAlign
                };
                this._rows = new kendo.spreadsheet.Axis(rowCount, rowHeight);
                this._columns = new kendo.spreadsheet.Axis(columnCount, columnWidth);
                this._filteredRows = new kendo.spreadsheet.RangeList(0, rowCount - 1, false);
                this._mergedCells = [];
                this._frozenRows = 0;
                this._frozenColumns = 0;
                this._suspendChanges = false;
                this._filter = null;
                this._showGridLines = true;
                this._gridLinesColor = null;
                this._grid = new kendo.spreadsheet.Grid(this._rows, this._columns, rowCount, columnCount, headerHeight, headerWidth);
                this._sheetRef = this._grid.normalize(kendo.spreadsheet.SHEETREF);
                this._properties = new kendo.spreadsheet.PropertyBag(rowCount, columnCount, this._defaultCellStyle);
                this._sorter = new kendo.spreadsheet.Sorter(this._grid, this._properties.sortable());
                this._viewSelection = new Selection(this);
                this._editSelection = new Selection(this);
                this._formulaSelections = [];
                this._drawings = [];
            },
            _selectionState: function () {
                return this._inEdit ? this._editSelection : this._viewSelection;
            },
            navigator: function () {
                if (!this._navigator) {
                    this._navigator = new kendo.spreadsheet.SheetNavigator(this);
                }
                return this._navigator;
            },
            axisManager: function () {
                if (!this._axisManager) {
                    this._axisManager = new kendo.spreadsheet.AxisManager(this);
                }
                return this._axisManager;
            },
            _name: function (value) {
                if (!value) {
                    return this._sheetName;
                }
                this._sheetName = value;
                return this;
            },
            name: function () {
                return this._name();
            },
            _property: function (accessor, value, reason) {
                if (value === undefined) {
                    return accessor();
                } else {
                    accessor(value);
                    return this.triggerChange(reason);
                }
            },
            _field: function (name, value, reason) {
                if (value === undefined) {
                    return this[name];
                } else {
                    this[name] = value;
                    return this.triggerChange(reason);
                }
            },
            suspendChanges: function (value) {
                if (value === undefined) {
                    return this._suspendChanges;
                }
                this._suspendChanges = value;
                return this;
            },
            triggerChange: function (reason) {
                if (!this._suspendChanges) {
                    this.trigger('change', reason);
                }
                return this;
            },
            triggerSelect: function (range) {
                this.trigger('select', { range: range });
            },
            setDataSource: function (dataSource, columns) {
                if (this.dataSourceBinder) {
                    this.dataSourceBinder.destroy();
                }
                this.dataSourceBinder = new kendo.spreadsheet.SheetDataSourceBinder({
                    dataSource: dataSource,
                    sheet: this,
                    columns: columns
                });
                this.dataSource = this.dataSourceBinder.dataSource;
            },
            hideColumn: function (columnIndex) {
                if (this.trigger('hideColumn', { index: columnIndex })) {
                    return;
                }
                return this._property(this._columns.hide.bind(this._columns), columnIndex, { layout: true });
            },
            unhideColumn: function (columnIndex) {
                if (this.trigger('unhideColumn', { index: columnIndex })) {
                    return;
                }
                return this._property(this._columns.unhide.bind(this._columns), columnIndex, { layout: true });
            },
            isHiddenColumn: function (columnIndex) {
                return this._grid._columns.hidden(columnIndex);
            },
            _copyRange: function (sourceRangeRef, targetRef) {
                var grid = this._grid;
                var rowCount = grid.rowCount;
                var nextRefTopLeft = grid.normalize(sourceRangeRef.topLeft);
                var nextRefBottomRight = grid.normalize(sourceRangeRef.bottomRight);
                var nextIndex = nextRefTopLeft.col * rowCount + nextRefTopLeft.row;
                var nextBottomIndex = nextRefBottomRight.col * rowCount + nextRefBottomRight.row;
                var targetIndex = targetRef.col * rowCount + targetRef.row;
                this._properties.copy(nextIndex, nextBottomIndex, targetIndex);
            },
            _saveModifiedFormulas: function (array, callback) {
                var save = MODIFIED_FORMULAS;
                MODIFIED_FORMULAS = array;
                var ret = callback();
                MODIFIED_FORMULAS = save;
                return ret;
            },
            _restoreModifiedFormulas: function (array) {
                var wb = this._workbook;
                array.forEach(function (f) {
                    var sheet = wb.sheetByName(f.sheet), index;
                    if (f instanceof kendo.spreadsheet.calc.runtime.Formula) {
                        index = sheet._grid.cellRefIndex(f);
                        sheet._properties.set('formula', index, index, f);
                    }
                    if (f instanceof kendo.spreadsheet.validation.Validation) {
                        index = sheet._grid.cellRefIndex(f);
                        sheet._properties.set('validation', index, index, f);
                    }
                });
            },
            _adjustReferences: function (operation, start, delta, mergedCells) {
                this._mergedCells = mergedCells.reduce(function (a, ref) {
                    ref = ref.adjust(null, null, null, null, operation == 'row', start, delta);
                    if (ref instanceof RangeRef) {
                        a.push(ref);
                    }
                    return a;
                }, []);
                if (this._workbook) {
                    var affectedSheet = this._name();
                    this._workbook._sheets.forEach(function (sheet) {
                        sheet._forFormulas(function (formula) {
                            var prev = formula.adjust(affectedSheet, operation, start, delta);
                            if (prev && MODIFIED_FORMULAS) {
                                MODIFIED_FORMULAS.push(prev);
                            }
                        });
                        sheet._forValidations(function (validation) {
                            var prev = validation.adjust(affectedSheet, operation, start, delta);
                            if (prev && MODIFIED_FORMULAS) {
                                MODIFIED_FORMULAS.push(prev);
                            }
                        });
                    });
                    this._workbook.adjustNames(affectedSheet, operation == 'row', start, delta);
                }
                var selection = this.select();
                selection = selection.adjust(null, null, null, null, operation == 'row', start, delta);
                if (selection !== kendo.spreadsheet.NULLREF) {
                    this.select(selection);
                }
                var axis = operation == 'col' ? this._columns : this._rows;
                axis.adjust(start, delta);
                if (operation == 'row') {
                    if (delta < 0) {
                        this._filteredRows.copy(start - delta, this._rows._count - 1, start);
                    } else {
                        this._filteredRows.copy(start, this._rows._count, start + delta);
                        this._filteredRows.value(start, start + delta - 1, false);
                    }
                }
                this._drawings.forEach(function (drawing) {
                    if (drawing.topLeftCell) {
                        drawing.topLeftCell = drawing.topLeftCell.adjust(null, null, null, null, operation == 'row', start, delta);
                    }
                });
            },
            _forFormulas: function (callback) {
                var props = this._properties;
                var formulas = props.get('formula').values();
                var n = formulas.length;
                formulas.forEach(function (f, i) {
                    callback.call(this, f.value, i, n);
                }, this);
            },
            _forValidations: function (callback) {
                var props = this._properties;
                props.get('validation').values().forEach(function (v) {
                    callback.call(this, v.value);
                }, this);
            },
            preventInsertRow: function (rowIndex, count) {
                if (this.selectedHeaders().allRows) {
                    return {
                        reason: 'error',
                        type: 'insertRowWhenColumnIsSelected'
                    };
                }
                count = count || 1;
                var grid = this._grid;
                var range = this.range(grid.rowCount - count, 0, count, grid.columnCount);
                if (range.hasValue()) {
                    return {
                        reason: 'error',
                        type: 'shiftingNonblankCells'
                    };
                }
                return false;
            },
            preventInsertColumn: function (colIndex, count) {
                if (this.selectedHeaders().allCols) {
                    return {
                        reason: 'error',
                        type: 'insertColumnWhenRowIsSelected'
                    };
                }
                count = count || 1;
                var grid = this._grid;
                var range = this.range(0, grid.columnCount - count, grid.rowCount, count);
                if (range.hasValue()) {
                    return {
                        reason: 'error',
                        type: 'shiftingNonblankCells'
                    };
                }
                return false;
            },
            insertRow: function (rowIndex) {
                var result = this.preventInsertRow(rowIndex);
                if (result) {
                    throw new Error('Shifting nonblank cells off the worksheet is not supported!');
                }
                if (this.trigger('insertRow', { index: rowIndex })) {
                    return;
                }
                this.batch(function () {
                    var grid = this._grid;
                    var columnCount = grid.columnCount;
                    var rowCount = grid.rowCount;
                    var frozenRows = this.frozenRows();
                    if (rowIndex < frozenRows) {
                        this.frozenRows(frozenRows + 1);
                    }
                    var mergedCells = this._mergedCells.slice();
                    for (var ci = 0; ci < columnCount; ci++) {
                        var ref = new RangeRef(new CellRef(rowIndex, ci), new CellRef(rowIndex, ci));
                        var topLeft = grid.normalize(ref.topLeft);
                        var bottomRight = grid.normalize(ref.bottomRight);
                        var nextRef = new RangeRef(new CellRef(topLeft.row, topLeft.col), new CellRef(rowCount - 2, bottomRight.col));
                        this._copyRange(nextRef, new CellRef(topLeft.row + 1, topLeft.col));
                        new Range(ref, this).clear({
                            clearAll: true,
                            keepBorders: true
                        });
                    }
                    this._adjustReferences('row', rowIndex, 1, mergedCells);
                }, {
                    recalc: true,
                    layout: true,
                    insertRow: { index: rowIndex },
                    ref: new RangeRef(new CellRef(rowIndex, 0), new CellRef(Infinity, Infinity))
                });
                this.trigger('afterInsertRow', { index: rowIndex });
                return this;
            },
            isEnabledRow: function (rowIndex) {
                var ref = new RangeRef(new CellRef(rowIndex, 0), new CellRef(rowIndex, this._grid.columnCount));
                return new Range(ref, this).enable();
            },
            deleteRow: function (rowIndex) {
                if (!this.isEnabledRow(rowIndex)) {
                    return this;
                }
                if (this.trigger('deleteRow', { index: rowIndex })) {
                    return;
                }
                this.batch(function () {
                    var grid = this._grid;
                    var columnCount = grid.columnCount;
                    var frozenRows = this.frozenRows();
                    if (rowIndex < frozenRows) {
                        this.frozenRows(frozenRows - 1);
                    }
                    var mergedCells = this._mergedCells.slice();
                    for (var ci = 0; ci < columnCount; ci++) {
                        var ref = new RangeRef(new CellRef(rowIndex, ci), new CellRef(rowIndex, ci));
                        new Range(ref, this).clear({
                            clearAll: true,
                            keepBorders: true
                        });
                        var topLeft = grid.normalize(ref.topLeft);
                        var bottomRight = grid.normalize(ref.bottomRight);
                        var nextRef = new RangeRef(new CellRef(topLeft.row + 1, topLeft.col), new CellRef(Infinity, bottomRight.col));
                        this._copyRange(nextRef, topLeft);
                        var nextRefBottomRight = grid.normalize(nextRef.bottomRight);
                        new Range(new RangeRef(nextRefBottomRight, nextRefBottomRight), this).clear();
                    }
                    this._adjustReferences('row', rowIndex, -1, mergedCells);
                }, {
                    recalc: true,
                    layout: true,
                    deleteRow: { index: rowIndex },
                    ref: new RangeRef(new CellRef(rowIndex, 0), new CellRef(Infinity, Infinity))
                });
                this.trigger('afterDeleteRow', { index: rowIndex });
                return this;
            },
            insertColumn: function (columnIndex) {
                if (this.trigger('insertColumn', { index: columnIndex })) {
                    return;
                }
                this.batch(function () {
                    var grid = this._grid;
                    var columnCount = grid.columnCount;
                    var frozenColumns = this.frozenColumns();
                    if (columnIndex < frozenColumns) {
                        this.frozenColumns(frozenColumns + 1);
                    }
                    var mergedCells = this._mergedCells.slice();
                    for (var ci = columnCount; ci >= columnIndex; ci--) {
                        var ref = new RangeRef(new CellRef(0, ci), new CellRef(Infinity, ci));
                        new Range(ref, this).clear({
                            clearAll: true,
                            keepBorders: true
                        });
                        if (ci == columnIndex) {
                            break;
                        }
                        var topLeft = grid.normalize(ref.topLeft);
                        var bottomRight = grid.normalize(ref.bottomRight);
                        var nextRef = new RangeRef(new CellRef(topLeft.row, topLeft.col - 1), new CellRef(bottomRight.row, bottomRight.col - 1));
                        this._copyRange(nextRef, topLeft);
                    }
                    this._adjustReferences('col', columnIndex, 1, mergedCells);
                }, {
                    recalc: true,
                    layout: true,
                    insertColumn: { index: columnIndex },
                    ref: new RangeRef(new CellRef(0, columnIndex), new CellRef(Infinity, Infinity))
                });
                return this;
            },
            isEnabledColumn: function (columnIndex) {
                var ref = new RangeRef(new CellRef(0, columnIndex), new CellRef(Infinity, columnIndex));
                return new Range(ref, this).enable();
            },
            deleteColumn: function (columnIndex) {
                if (!this.isEnabledColumn(columnIndex)) {
                    return this;
                }
                if (this.trigger('deleteColumn', { index: columnIndex })) {
                    return;
                }
                this.batch(function () {
                    var grid = this._grid;
                    var columnCount = grid.columnCount;
                    var frozenColumns = this.frozenColumns();
                    if (columnIndex < frozenColumns) {
                        this.frozenColumns(frozenColumns - 1);
                    }
                    var mergedCells = this._mergedCells.slice();
                    for (var ci = columnIndex; ci < columnCount; ci++) {
                        var ref = new RangeRef(new CellRef(0, ci), new CellRef(Infinity, ci));
                        new Range(ref, this).clear({
                            clearAll: true,
                            keepBorders: true
                        });
                        if (ci == columnCount - 1) {
                            break;
                        }
                        var topLeft = grid.normalize(ref.topLeft);
                        var bottomRight = grid.normalize(ref.bottomRight);
                        var nextRef = new RangeRef(new CellRef(topLeft.row, topLeft.col + 1), new CellRef(bottomRight.row, bottomRight.col + 1));
                        this._copyRange(nextRef, topLeft);
                    }
                    this._adjustReferences('col', columnIndex, -1, mergedCells);
                }, {
                    recalc: true,
                    layout: true,
                    deleteColumn: { index: columnIndex },
                    ref: new RangeRef(new CellRef(0, columnIndex), new CellRef(Infinity, Infinity))
                });
                return this;
            },
            _filterRow: function (rowIndex) {
                this._rows.hide(rowIndex);
                this._filteredRows.value(rowIndex, rowIndex, true);
                this.triggerChange({ layout: true });
            },
            hideRow: function (rowIndex) {
                if (this.trigger('hideRow', { index: rowIndex })) {
                    return;
                }
                return this._property(this._rows.hide.bind(this._rows), rowIndex, { layout: true });
            },
            unhideRow: function (rowIndex) {
                if (this.trigger('unhideRow', { index: rowIndex })) {
                    return;
                }
                return this._property(this._rows.unhide.bind(this._rows), rowIndex, { layout: true });
            },
            isHiddenRow: function (rowIndex) {
                return this._grid._rows.hidden(rowIndex);
            },
            isFilteredRow: function (rowIndex) {
                return this._filteredRows.value(rowIndex);
            },
            columnWidth: function (columnIndex, width) {
                return this._property(this._columns.value.bind(this._columns, columnIndex, columnIndex), width, { layout: true });
            },
            rowHeight: function (rowIndex, height) {
                return this._property(this._rows.value.bind(this._rows, rowIndex, rowIndex), height, { layout: true });
            },
            frozenRows: function (value) {
                return this._field('_frozenRows', value, { layout: true });
            },
            frozenColumns: function (value) {
                return this._field('_frozenColumns', value, { layout: true });
            },
            showGridLines: function (value) {
                return this._field('_showGridLines', value, { layout: true });
            },
            gridLinesColor: function (value) {
                return this._field('_gridLinesColor', value, { layout: true });
            },
            _ref: function (row, column, numRows, numColumns) {
                var ref = null;
                if (row instanceof kendo.spreadsheet.Ref) {
                    return row;
                }
                if (row instanceof kendo.spreadsheet.Range) {
                    return row._ref.toRangeRef();
                }
                if (typeof row === 'string') {
                    ref = kendo.spreadsheet.calc.parseReference(row);
                } else {
                    if (!numRows) {
                        numRows = 1;
                    }
                    if (!numColumns) {
                        numColumns = 1;
                    }
                    ref = new RangeRef(new CellRef(row, column), new CellRef(row + numRows - 1, column + numColumns - 1));
                }
                return ref;
            },
            range: function (row, column, numRows, numColumns) {
                return new Range(this._ref(row, column, numRows, numColumns), this);
            },
            _getMergedCells: function (range) {
                var grid = this._grid;
                var primary = {};
                var secondary = {};
                var hasMerged = false;
                this.forEachMergedCell(range, function (ref) {
                    var topLeft = ref.topLeft;
                    grid.forEach(ref, function (cellRef) {
                        if (topLeft.eq(cellRef)) {
                            primary[cellRef.print()] = ref;
                            hasMerged = true;
                        } else if (range.contains(cellRef)) {
                            secondary[cellRef.print()] = topLeft;
                            hasMerged = true;
                        }
                    });
                });
                return {
                    primary: primary,
                    secondary: secondary,
                    hasMerged: hasMerged
                };
            },
            forEachMergedCell: function (ref, callback) {
                var selectAll = false;
                if (typeof callback === 'undefined') {
                    callback = ref;
                    selectAll = true;
                }
                this._mergedCells.forEach(function (merged) {
                    if (selectAll || merged.intersects(ref)) {
                        callback(merged);
                    }
                });
            },
            forEachFilterHeader: function (ref, callback) {
                var selectAll = false;
                if (typeof callback === 'undefined') {
                    callback = ref;
                    selectAll = true;
                }
                if (this._filter) {
                    var refs = [];
                    this._filter.ref.forEachColumn(function (columnRef) {
                        if (selectAll || columnRef.intersects(ref)) {
                            refs.push(columnRef.topLeft);
                        }
                    });
                    this._mergedCells.forEach(function (merged) {
                        refs = refs.map(function (ref) {
                            if (merged.intersects(ref)) {
                                return merged;
                            }
                            return ref;
                        });
                    });
                    refs.reduce(function unique(result, element) {
                        if (result.indexOf(element) < 0) {
                            result.push(element);
                        }
                        return result;
                    }, []).forEach(callback);
                }
            },
            forEach: function (ref, callback) {
                var self = this;
                function forEachRange(ref) {
                    if (!(ref instanceof RangeRef)) {
                        ref = ref.toRangeRef();
                    }
                    var topLeft = self._grid.normalize(ref.topLeft);
                    var bottomRight = self._grid.normalize(ref.bottomRight);
                    var ci, ri;
                    function doIt(value) {
                        callback(ri++, ci, value);
                    }
                    for (ci = topLeft.col; ci <= bottomRight.col; ci++) {
                        ri = topLeft.row;
                        var startCellIndex = self._grid.index(ri, ci);
                        var endCellIndex = self._grid.index(bottomRight.row, ci);
                        self._properties.forEach(startCellIndex, endCellIndex, doIt);
                    }
                }
                if (!(ref instanceof RangeRef)) {
                    ref = self._ref(ref);
                }
                if (ref instanceof UnionRef) {
                    ref.forEach(forEachRange);
                } else {
                    forEachRange(ref);
                }
            },
            startResizing: function (initialPosition) {
                this._initialPosition = initialPosition;
                this._resizeInProgress = true;
            },
            startAutoFill: function () {
                this._autoFillInProgress = true;
                var selection = this.select();
                this._autoFillOrigin = selection;
                this._autoFillDest = selection;
                this.triggerChange({ selection: true });
            },
            updateAutoFill: function (dest, punch, hint, direction) {
                this._autoFillDest = dest;
                this._autoFillPunch = punch;
                this._autoFillHint = hint;
                this._autoFillDirection = direction;
                this.triggerChange({ selection: true });
            },
            autoFillRef: function () {
                return this._autoFillDest;
            },
            autoFillPunch: function () {
                return this._autoFillPunch;
            },
            autoFillInProgress: function () {
                return this._autoFillInProgress;
            },
            resizingInProgress: function () {
                return this._resizeInProgress;
            },
            draggingInProgress: function () {
                return this._draggingInProgress;
            },
            completeResizing: function () {
                if (this._resizeInProgress) {
                    this._resizeInProgress = false;
                    var hintPosition = this.resizeHintPosition();
                    if (this._initialPosition && hintPosition) {
                        var handlePosition = this.resizeHandlePosition();
                        if (handlePosition.col !== -Infinity) {
                            this.trigger('commandRequest', {
                                command: 'ColumnWidthCommand',
                                options: {
                                    target: handlePosition.col,
                                    value: this.columnWidth(handlePosition.col) - (this._initialPosition.x - hintPosition.x)
                                }
                            });
                        } else {
                            this.trigger('commandRequest', {
                                command: 'RowHeightCommand',
                                options: {
                                    target: handlePosition.row,
                                    value: this.rowHeight(handlePosition.row) - (this._initialPosition.y - hintPosition.y)
                                }
                            });
                        }
                    } else {
                        this.trigger('change', { resize: true });
                    }
                }
            },
            _renderComment: function (ref) {
                var comment = ref ? this.range(ref).comment() : null;
                if (comment) {
                    if (!this._commentRef || !ref.eq(this._commentRef)) {
                        this._commentRef = ref;
                        this.trigger('change', { comment: true });
                    }
                } else {
                    if (this._commentRef) {
                        this._commentRef = null;
                        this.trigger('change', { comment: true });
                    }
                }
            },
            resizeHandlePosition: function () {
                return this._resizeHandlePosition;
            },
            resizeHintPosition: function (location) {
                if (location !== undefined) {
                    this._resizeHintPosition = location;
                    this.trigger('change', { resize: true });
                }
                return this._resizeHintPosition;
            },
            removeResizeHandle: function () {
                if (this._resizeHandlePosition) {
                    this._resizeHintPosition = undefined;
                    this._resizeHandlePosition = undefined;
                    this._initialPosition = undefined;
                    this.trigger('change', { resize: true });
                }
            },
            positionResizeHandle: function (ref) {
                this._resizeHandlePosition = ref;
                this.trigger('change', { resize: true });
            },
            startDragging: function (data) {
                this._draggingInProgress = data;
            },
            completeDragging: function () {
                var drag = this._draggingInProgress;
                if (drag) {
                    this._draggingInProgress = null;
                    var drawing = drag.drawing;
                    if (drawing.eq(drag.copy)) {
                        return;
                    }
                    if (drawing.topLeftCell) {
                        var box = this.drawingBoundingBox(drawing);
                        var row = this._rows.indexVisible(box.top);
                        var col = this._columns.indexVisible(box.left);
                        var ref = new CellRef(row, col);
                        var refBox = this.refBoundingBox(ref);
                        drawing.offsetX = box.left - refBox.left;
                        drawing.offsetY = box.top - refBox.top;
                        drawing.topLeftCell = ref;
                        this.triggerChange({ dragging: true });
                    }
                    this.trigger('commandRequest', {
                        command: 'DrawingUpdateCommand',
                        options: {
                            sheet: this,
                            drawing: drawing,
                            previous: drag.copy
                        }
                    });
                }
            },
            startSelection: function () {
                this._selectionInProgress = true;
            },
            completeSelection: function () {
                if (this._selectionInProgress) {
                    this._selectionInProgress = false;
                    this._resizeHintPosition = undefined;
                    this.trigger('change', { selection: true });
                }
                if (this._autoFillInProgress) {
                    this._autoFillInProgress = false;
                    var dest = this._autoFillDest;
                    var origin = this._autoFillOrigin;
                    if (this._autoFillPunch) {
                        this.trigger('commandRequest', {
                            command: 'ClearContentCommand',
                            options: { operatingRange: this.range(this._autoFillPunch) }
                        });
                    } else {
                        if (!dest.eq(origin)) {
                            this.trigger('commandRequest', {
                                command: 'AutoFillCommand',
                                options: {
                                    operatingRange: this.range(dest),
                                    origin: this.range(origin)
                                }
                            });
                        } else {
                            this.triggerChange({ selection: true });
                        }
                    }
                    this._autoFillDest = null;
                    this._autoFillPunch = null;
                    this._autoFillOrigin = null;
                    this.select(dest);
                }
            },
            selectionInProgress: function () {
                return this._selectionInProgress;
            },
            select: function (ref, changeActiveCell) {
                var selectionState = this._selectionState();
                var expandedRef;
                if (ref) {
                    ref = this._ref(ref);
                    ref = this._grid.normalize(ref);
                    expandedRef = this._grid.isAxis(ref) ? ref : this.unionWithMerged(ref);
                }
                return selectionState.select(ref, expandedRef, changeActiveCell);
            },
            originalSelect: function () {
                return this._selectionState().originalSelection;
            },
            currentSelectionRange: function () {
                return this._selectionState().currentSelectionRange();
            },
            currentOriginalSelectionRange: function () {
                return this._selectionState().currentOriginalNavigationRange();
            },
            currentNavigationRange: function () {
                return this._selectionState().currentNavigationRange();
            },
            nextNavigationRange: function () {
                return this._selectionState().nextNavigationRange();
            },
            previousNavigationRange: function () {
                return this._selectionState().previousNavigationRange();
            },
            selectionRangeIndex: function () {
                return this._selectionState().selectionRangeIndex;
            },
            activeCell: function (ref) {
                return this._selectionState().activeCell(ref);
            },
            originalActiveCell: function () {
                return this._selectionState().originalActiveCell;
            },
            singleCellSelection: function () {
                return this._selectionState().singleCellSelection();
            },
            unionWithMerged: function (ref) {
                var mergedCells = this._mergedCells;
                return ref.map(function (ref) {
                    return ref.toRangeRef().union(mergedCells);
                });
            },
            trim: function (ref) {
                var trims = [];
                var grid = this._grid;
                this._properties.forEachProperty(function (property) {
                    trims.push(grid.trim(ref, property.list));
                });
                return this.unionWithMerged(ref.topLeft.toRangeRef().union(trims));
            },
            focus: function (ref) {
                if (ref) {
                    this._focus = ref.toRangeRef();
                } else {
                    var focus = this._focus;
                    this._focus = null;
                    return focus;
                }
            },
            activeCellSelection: function () {
                return new Range(this._grid.normalize(this.activeCell()), this);
            },
            selection: function () {
                return new Range(this._grid.normalize(this._selectionState().selection), this);
            },
            selectedHeaders: function () {
                var selection = this.select();
                var rows = {};
                var cols = {};
                var allCols = false;
                var allRows = false;
                var maxRow = this._grid.rowCount - 1;
                var maxCol = this._grid.columnCount - 1;
                selection.forEach(function (ref) {
                    var i;
                    var rowState = 'partial';
                    var colState = 'partial';
                    ref = ref.toRangeRef();
                    var bottomRight = ref.bottomRight;
                    var topLeft = ref.topLeft;
                    var rowSelection = topLeft.col <= 0 && bottomRight.col >= maxCol;
                    var colSelection = topLeft.row <= 0 && bottomRight.row >= maxRow;
                    if (colSelection) {
                        allRows = true;
                        colState = 'full';
                    }
                    if (rowSelection) {
                        allCols = true;
                        rowState = 'full';
                    }
                    if (!colSelection) {
                        for (i = topLeft.row; i <= bottomRight.row; i++) {
                            if (rows[i] !== 'full') {
                                rows[i] = rowState;
                            }
                        }
                    }
                    if (!rowSelection) {
                        for (i = topLeft.col; i <= bottomRight.col; i++) {
                            if (cols[i] !== 'full') {
                                cols[i] = colState;
                            }
                        }
                    }
                });
                return {
                    rows: rows,
                    cols: cols,
                    allRows: allRows,
                    allCols: allCols,
                    all: allRows && allCols
                };
            },
            isInEditMode: function (isInEdit) {
                if (isInEdit === undefined) {
                    return this._inEdit;
                }
                this._inEdit = isInEdit;
                if (isInEdit) {
                    this._editSelection.selection = this._viewSelection.selection.clone();
                    this._editSelection.originalSelection = this._viewSelection.originalSelection.clone();
                    this._editSelection._activeCell = this._viewSelection._activeCell.clone();
                    this._editSelection.originalActiveCell = this._viewSelection.originalActiveCell.clone();
                }
            },
            _setFormulaSelections: function (selection) {
                this._formulaSelections = (selection || []).slice();
                this.triggerChange({ selection: true });
            },
            _viewActiveCell: function () {
                return this._viewSelection._activeCell.toRangeRef();
            },
            toJSON: function () {
                var positions = {};
                var rows = this._rows.toJSON('height', positions);
                var columns = this._columns.toJSON('width', {});
                var viewSelection = this._viewSelection;
                var hyperlinks = [];
                var defaultCellStyle = this._defaultCellStyle || {};
                function clearDefaultStyle(cell) {
                    Object.keys(defaultCellStyle).forEach(function (key) {
                        if (cell[key] === defaultCellStyle[key]) {
                            delete cell[key];
                        }
                    });
                }
                this.forEach(kendo.spreadsheet.SHEETREF, function (row, col, cell) {
                    clearDefaultStyle(cell);
                    if (Object.keys(cell).length === 0) {
                        return;
                    }
                    if (cell.link) {
                        hyperlinks.push({
                            ref: kendo.spreadsheet.Ref.display(null, row, col),
                            target: cell.link
                        });
                    }
                    var position = positions[row];
                    if (position === undefined) {
                        position = rows.length;
                        rows.push({ index: row });
                        positions[row] = position;
                    }
                    row = rows[position];
                    cell.index = col;
                    if (row.cells === undefined) {
                        row.cells = [];
                    }
                    if (cell.formula) {
                        if (cell.formula.arrayFormulaRange) {
                            cell.formula = {
                                src: cell.formula.toString(),
                                ref: cell.formula.arrayFormulaRange.toString()
                            };
                        } else {
                            cell.formula = cell.formula.toString();
                        }
                    }
                    if (cell.validation) {
                        cell.validation = cell.validation.toJSON();
                    }
                    if (cell.color) {
                        cell.color = kendo.parseColor(cell.color).toCss();
                    }
                    if (cell.background) {
                        cell.background = kendo.parseColor(cell.background).toCss();
                    }
                    if (cell.borderTop && cell.borderTop.color) {
                        cell.borderTop.color = kendo.parseColor(cell.borderTop.color).toCss();
                    }
                    if (cell.borderBottom && cell.borderBottom.color) {
                        cell.borderBottom.color = kendo.parseColor(cell.borderBottom.color).toCss();
                    }
                    if (cell.borderRight && cell.borderRight.color) {
                        cell.borderRight.color = kendo.parseColor(cell.borderRight.color).toCss();
                    }
                    if (cell.borderLeft && cell.borderLeft.color) {
                        cell.borderLeft.color = kendo.parseColor(cell.borderLeft.color).toCss();
                    }
                    row.cells.push(cell);
                });
                var json = {
                    name: this._name(),
                    rows: rows,
                    columns: columns,
                    selection: viewSelection.selection.toString(),
                    activeCell: viewSelection.activeCell().toString(),
                    frozenRows: this.frozenRows(),
                    frozenColumns: this.frozenColumns(),
                    showGridLines: this.showGridLines(),
                    gridLinesColor: this.gridLinesColor(),
                    mergedCells: this._mergedCells.map(function (ref) {
                        return ref.toString();
                    }),
                    hyperlinks: hyperlinks,
                    defaultCellStyle: defaultCellStyle,
                    drawings: this._drawings.map(function (dr) {
                        return dr.toJSON();
                    })
                };
                if (this._sort) {
                    json.sort = {
                        ref: this._sort.ref.toString(),
                        columns: this._sort.columns.map(function (column) {
                            return {
                                index: column.index,
                                ascending: column.ascending
                            };
                        })
                    };
                }
                if (this._filter) {
                    json.filter = {
                        ref: this._filter.ref.toString(),
                        columns: this._filter.columns.map(function (column) {
                            var filter = column.filter.toJSON();
                            filter.index = column.index;
                            return filter;
                        })
                    };
                }
                return json;
            },
            fromJSON: function (json) {
                this.batch(function () {
                    if (json.name !== undefined) {
                        this._name(json.name);
                    }
                    if (json.frozenColumns !== undefined) {
                        this.frozenColumns(json.frozenColumns);
                    }
                    if (json.frozenRows !== undefined) {
                        this.frozenRows(json.frozenRows);
                    }
                    if (json.columns !== undefined) {
                        this._columns.fromJSON('width', json.columns);
                    }
                    if (json.rows !== undefined) {
                        this._rows.fromJSON('height', json.rows);
                        for (var ri = 0; ri < json.rows.length; ri++) {
                            var row = json.rows[ri];
                            var rowIndex = row.index;
                            if (rowIndex === undefined) {
                                rowIndex = ri;
                            }
                            if (row.cells) {
                                for (var ci = 0; ci < row.cells.length; ci++) {
                                    var cell = row.cells[ci];
                                    var columnIndex = cell.index;
                                    if (columnIndex === undefined) {
                                        columnIndex = ci;
                                    }
                                    if (cell.formula) {
                                        var isArray = typeof cell.formula != 'string';
                                        var src = isArray ? cell.formula.src : cell.formula;
                                        var formula = this._compileFormula(rowIndex, columnIndex, src);
                                        if (isArray) {
                                            formula.setArrayFormulaRange(kendo.spreadsheet.calc.parseReference(cell.formula.ref));
                                        }
                                        cell.formula = formula;
                                    }
                                    if (cell.validation) {
                                        cell.validation = this._compileValidation(rowIndex, columnIndex, cell.validation);
                                    }
                                    this._properties.fromJSON(this._grid.index(rowIndex, columnIndex), cell);
                                }
                            }
                        }
                    }
                    if (json.drawings) {
                        this._drawings = json.drawings.map(Drawing.fromJSON);
                    }
                    if (json.selection) {
                        this._viewSelection.selection = this._viewSelection.originalSelection = this._ref(json.selection);
                    }
                    if (json.activeCell) {
                        var activeCellRef = this._ref(json.activeCell);
                        this._viewSelection._activeCell = activeCellRef.toRangeRef();
                        this._viewSelection.originalActiveCell = activeCellRef.first();
                    }
                    if (json.mergedCells) {
                        json.mergedCells.forEach(function (ref) {
                            this.range(ref).merge();
                        }, this);
                    }
                    if (json.sort) {
                        this._sort = {
                            ref: this._ref(json.sort.ref),
                            columns: json.sort.columns.slice(0)
                        };
                    }
                    if (json.filter) {
                        var ref = json.filter.ref;
                        var columns = json.filter.columns === undefined ? [] : json.filter.columns;
                        if (!ref) {
                            kendo.logToConsole('Dropping filter for sheet \'' + json.name + '\' due to missing ref');
                        } else {
                            this._filter = {
                                ref: this._ref(ref),
                                columns: columns.map(function (column) {
                                    return {
                                        index: column.index,
                                        filter: kendo.spreadsheet.Filter.create(column)
                                    };
                                })
                            };
                            this._refreshFilter();
                        }
                    }
                    if (json.showGridLines !== undefined) {
                        this._showGridLines = json.showGridLines;
                    }
                    this._gridLinesColor = json.gridLinesColor;
                });
                this._rows._refresh();
                this._columns._refresh();
            },
            formula: function (ref) {
                return this._properties.get('formula', this._grid.cellRefIndex(ref));
            },
            validation: function (ref) {
                return this._properties.get('validation', this._grid.cellRefIndex(ref));
            },
            resetFormulas: function () {
                this._forFormulas(function (formula) {
                    formula.reset();
                });
            },
            resetValidations: function () {
                this._forValidations(function (validation) {
                    validation.reset();
                });
            },
            recalc: function (context, callback) {
                var formulas = this._properties.get('formula').values();
                var count = formulas.length, pending = 0, i = 0;
                if (!count && callback) {
                    return callback();
                }
                function next() {
                    pending--;
                    if (i == count && !pending) {
                        callback();
                    }
                }
                while (i < count) {
                    pending++;
                    formulas[i++].value.exec(context, callback ? next : null);
                }
            },
            revalidate: function (context) {
                var self = this;
                this._forValidations(function (validation) {
                    var cellRef = new CellRef(validation.row, validation.col);
                    var ref = new RangeRef(cellRef, cellRef);
                    validation.exec(context, self._get(ref, 'value'), self._get(ref, 'format'));
                });
            },
            _value: function (row, col, value) {
                var index = this._grid.index(row, col);
                if (value !== undefined) {
                    this._properties.set('value', index, index, value);
                } else {
                    return this._properties.get('value', index);
                }
            },
            _validation: function (row, col) {
                var index = this._grid.index(row, col);
                return this._properties.get('validation', index);
            },
            _compileValidation: function (row, col, validation) {
                if (validation instanceof kendo.spreadsheet.validation.Validation) {
                    return validation.clone(this._name(), row, col);
                }
                if (validation.from != null) {
                    validation.from = (validation.from + '').replace(/^=/, '');
                }
                if (validation.to != null) {
                    validation.to = (validation.to + '').replace(/^=/, '');
                }
                return kendo.spreadsheet.validation.compile(this._name(), row, col, validation);
            },
            _compileFormula: function (row, col, f) {
                f = f.replace(/^=/, '');
                f = kendo.spreadsheet.calc.parseFormula(this._name(), row, col, f);
                return kendo.spreadsheet.calc.compile(f);
            },
            _copyValuesInRange: function (topLeft, bottomRight, value, property) {
                var ci, start, end;
                for (ci = topLeft.col; ci <= bottomRight.col; ci++) {
                    start = this._grid.index(topLeft.row, ci);
                    end = this._grid.index(bottomRight.row, ci);
                    for (var index = start, row = topLeft.row; index <= end; ++index, ++row) {
                        value = value.clone(this._name(), row, ci);
                        this._properties.set(property, index, index, value);
                    }
                }
                return value;
            },
            _set: function (ref, name, value) {
                var topLeft = this._grid.normalize(ref.topLeft);
                var bottomRight = this._grid.normalize(ref.bottomRight);
                var ci, start, end;
                if (typeof value == 'number') {
                    value = kendo.spreadsheet.calc.runtime.limitPrecision(value);
                }
                if (value && name == 'formula') {
                    if (typeof value == 'string') {
                        value = this._compileFormula(topLeft.row, topLeft.col, value);
                    }
                    value = this._copyValuesInRange(topLeft, bottomRight, value, 'formula');
                } else if (value && name == 'validation') {
                    value = this._compileValidation(topLeft.row, topLeft.col, value);
                    value = this._copyValuesInRange(topLeft, bottomRight, value, 'validation');
                } else {
                    for (ci = topLeft.col; ci <= bottomRight.col; ci++) {
                        start = this._grid.index(topLeft.row, ci);
                        end = this._grid.index(bottomRight.row, ci);
                        this._properties.set(name, start, end, value);
                        if (name == 'formula') {
                            this._properties.set('value', start, end, null);
                        }
                    }
                }
            },
            _get: function (ref, name) {
                var topLeft = this._grid.normalize(ref.topLeft);
                var index = this._grid.index(topLeft.row, topLeft.col);
                return this._properties.get(name, index);
            },
            batch: function (callback, reason) {
                var suspended = this.suspendChanges();
                this.suspendChanges(true);
                callback.call(this);
                return this.suspendChanges(suspended).triggerChange(reason || { recalc: true });
            },
            _sortBy: function (ref, columns) {
                var indices = null;
                columns.forEach(function (column) {
                    indices = this._sorter.sortBy(ref, column.index, this._properties.get('value'), column.ascending, indices);
                }, this);
                this._sort = {
                    ref: ref,
                    columns: columns
                };
                this._refreshFilter();
                this.forEach(ref, function (row, col, props) {
                    var formula = props.formula;
                    if (formula) {
                        var diff = row - formula.row;
                        if (diff !== 0) {
                            var start = diff > 0 ? formula.row : formula.row + diff;
                            formula.adjust(this.name(), 'row', start, diff);
                        }
                    }
                }.bind(this));
                this.triggerChange({ recalc: true });
            },
            _refreshFilter: function () {
                if (this._filter) {
                    this._filterBy(this._filter.ref, this._filter.columns);
                }
            },
            _filterBy: function (ref, columns) {
                this.batch(function () {
                    for (var ri = ref.topLeft.row; ri <= ref.bottomRight.row; ri++) {
                        if (this.isFilteredRow(ri)) {
                            this._filteredRows.value(ri, ri, false);
                            this._rows.unhide(ri);
                        }
                    }
                    columns.forEach(function (column) {
                        var columnRef = ref.resize({ top: 1 }).toColumn(column.index);
                        var cells = [];
                        if (columnRef === kendo.spreadsheet.NULLREF) {
                            return;
                        }
                        this.forEach(columnRef, function (row, col, cell) {
                            cell.row = row;
                            cells.push(cell);
                        });
                        column.filter.prepare(cells);
                        for (var ci = 0; ci < cells.length; ci++) {
                            var cell = cells[ci];
                            var value = column.filter.value(cell);
                            if (column.filter.matches(value) === false) {
                                this._filterRow(cell.row);
                            }
                        }
                    }, this);
                    this._filter = {
                        ref: ref,
                        columns: columns
                    };
                }, {
                    recalc: true,
                    layout: true,
                    filter: true
                });
            },
            filterColumn: function (ref) {
                var filterRef = this.filter().ref;
                return ref.toRangeRef().topLeft.col - filterRef.topLeft.col;
            },
            filter: function () {
                return this._filter;
            },
            clearFilter: function (spec) {
                this._clearFilter(spec instanceof Array ? spec : [spec]);
            },
            _clearFilter: function (indices) {
                if (this._filter) {
                    this.batch(function () {
                        this._filter.columns = this._filter.columns.filter(function (column) {
                            return indices.indexOf(column.index) < 0;
                        });
                        this._refreshFilter();
                    }, {
                        recalc: true,
                        layout: true,
                        filter: true
                    });
                }
            },
            getAxisState: function () {
                return {
                    rows: this._rows.getState(),
                    columns: this._columns.getState()
                };
            },
            setAxisState: function (state) {
                this._rows.setState(state.rows);
                this._columns.setState(state.columns);
                this.triggerChange({ layout: true });
            },
            getState: function () {
                return {
                    rows: this._rows.getState(),
                    columns: this._columns.getState(),
                    mergedCells: this._mergedCells.map(function (cell) {
                        return cell.clone();
                    }),
                    properties: this._properties.getState()
                };
            },
            setState: function (state) {
                this._rows.setState(state.rows);
                this._columns.setState(state.columns);
                this._mergedCells = state.mergedCells;
                this._properties.setState(state.properties);
                this.triggerChange(kendo.spreadsheet.ALL_REASONS);
            },
            _merge: function (ref) {
                var mergedCells = this._mergedCells;
                var sheet = this;
                var mergedRef;
                this.batch(function () {
                    mergedRef = ref.map(function (ref) {
                        if (ref instanceof kendo.spreadsheet.CellRef) {
                            return ref;
                        }
                        var currentRef = ref.toRangeRef().union(mergedCells, function (ref) {
                            mergedCells.splice(mergedCells.indexOf(ref), 1);
                        });
                        var range = new Range(currentRef, sheet);
                        var formula = range._get('formula');
                        var value = range.value();
                        var format = range.format();
                        var background = range.background();
                        range.value(null);
                        range.format(null);
                        range.background(null);
                        var topLeft = new Range(currentRef.collapse(), sheet);
                        if (formula) {
                            topLeft._set('formula', formula);
                        } else {
                            topLeft.value(value);
                        }
                        topLeft.format(format);
                        topLeft.background(background);
                        mergedCells.push(currentRef);
                        return currentRef;
                    });
                    var viewSelection = sheet._viewSelection;
                    viewSelection.selection = sheet.unionWithMerged(viewSelection.originalSelection);
                    viewSelection._activeCell = sheet.unionWithMerged(viewSelection.originalActiveCell);
                }, {
                    activeCell: true,
                    selection: true
                });
                return mergedRef;
            },
            _useCultureDecimals: function () {
                return this._workbook && this._workbook.options.useCultureDecimals;
            },
            withCultureDecimals: function (f) {
                var dot = '.';
                if (this._useCultureDecimals()) {
                    dot = kendo.culture().numberFormat['.'];
                }
                return kendo.spreadsheet.calc.withDecimalSeparator(dot, f);
            },
            drawingBoundingBox: function (drawing) {
                var left = drawing.offsetX;
                var top = drawing.offsetY;
                if (drawing.topLeftCell) {
                    left += this._columns.sum(0, drawing.topLeftCell.col - 1);
                    top += this._rows.sum(0, drawing.topLeftCell.row - 1);
                }
                return new kendo.spreadsheet.Rectangle(left, top, drawing.width, drawing.height);
            },
            refBoundingBox: function (ref) {
                return this._grid.rectangle(ref.toRangeRef());
            },
            addDrawing: function (drw, activate) {
                if (!(drw instanceof Drawing)) {
                    drw = new Drawing(drw);
                }
                this._drawings.push(drw);
                if (activate) {
                    this._activeDrawing = drw;
                }
                this.triggerChange({ layout: true });
                return drw;
            },
            removeDrawing: function (drawing) {
                var pos = this._drawings.indexOf(drawing);
                if (pos >= 0) {
                    this._drawings.splice(pos, 1);
                    this.triggerChange({ layout: true });
                }
            },
            usesImage: function (img) {
                for (var i = this._drawings.length; --i >= 0;) {
                    if (this._drawings[i].image === img) {
                        return true;
                    }
                }
                return false;
            }
        });
        var Drawing = kendo.Class.extend({
            init: function Drawing(args) {
                this.reset(args);
            },
            toJSON: function () {
                return {
                    topLeftCell: this.topLeftCell.toString(),
                    offsetX: this.offsetX,
                    offsetY: this.offsetY,
                    width: this.width,
                    height: this.height,
                    image: this.image,
                    opacity: this.opacity
                };
            },
            clone: function () {
                return new Drawing(this);
            },
            reset: function (dr) {
                var anchor = dr.topLeftCell;
                if (typeof anchor == 'string') {
                    anchor = kendo.spreadsheet.calc.parseReference(anchor);
                }
                this.topLeftCell = anchor;
                this.offsetX = dr.offsetX || 0;
                this.offsetY = dr.offsetY || 0;
                this.width = dr.width;
                this.height = dr.height;
                this.image = dr.image;
                this.opacity = dr.opacity != null ? dr.opacity : 1;
            },
            eq: function (dr) {
                return (!this.topLeftCell && !dr.topLeftCell || this.topLeftCell && dr.topLeftCell && this.topLeftCell.eq(dr.topLeftCell)) && this.offsetX === dr.offsetX && this.offsetY === dr.offsetY && this.width === dr.width && this.height === dr.height && this.image === dr.image && this.opacity === dr.opacity;
            }
        });
        Drawing.fromJSON = function (args) {
            return new Drawing(args);
        };
        kendo.spreadsheet.Sheet = Sheet;
        kendo.spreadsheet.Drawing = Drawing;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/sheetsbar', [
        'kendo.core',
        'kendo.sortable'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var outerWidth = kendo._outerWidth;
        var DOT = '.';
        var EMPTYCHAR = ' ';
        var sheetsBarClassNames = {
            sheetsBarWrapper: 'k-widget k-header',
            sheetsBarSheetsWrapper: 'k-tabstrip k-floatwrap k-tabstrip-bottom',
            sheetsBarActive: 'k-spreadsheet-sheets-bar-active',
            sheetsBarInactive: 'k-spreadsheet-sheets-bar-inactive',
            sheetsBarAdd: 'k-spreadsheet-sheets-bar-add',
            sheetsBarRemove: 'k-spreadsheet-sheets-remove',
            sheetsBarItems: 'k-spreadsheet-sheets-items',
            sheetsBarEditor: 'k-spreadsheet-sheets-editor',
            sheetsBarScrollable: 'k-tabstrip-scrollable',
            sheetsBarNext: 'k-tabstrip-next',
            sheetsBarPrev: 'k-tabstrip-prev',
            sheetsBarKItem: 'k-item k-state-default',
            sheetsBarKActive: 'k-state-active k-state-tab-on-top',
            sheetsBarKTextbox: 'k-textbox',
            sheetsBarKLink: 'k-link',
            sheetsBarKIcon: 'k-icon',
            sheetsBarKFontIcon: 'k-icon',
            sheetsBarKButton: 'k-button k-button-icon',
            sheetsBarKButtonBare: 'k-bare',
            sheetsBarKArrowW: 'k-i-arrow-60-left',
            sheetsBarKArrowE: 'k-i-arrow-60-right',
            sheetsBarKReset: 'k-reset k-tabstrip-items',
            sheetsBarKIconX: 'k-i-close',
            sheetsBarKSprite: 'k-sprite',
            sheetsBarKIconPlus: 'k-i-plus',
            sheetsBarHintWrapper: 'k-widget k-tabstrip k-tabstrip-bottom k-spreadsheet-sheets-items-hint',
            sheetsBarKResetItems: 'k-reset k-tabstrip-items'
        };
        var SheetsBar = kendo.ui.Widget.extend({
            init: function (element, options) {
                var classNames = SheetsBar.classNames;
                kendo.ui.Widget.call(this, element, options);
                element = this.element;
                element.addClass(classNames.sheetsBarWrapper);
                this._openDialog = options.openDialog;
                this._tree = new kendo.dom.Tree(element[0]);
                this._tree.render([
                    this._addButton(),
                    this._createSheetsWrapper([])
                ]);
                this._toggleScrollEvents(true);
                this._createSortable();
                this._sortable.bind('start', this._onSheetReorderStart.bind(this));
                this._sortable.bind('end', this._onSheetReorderEnd.bind(this));
                element.on('click', DOT + classNames.sheetsBarRemove, this._onSheetRemove.bind(this));
                element.on('click', 'li', this._onSheetSelect.bind(this));
                element.on('dblclick', 'li' + DOT + classNames.sheetsBarActive, this._createEditor.bind(this));
                element.on('click', DOT + classNames.sheetsBarAdd, this._onAddSelect.bind(this));
            },
            options: {
                name: 'SheetsBar',
                scrollable: { distance: 200 }
            },
            events: [
                'select',
                'reorder',
                'rename'
            ],
            _createEditor: function () {
                if (this._editor) {
                    return;
                }
                this._renderSheets(this._sheets, this._selectedIndex, true);
                this._editor = this.element.find(kendo.format('input{0}{1}', DOT, SheetsBar.classNames.sheetsBarEditor)).focus().on('keydown', this._onEditorKeydown.bind(this)).on('blur', this._onEditorBlur.bind(this));
            },
            _destroyEditor: function (canceled) {
                var newSheetName = canceled ? null : this._editor.val();
                this._editor.off();
                this._editor = null;
                this._renderSheets(this._sheets, this._selectedIndex, false);
                this._onSheetRename(newSheetName);
            },
            renderSheets: function (sheets, selectedIndex) {
                if (!sheets || selectedIndex < 0) {
                    return;
                }
                this._renderSheets(sheets, selectedIndex, false);
            },
            _renderSheets: function (sheets, selectedIndex, isInEditMode) {
                var that = this;
                var wrapperOffsetWidth;
                var sheetsGroupScrollWidth;
                var classNames = SheetsBar.classNames;
                that._isRtl = kendo.support.isRtl(that.element);
                that._sheets = sheets;
                that._selectedIndex = selectedIndex;
                that._renderHtml(isInEditMode, true);
                if (!that._scrollableAllowed()) {
                    return;
                }
                var sheetsWrapper = that._sheetsWrapper();
                var scrollPrevButton = sheetsWrapper.children(DOT + classNames.sheetsBarPrev);
                var scrollNextButton = sheetsWrapper.children(DOT + classNames.sheetsBarNext);
                var gapWidth = 2;
                var addButton = that.element.find(DOT + classNames.sheetsBarAdd);
                var addButtonWidth = outerWidth(addButton) + addButton.position().left + gapWidth;
                var scrollPrevButtonWidth = outerWidth(scrollPrevButton) + gapWidth;
                var sheetsGroup = that._sheetsGroup();
                scrollPrevButton.css({ left: addButtonWidth });
                sheetsWrapper.addClass(classNames.sheetsBarScrollable + EMPTYCHAR + classNames.sheetsBarSheetsWrapper);
                sheetsGroup.css({ marginLeft: addButtonWidth });
                wrapperOffsetWidth = sheetsWrapper[0].offsetWidth;
                sheetsGroupScrollWidth = sheetsGroup[0].scrollWidth;
                if (sheetsGroupScrollWidth + addButtonWidth > wrapperOffsetWidth) {
                    var scrollNextButtonRight = Math.ceil(kendo.parseFloat(scrollNextButton.css('right')));
                    if (!that._scrollableModeActive) {
                        that._nowScrollingSheets = false;
                        that._scrollableModeActive = true;
                    }
                    sheetsGroup.css({
                        marginLeft: scrollPrevButtonWidth + addButtonWidth,
                        marginRight: outerWidth(scrollNextButton) + scrollNextButtonRight + gapWidth
                    });
                } else {
                    if (that._scrollableModeActive && sheetsGroupScrollWidth <= wrapperOffsetWidth) {
                        that._scrollableModeActive = false;
                        sheetsGroup.css({
                            marginLeft: addButtonWidth,
                            marginRight: ''
                        });
                    } else {
                        sheetsGroup.css({ marginLeft: addButtonWidth });
                    }
                }
                that._toggleScrollButtons();
            },
            _toggleScrollButtons: function (toggle) {
                var that = this;
                var ul = that._sheetsGroup();
                var wrapper = that._sheetsWrapper();
                var scrollLeft = ul.scrollLeft();
                var prev = wrapper.find(DOT + SheetsBar.classNames.sheetsBarPrev);
                var next = wrapper.find(DOT + SheetsBar.classNames.sheetsBarNext);
                if (toggle === false) {
                    prev.toggle(false);
                    next.toggle(false);
                } else {
                    prev.toggle(that._isRtl ? scrollLeft < ul[0].scrollWidth - ul[0].offsetWidth - 1 : scrollLeft !== 0);
                    next.toggle(that._isRtl ? scrollLeft !== 0 : scrollLeft < ul[0].scrollWidth - ul[0].offsetWidth - 1);
                }
            },
            _toggleScrollEvents: function (toggle) {
                var that = this;
                var classNames = SheetsBar.classNames;
                var options = that.options;
                var scrollPrevButton;
                var scrollNextButton;
                var sheetsWrapper = that._sheetsWrapper();
                scrollPrevButton = sheetsWrapper.children(DOT + classNames.sheetsBarPrev);
                scrollNextButton = sheetsWrapper.children(DOT + classNames.sheetsBarNext);
                if (toggle) {
                    scrollPrevButton.on('mousedown', function () {
                        that._nowScrollingSheets = true;
                        that._scrollSheetsByDelta(options.scrollable.distance * (that._isRtl ? 1 : -1));
                    });
                    scrollNextButton.on('mousedown', function () {
                        that._nowScrollingSheets = true;
                        that._scrollSheetsByDelta(options.scrollable.distance * (that._isRtl ? -1 : 1));
                    });
                    scrollPrevButton.add(scrollNextButton).on('mouseup', function () {
                        that._nowScrollingSheets = false;
                    });
                } else {
                    scrollPrevButton.off();
                    scrollNextButton.off();
                }
            },
            _renderHtml: function (isInEditMode, renderScrollButtons) {
                var idx;
                var sheetElements = [];
                var dom = kendo.dom;
                var element = dom.element;
                var sheets = this._sheets;
                var selectedIndex = this._selectedIndex;
                var classNames = SheetsBar.classNames;
                for (idx = 0; idx < sheets.length; idx++) {
                    var sheet = sheets[idx];
                    var isSelectedSheet = idx === selectedIndex;
                    var attr = { className: classNames.sheetsBarKItem + EMPTYCHAR };
                    var elementContent = [];
                    if (isSelectedSheet) {
                        attr.className += classNames.sheetsBarKActive + EMPTYCHAR + classNames.sheetsBarActive;
                    } else {
                        attr.className += classNames.sheetsBarInactive;
                    }
                    if (isSelectedSheet && isInEditMode) {
                        elementContent.push(element('input', {
                            type: 'text',
                            value: sheet.name(),
                            className: classNames.sheetsBarKTextbox + EMPTYCHAR + classNames.sheetsBarEditor,
                            maxlength: 50
                        }, []));
                    } else {
                        elementContent.push(element('span', {
                            className: classNames.sheetsBarKLink,
                            title: sheet.name()
                        }, [dom.text(sheet.name())]));
                        if (sheets.length > 1) {
                            var deleteIcon = element('span', { className: classNames.sheetsBarKIcon + EMPTYCHAR + classNames.sheetsBarKFontIcon + EMPTYCHAR + classNames.sheetsBarKIconX }, []);
                            elementContent.push(element('span', { className: classNames.sheetsBarKLink + EMPTYCHAR + classNames.sheetsBarRemove }, [deleteIcon]));
                        }
                    }
                    sheetElements.push(element('li', attr, elementContent));
                }
                this._tree.render([
                    this._addButton(),
                    this._createSheetsWrapper(sheetElements, renderScrollButtons)
                ]);
            },
            _createSheetsWrapper: function (sheetElements, renderScrollButtons) {
                var element = kendo.dom.element;
                var classNames = SheetsBar.classNames;
                var childrenElements = [element('ul', { className: classNames.sheetsBarKReset }, sheetElements)];
                renderScrollButtons = true;
                if (renderScrollButtons) {
                    var baseButtonClass = classNames.sheetsBarKButton + EMPTYCHAR + classNames.sheetsBarKButtonBare + EMPTYCHAR;
                    childrenElements.push(element('span', { className: baseButtonClass + classNames.sheetsBarPrev }, [element('span', { className: classNames.sheetsBarKIcon + EMPTYCHAR + classNames.sheetsBarKArrowW }, [])]));
                    childrenElements.push(element('span', { className: baseButtonClass + classNames.sheetsBarNext }, [element('span', { className: classNames.sheetsBarKIcon + EMPTYCHAR + classNames.sheetsBarKArrowE }, [])]));
                }
                return element('div', { className: classNames.sheetsBarItems }, childrenElements);
            },
            _createSortable: function () {
                var classNames = SheetsBar.classNames;
                this._sortable = new kendo.ui.Sortable(this.element, {
                    filter: kendo.format('ul li.{0},ul li.{1}', classNames.sheetsBarActive, classNames.sheetsBarInactive),
                    container: DOT + classNames.sheetsBarItems,
                    axis: 'x',
                    animation: false,
                    ignore: 'input',
                    end: function () {
                        if (this.draggable.hint) {
                            this.draggable.hint.remove();
                        }
                    },
                    hint: function (element) {
                        var hint = $(element).clone();
                        return hint.wrap('<div class=\'' + classNames.sheetsBarHintWrapper + '\'><ul class=\'' + classNames.sheetsBarKResetItems + '\'></ul></div>').closest('div');
                    }
                });
            },
            _onEditorKeydown: function (e) {
                if (this._editor) {
                    if (e.which === 13) {
                        this._destroyEditor();
                    }
                    if (e.which === 27) {
                        this._destroyEditor(true);
                    }
                }
            },
            _onEditorBlur: function () {
                if (this._editor) {
                    this._destroyEditor();
                }
            },
            _onSheetReorderEnd: function (e) {
                e.preventDefault();
                this.trigger('reorder', {
                    oldIndex: e.oldIndex,
                    newIndex: e.newIndex
                });
            },
            _onSheetReorderStart: function (e) {
                if (this._editor) {
                    e.preventDefault();
                }
            },
            _onSheetRemove: function (e) {
                var removedSheetName = $(e.target).closest('li').text();
                if (this._editor) {
                    this._destroyEditor();
                }
                var closeCallback = function (e) {
                    var dlg = e.sender;
                    if (dlg.isConfirmed()) {
                        this.trigger('remove', {
                            name: removedSheetName,
                            confirmation: true
                        });
                    }
                }.bind(this);
                this._openDialog('confirmation', { close: closeCallback });
            },
            _onSheetSelect: function (e) {
                var selectedSheetText = $(e.target).text();
                if ($(e.target).is(DOT + SheetsBar.classNames.sheetsBarEditor) || !selectedSheetText) {
                    e.preventDefault();
                    return;
                }
                if (this._editor) {
                    this._destroyEditor();
                }
                this._scrollSheetsToItem($(e.target).closest('li'));
                this.trigger('select', {
                    name: selectedSheetText,
                    isAddButton: false
                });
            },
            _onSheetRename: function (newSheetName) {
                if (this._sheets[this._selectedIndex].name() === newSheetName || newSheetName === null) {
                    return;
                }
                this.trigger('rename', {
                    name: newSheetName,
                    sheetIndex: this._selectedIndex
                });
            },
            _onAddSelect: function () {
                this.trigger('select', { isAddButton: true });
            },
            _addButton: function () {
                var element = kendo.dom.element;
                var classNames = SheetsBar.classNames;
                return element('a', { className: classNames.sheetsBarAdd + EMPTYCHAR + classNames.sheetsBarKButton }, [element('span', { className: classNames.sheetsBarKIcon + EMPTYCHAR + classNames.sheetsBarKFontIcon + EMPTYCHAR + classNames.sheetsBarKIconPlus }, [])]);
            },
            destroy: function () {
                this._sortable.destroy();
            },
            _scrollableAllowed: function () {
                var options = this.options;
                return options.scrollable && !isNaN(options.scrollable.distance);
            },
            _scrollSheetsToItem: function (item) {
                var that = this;
                if (!that._scrollableModeActive) {
                    return;
                }
                var sheetsGroup = that._sheetsGroup();
                var currentScrollOffset = sheetsGroup.scrollLeft();
                var itemWidth = outerWidth(item);
                var itemOffset = that._isRtl ? item.position().left : item.position().left - sheetsGroup.children().first().position().left;
                var sheetsGroupWidth = sheetsGroup[0].offsetWidth;
                var sheetsGroupPadding = Math.ceil(parseFloat(sheetsGroup.css('padding-left')));
                var itemPosition;
                if (that._isRtl) {
                    if (itemOffset < 0) {
                        itemPosition = currentScrollOffset + itemOffset - (sheetsGroupWidth - currentScrollOffset) - sheetsGroupPadding;
                    } else if (itemOffset + itemWidth > sheetsGroupWidth) {
                        itemPosition = currentScrollOffset + itemOffset - itemWidth + sheetsGroupPadding * 2;
                    }
                } else {
                    if (currentScrollOffset + sheetsGroupWidth < itemOffset + itemWidth) {
                        itemPosition = itemOffset + itemWidth - sheetsGroupWidth + sheetsGroupPadding * 2;
                    } else if (currentScrollOffset > itemOffset) {
                        itemPosition = itemOffset - sheetsGroupPadding;
                    }
                }
                sheetsGroup.finish().animate({ 'scrollLeft': itemPosition }, 'fast', 'linear', function () {
                    that._toggleScrollButtons();
                });
            },
            _sheetsGroup: function () {
                return this._sheetsWrapper().children('ul');
            },
            _sheetsWrapper: function () {
                return this.element.find(DOT + SheetsBar.classNames.sheetsBarItems);
            },
            _scrollSheetsByDelta: function (delta) {
                var that = this;
                var sheetsGroup = that._sheetsGroup();
                var scrLeft = sheetsGroup.scrollLeft();
                sheetsGroup.finish().animate({ 'scrollLeft': scrLeft + delta }, 'fast', 'linear', function () {
                    if (that._nowScrollingSheets) {
                        that._scrollSheetsByDelta(delta);
                    } else {
                        that._toggleScrollButtons();
                    }
                });
            }
        });
        kendo.spreadsheet.SheetsBar = SheetsBar;
        $.extend(true, SheetsBar, { classNames: sheetsBarClassNames });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/calc', ['spreadsheet/runtime'], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var util = kendo.util;
    var spreadsheet = kendo.spreadsheet;
    var Ref = spreadsheet.Ref;
    var RangeRef = spreadsheet.RangeRef;
    var CellRef = spreadsheet.CellRef;
    var NameRef = spreadsheet.NameRef;
    var exports = spreadsheet.calc;
    var runtime = exports.runtime;
    var OPERATORS_STANDARD = Object.create(null);
    var OPERATORS_COMMA = Object.create(null);
    (function (ops) {
        ops.forEach(function (cls, i) {
            cls.forEach(function (op) {
                OPERATORS_STANDARD[op] = ops.length - i;
                OPERATORS_COMMA[op == ',' ? ';' : op] = ops.length - i;
            });
        });
    }([
        [':'],
        [' '],
        [','],
        ['%'],
        ['^'],
        [
            '*',
            '/'
        ],
        [
            '+',
            '-'
        ],
        ['&'],
        [
            '=',
            '<',
            '>',
            '<=',
            '>=',
            '<>'
        ]
    ]));
    var OPERATORS = OPERATORS_STANDARD;
    var SEPARATORS = {
        DEC: '.',
        ARG: ',',
        COL: ','
    };
    function setDecimalSeparator(sep) {
        SEPARATORS.DEC = sep;
        SEPARATORS.ARG = sep == ',' ? ';' : ',';
        SEPARATORS.COL = sep == ',' ? '\\' : ',';
        OPERATORS = sep == ',' ? OPERATORS_COMMA : OPERATORS_STANDARD;
    }
    exports.withDecimalSeparator = function (sep, f) {
        if (SEPARATORS.DEC == sep) {
            return f();
        }
        var save = SEPARATORS.DEC;
        setDecimalSeparator(sep);
        try {
            return f();
        } finally {
            setDecimalSeparator(save);
        }
    };
    exports._separators = SEPARATORS;
    var ParseError = kendo.Class.extend({
        init: function ParseError(message, pos) {
            this.message = message;
            this.pos = pos;
        },
        toString: function () {
            return this.message;
        }
    });
    var TRUE = {
        type: 'bool',
        value: true
    };
    var FALSE = {
        type: 'bool',
        value: false
    };
    function getcol(str) {
        str = str.toUpperCase();
        for (var col = 0, i = 0; i < str.length; ++i) {
            col = col * 26 + str.charCodeAt(i) - 64;
        }
        return col - 1;
    }
    function getrow(str) {
        return parseInt(str, 10) - 1;
    }
    function parseReference(name, noThrow) {
        if (name.toLowerCase() == '#sheet') {
            return spreadsheet.SHEETREF;
        }
        OUT: {
            var m;
            if (m = /^(\$)?([a-z]+)(\$)?(\d+)$/i.exec(name)) {
                var row = getrow(m[4]), col = getcol(m[2]);
                if (row < 1048576 && col < 16384) {
                    return new CellRef(getrow(m[4]), getcol(m[2]));
                }
                break OUT;
            }
            var stream = TokenStream(name, {});
            var a = [];
            while (true) {
                var ref = stream.next();
                if (ref instanceof CellRef) {
                    ref.rel = 0;
                } else if (ref instanceof RangeRef) {
                    ref.topLeft.rel = 0;
                    ref.bottomRight.rel = 0;
                } else {
                    break OUT;
                }
                a.push(ref);
                if (stream.eof()) {
                    break;
                }
                if (!stream.is('op', SEPARATORS.ARG)) {
                    break OUT;
                }
                stream.next();
            }
            return a.length == 1 ? a[0] : new spreadsheet.UnionRef(a);
        }
        if (!noThrow) {
            throw new Error('Cannot parse reference: ' + name);
        }
    }
    function parseFormula(sheet, row, col, input) {
        var refs = [];
        input = TokenStream(input, {
            row: row,
            col: col
        });
        var is = input.is;
        return {
            type: 'exp',
            ast: parseExpression(true),
            refs: refs,
            sheet: sheet,
            row: row,
            col: col
        };
        function addReference(ref) {
            ref.index = refs.length;
            refs.push(ref);
            return ref;
        }
        function skip(type, value, allowEOF) {
            if (is(type, value)) {
                return input.next();
            } else {
                var tok = input.peek();
                if (tok) {
                    input.croak('Expected ' + type + ' \xAB' + value + '\xBB but found ' + tok.type + ' \xAB' + tok.value + '\xBB');
                } else if (!allowEOF) {
                    input.croak('Expected ' + type + ' \xAB' + value + '\xBB');
                }
            }
        }
        function parseExpression(commas) {
            return maybeBinary(maybeIntersect(parseAtom()), 0, commas);
        }
        function parseSymbol(tok) {
            if (tok.upper == 'TRUE' || tok.upper == 'FALSE') {
                return tok.upper == 'TRUE' ? TRUE : FALSE;
            }
            return addReference(new NameRef(tok.value));
        }
        function parseFuncall() {
            var fname = input.next();
            fname = fname.value;
            skip('punc', '(');
            var args = [];
            while (1) {
                if (is('punc', ')')) {
                    break;
                }
                if (is('op', SEPARATORS.ARG)) {
                    args.push({ type: 'null' });
                    input.next();
                    continue;
                }
                args.push(parseExpression(false));
                if (input.eof() || is('punc', ')')) {
                    break;
                }
                skip('op', SEPARATORS.ARG);
            }
            skip('punc', ')', true);
            return {
                type: 'func',
                func: fname,
                args: args
            };
        }
        function fixReference(ref) {
            if (!ref.hasSheet()) {
                ref.setSheet(sheet);
            }
            return addReference(ref);
        }
        function parseAtom() {
            var exp;
            if (is('ref')) {
                exp = fixReference(input.next());
            } else if (is('func')) {
                exp = parseFuncall();
            } else if (is('punc', '(')) {
                input.next();
                exp = parseExpression(true);
                skip('punc', ')', true);
            } else if (is('punc', '{')) {
                input.next();
                exp = parseArray();
                skip('punc', '}', true);
            } else if (is('num') || is('str') || is('error')) {
                exp = input.next();
            } else if (is('sym')) {
                exp = parseSymbol(input.next());
            } else if (is('op', '+') || is('op', '-')) {
                exp = {
                    type: 'prefix',
                    op: input.next().value,
                    exp: parseAtom()
                };
            } else if (!input.peek()) {
                input.croak('Incomplete expression');
            } else if (is('punc', '[')) {
                input.croak('External reference not supported');
            } else {
                input.croak('Parse error');
            }
            return maybePercent(exp);
        }
        function parseArray() {
            var row = [], value = [row], first = true;
            while (!input.eof() && !is('punc', '}')) {
                if (first) {
                    first = false;
                } else if (is(null, ';')) {
                    value.push(row = []);
                    input.next();
                } else {
                    skip(null, SEPARATORS.COL);
                }
                row.push(parseExpression(false));
            }
            return {
                type: 'matrix',
                value: value
            };
        }
        function maybeIntersect(exp) {
            if (is('punc', '(') || is('ref') || is('num') || is('func')) {
                return {
                    type: 'binary',
                    op: ' ',
                    left: exp,
                    right: parseExpression(false)
                };
            } else {
                return exp;
            }
        }
        function maybePercent(exp) {
            if (is('op', '%')) {
                input.next();
                return maybePercent({
                    type: 'postfix',
                    op: '%',
                    exp: exp
                });
            } else {
                return exp;
            }
        }
        function maybeBinary(left, my_prec, commas) {
            var tok = is('op');
            if (tok && (commas || tok.value != SEPARATORS.ARG)) {
                var his_prec = OPERATORS[tok.value];
                if (his_prec > my_prec) {
                    input.next();
                    var right = maybeBinary(parseAtom(), his_prec, commas);
                    return maybeBinary({
                        type: 'binary',
                        op: tok.value == ';' ? ',' : tok.value,
                        left: left,
                        right: right
                    }, my_prec, commas);
                }
            }
            return left;
        }
    }
    function parseNameDefinition(name, def) {
        var nameRef = parseFormula(null, 0, 0, name);
        if (!(nameRef.ast instanceof NameRef)) {
            throw new ParseError('Invalid name: ' + name);
        }
        nameRef = nameRef.ast;
        if (!(def instanceof Ref)) {
            var defAST = parseFormula(nameRef.sheet, 0, 0, def);
            if (defAST.ast instanceof Ref) {
                def = defAST.ast;
            } else if (/^(?:str|num|bool|error)$/.test(defAST.ast.type)) {
                def = defAST.ast.value;
            } else {
                def = makeFormula(defAST);
            }
        }
        return {
            name: nameRef,
            value: def
        };
    }
    var makeClosure = function (cache) {
        return function (code) {
            var f = cache[code];
            if (!f) {
                f = cache[code] = new Function('\'use strict\';return(' + code + ')')();
            }
            return f;
        };
    }(Object.create(null));
    function makePrinter(exp) {
        return makeClosure('function(row, col, mod){return(' + print(exp.ast, exp, 0) + ')}');
        function print(node, parent, prec) {
            switch (node.type) {
            case 'num':
                return '(kendo.spreadsheet.calc._separators.DEC == \'.\' ? ' + JSON.stringify(JSON.stringify(node.value)) + ' : ' + JSON.stringify(JSON.stringify(node.value)) + '.replace(\'.\' , kendo.spreadsheet.calc._separators.DEC))';
            case 'bool':
                return JSON.stringify(node.value);
            case 'error':
                return JSON.stringify('#' + node.value);
            case 'str':
                return JSON.stringify(JSON.stringify(node.value));
            case 'ref':
                return 'this.refs[' + node.index + '].print(row, col, mod)';
            case 'prefix':
                return withParens(function () {
                    return JSON.stringify(node.op) + ' + ' + print(node.exp, node, OPERATORS[node.op]);
                });
            case 'postfix':
                return withParens(function () {
                    return print(node.exp, node, OPERATORS[node.op]) + ' + ' + JSON.stringify(node.op);
                });
            case 'binary':
                return withParens(function () {
                    var left = parenthesize(print(node.left, node, OPERATORS[node.op]), node.left instanceof NameRef && node.op == ':');
                    var right = parenthesize(print(node.right, node, OPERATORS[node.op]), node.right instanceof NameRef && node.op == ':');
                    if (/^[,;]/.test(node.op)) {
                        return left + ' + kendo.spreadsheet.calc._separators.ARG + ' + right;
                    } else {
                        return left + ' + ' + JSON.stringify(node.op) + ' + ' + right;
                    }
                });
            case 'func':
                return JSON.stringify(node.func + '(') + ' + ' + (node.args.length > 0 ? node.args.map(function (arg) {
                    return print(arg, node, 0);
                }).join(' + kendo.spreadsheet.calc._separators.ARG + \' \' + ') : '\'\'') + ' + \')\'';
            case 'matrix':
                return '\'{ \' + ' + node.value.map(function (el) {
                    return el.map(function (el) {
                        return print(el, node, 0);
                    }).join(' + kendo.spreadsheet.calc._separators.COL + \' \' + ');
                }).join(' + \'; \' + ') + '+ \' }\'';
            case 'null':
                return '\'\'';
            }
            throw new Error('Cannot make printer for node ' + node.type);
            function withParens(f) {
                var op = node.op;
                var needParens = OPERATORS[op] < prec || !prec && op == ',' || parent.type == 'prefix' && prec == OPERATORS[op] && parent.op == '-' || parent.type == 'binary' && prec == OPERATORS[op] && node === parent.right;
                return parenthesize(f(), needParens);
            }
        }
        function parenthesize(code, cond) {
            return cond ? '\'(\' + ' + code + ' + \')\'' : code;
        }
    }
    function toCPS(ast, k) {
        var GENSYM = 0;
        return cps(ast, k);
        function cps(node, k) {
            switch (node.type) {
            case 'ref':
                return cpsRef(node, k);
            case 'num':
            case 'str':
            case 'null':
            case 'error':
            case 'bool':
                return cpsAtom(node, k);
            case 'prefix':
            case 'postfix':
                return cpsUnary(node, k);
            case 'binary':
                return cpsBinary(node, k);
            case 'func':
                return cpsFunc(node, k);
            case 'lambda':
                return cpsLambda(node, k);
            case 'matrix':
                return cpsMatrix(node.value, k, true);
            }
            throw new Error('Cannot CPS ' + node.type);
        }
        function cpsRef(node, k) {
            return node.ref == 'name' ? cpsNameRef(node, k) : cpsAtom(node, k);
        }
        function cpsAtom(node, k) {
            return k(node);
        }
        function cpsNameRef(node, k) {
            return {
                type: 'func',
                func: ',getname',
                args: [
                    makeContinuation(k),
                    node
                ]
            };
        }
        function cpsUnary(node, k) {
            return cps({
                type: 'func',
                func: 'unary' + node.op,
                args: [node.exp]
            }, k);
        }
        function cpsBinary(node, k) {
            return cps({
                type: 'func',
                func: 'binary' + node.op,
                args: [
                    node.left,
                    node.right
                ]
            }, k);
        }
        function cpsIf(co, th, el, k) {
            return cps(co, function (co) {
                var rest = makeContinuation(k);
                var thenK = gensym('T');
                var elseK = gensym('E');
                return {
                    type: 'func',
                    func: 'if',
                    args: [
                        rest,
                        co,
                        {
                            type: 'lambda',
                            vars: [thenK],
                            body: cps(th || TRUE, function (th) {
                                return {
                                    type: 'call',
                                    func: {
                                        type: 'var',
                                        name: thenK
                                    },
                                    args: [th]
                                };
                            })
                        },
                        {
                            type: 'lambda',
                            vars: [elseK],
                            body: cps(el || FALSE, function (el) {
                                return {
                                    type: 'call',
                                    func: {
                                        type: 'var',
                                        name: elseK
                                    },
                                    args: [el]
                                };
                            })
                        }
                    ]
                };
            });
        }
        function cpsAnd(args, k) {
            if (args.length === 0) {
                return cpsAtom(TRUE, k);
            }
            return cps({
                type: 'func',
                func: 'IF',
                args: [
                    args[0],
                    {
                        type: 'func',
                        func: 'AND',
                        args: args.slice(1)
                    },
                    FALSE
                ]
            }, k);
        }
        function cpsOr(args, k) {
            if (args.length === 0) {
                return cpsAtom(FALSE, k);
            }
            return cps({
                type: 'func',
                func: 'IF',
                args: [
                    args[0],
                    TRUE,
                    {
                        type: 'func',
                        func: 'OR',
                        args: args.slice(1)
                    }
                ]
            }, k);
        }
        function cpsFunc(node, k) {
            switch (node.func.toLowerCase()) {
            case 'if':
                return cpsIf(node.args[0], node.args[1], node.args[2], k);
            case 'and':
                return cpsAnd(node.args, k);
            case 'or':
                return cpsOr(node.args, k);
            case 'true':
                return k(TRUE);
            case 'false':
                return k(FALSE);
            }
            return function loop(args, i) {
                if (i == node.args.length) {
                    return {
                        type: 'func',
                        func: node.func,
                        args: args
                    };
                } else {
                    return cps(node.args[i], function (value) {
                        return loop(args.concat([value]), i + 1);
                    });
                }
            }([makeContinuation(k)], 0);
        }
        function cpsLambda(node, k) {
            var cont = gensym('K');
            var body = cps(node.body, function (body) {
                return {
                    type: 'call',
                    func: {
                        type: 'var',
                        value: cont
                    },
                    args: [body]
                };
            });
            return k({
                type: 'lambda',
                vars: [cont].concat(node.vars),
                body: body
            });
        }
        function cpsMatrix(elements, k, isMatrix) {
            var a = [];
            return function loop(i) {
                if (i == elements.length) {
                    return k({
                        type: 'matrix',
                        value: a
                    });
                } else {
                    return (isMatrix ? cpsMatrix : cps)(elements[i], function (val) {
                        a[i] = val;
                        return loop(i + 1);
                    });
                }
            }(0);
        }
        function makeContinuation(k) {
            var cont = gensym('R');
            return {
                type: 'lambda',
                vars: [cont],
                body: k({
                    type: 'var',
                    name: cont
                })
            };
        }
        function gensym(name) {
            if (!name) {
                name = '';
            }
            name = '_' + name;
            return name + ++GENSYM;
        }
    }
    var FORMULA_CACHE = Object.create(null);
    function makeFormula(exp) {
        var printer = makePrinter(exp);
        var hash = printer.call(exp);
        var formula = FORMULA_CACHE[hash];
        if (formula) {
            return formula.clone(exp.sheet, exp.row, exp.col);
        }
        var code = js(toCPS(exp.ast, function (ret) {
            return {
                type: 'return',
                value: ret
            };
        }));
        code = [
            'function(){',
            'var context = this, refs = context.formula.absrefs',
            code,
            '}'
        ].join(';\n');
        formula = new runtime.Formula(exp.refs, makeClosure(code), printer, exp.sheet, exp.row, exp.col);
        FORMULA_CACHE[hash] = formula.clone(exp.sheet, exp.row, exp.col);
        return formula;
        function js(node) {
            var type = node.type;
            if (type == 'num') {
                return node.value + '';
            } else if (type == 'str') {
                return JSON.stringify(node.value);
            } else if (type == 'error') {
                return 'context.error(' + JSON.stringify(node.value) + ')';
            } else if (type == 'return') {
                return 'context.resolve(' + js(node.value) + ')';
            } else if (type == 'func') {
                return 'context.func(' + JSON.stringify(node.func) + ', ' + js(node.args[0]) + ', ' + jsArray(node.args.slice(1)) + ')';
            } else if (type == 'call') {
                return js(node.func) + '(' + node.args.map(js).join(', ') + ')';
            } else if (type == 'ref') {
                return 'refs[' + node.index + ']';
            } else if (type == 'bool') {
                return '' + node.value;
            } else if (type == 'if') {
                return '(context.bool(' + js(node.co) + ') ? ' + js(node.th) + ' : ' + js(node.el) + ')';
            } else if (type == 'lambda') {
                return '(function(' + node.vars.join(', ') + '){ return(' + js(node.body) + ') })';
            } else if (type == 'var') {
                return node.name;
            } else if (type == 'matrix') {
                return jsArray(node.value);
            } else if (type == 'null') {
                return 'null';
            } else {
                throw new Error('Cannot compile expression ' + type);
            }
        }
        function jsArray(a) {
            return '[ ' + a.map(js).join(', ') + ' ]';
        }
    }
    function identity(x) {
        return x;
    }
    function TokenStream(input, options) {
        input = RawTokenStream(InputStream(input), options);
        var ahead = input.ahead;
        var skip = input.skip;
        var token = null;
        var fixCell = options.row != null && options.col != null ? function (cell) {
            if (cell.rel & 1) {
                cell.col -= options.col;
            }
            if (cell.rel & 2) {
                cell.row -= options.row;
            }
            return cell;
        } : identity;
        var addPos = options.forEditor ? function (thing, startToken, endToken) {
            thing.begin = startToken.begin;
            thing.end = endToken.end;
            return thing;
        } : identity;
        return {
            peek: peek,
            next: next,
            croak: input.croak,
            eof: input.eof,
            is: is
        };
        function is(type, value) {
            var tok = peek();
            return tok != null && (type == null || tok.type === type) && (value == null || tok.value === value) ? tok : null;
        }
        function peek() {
            if (token == null) {
                token = readNext();
            }
            return token;
        }
        function next() {
            if (token != null) {
                var tmp = token;
                token = null;
                return tmp;
            }
            return readNext();
        }
        function readNext() {
            var ret;
            var t = input.peek();
            if (t) {
                if (t.type == 'sym' || t.type == 'rc' || t.type == 'num') {
                    ret = ahead(8, refRange3D) || ahead(6, refCell3D) || ahead(6, refSheetRange) || ahead(4, refSheetCell) || ahead(4, refRange) || ahead(2, refCell) || ahead(2, funcall);
                }
                if (!ret) {
                    ret = input.next();
                }
            }
            return ret;
        }
        function toCell(tok, isFirst) {
            if (tok.type == 'rc') {
                if (tok.rel && !options.forEditor && (options.row == null || options.col == null)) {
                    input.croak('Cannot read relative cell in RC notation');
                }
                return new CellRef(tok.row, tok.col, tok.rel);
            }
            if (tok.type == 'num') {
                if (tok.value <= 1048577) {
                    return fixCell(new CellRef(getrow(tok.value), isFirst ? -Infinity : +Infinity, 2));
                } else {
                    return null;
                }
            }
            var name = tok.value;
            var m = /^(\$)?([a-z]+)(\$)?(\d+)$/i.exec(name);
            if (m) {
                var row = getrow(m[4]), col = getcol(m[2]);
                if (row <= 1048576 && col <= 16383) {
                    return fixCell(new CellRef(getrow(m[4]), getcol(m[2]), (m[1] ? 0 : 1) | (m[3] ? 0 : 2)));
                } else {
                    return null;
                }
            }
            var abs = name.charAt(0) == '$';
            if (abs) {
                name = name.substr(1);
            }
            if (/^\d+$/.test(name)) {
                var row = getrow(name);
                if (row <= 1048576) {
                    return fixCell(new CellRef(getrow(name), isFirst ? -Infinity : +Infinity, abs ? 0 : 2));
                }
            } else {
                var col = getcol(name);
                if (col <= 16383) {
                    return fixCell(new CellRef(isFirst ? -Infinity : +Infinity, getcol(name), abs ? 0 : 1));
                }
            }
        }
        function refRange3D(a, b, c, d, e, f, g, h) {
            if (a.type == 'sym' && b.type == 'op' && b.value == ':' && c.type == 'sym' && d.type == 'punc' && d.value == '!' && (e.type == 'sym' || e.type == 'rc' || e.type == 'num' && e.value == e.value | 0) && f.type == 'op' && f.value == ':' && (g.type == 'sym' || g.type == 'rc' || g.type == 'num' && g.value == g.value | 0) && g.type == e.type && !(h.type == 'punc' && h.value == '(' && !g.space)) {
                var tl = toCell(e, true), br = toCell(g, false);
                if (tl && br) {
                    skip(7);
                    return addPos(new RangeRef(tl.setSheet(a.value, true), br.setSheet(c.value, true)).setSheet(a.value, true), a, g);
                }
            }
        }
        function refCell3D(a, b, c, d, e, f) {
            if (a.type == 'sym' && b.type == 'op' && b.value == ':' && c.type == 'sym' && d.type == 'punc' && d.value == '!' && (e.type == 'sym' || e.type == 'rc' || e.type == 'num' && e.value == e.value | 0) && !(f.type == 'punc' && f.value == '(' && !e.space)) {
                var tl = toCell(e);
                if (tl) {
                    skip(5);
                    var br = tl.clone();
                    return addPos(new RangeRef(tl.setSheet(a.value, true), br.setSheet(c.value, true)).setSheet(a.value, true), a, e);
                }
            }
        }
        function refSheetRange(a, b, c, d, e, f) {
            if (a.type == 'sym' && b.type == 'punc' && b.value == '!' && (c.type == 'sym' || c.type == 'rc' || c.type == 'num' && c.value == c.value | 0) && d.type == 'op' && d.value == ':' && (e.type == 'sym' || e.type == 'rc' || e.type == 'num' && e.value == e.value | 0) && !(f.type == 'punc' && f.value == '(' && !e.space)) {
                var tl = toCell(c, true), br = toCell(e, false);
                if (tl && br) {
                    skip(5);
                    return addPos(new RangeRef(tl, br).setSheet(a.value, true), a, e);
                }
            }
        }
        function refSheetCell(a, b, c, d) {
            if (a.type == 'sym' && b.type == 'punc' && b.value == '!' && (c.type == 'sym' || c.type == 'rc' || c.type == 'num' && c.value == c.value | 0) && !(d.type == 'punc' && d.value == '(' && !c.space)) {
                skip(3);
                var x = toCell(c);
                if (!x || !isFinite(x.row)) {
                    x = new NameRef(c.value);
                }
                return addPos(x.setSheet(a.value, true), a, c);
            }
        }
        function refRange(a, b, c, d) {
            if ((a.type == 'sym' || a.type == 'rc' || a.type == 'num' && a.value == a.value | 0) && (b.type == 'op' && b.value == ':') && (c.type == 'sym' || c.type == 'rc' || c.type == 'num' && c.value == c.value | 0) && !(d.type == 'punc' && d.value == '(' && !c.space)) {
                var tl = toCell(a, true), br = toCell(c, false);
                if (tl && br) {
                    skip(3);
                    return addPos(new RangeRef(tl, br), a, c);
                }
            }
        }
        function refCell(a, b) {
            if ((a.type == 'sym' || a.type == 'rc') && !(b.type == 'punc' && b.value == '(' && !a.space)) {
                var x = toCell(a);
                if (x && isFinite(x.row) && isFinite(x.col)) {
                    skip(1);
                    return addPos(x, a, a);
                }
            }
        }
        function funcall(a, b) {
            if (a.type == 'sym' && b.type == 'punc' && b.value == '(' && !a.space) {
                a.type = 'func';
                skip(1);
                return a;
            }
        }
    }
    function isWhitespace(ch) {
        return ' \t\r\n\xA0\u200B'.indexOf(ch) >= 0;
    }
    var EOF = { type: 'eof' };
    function RawTokenStream(input, options) {
        var tokens = [], index = 0;
        var readWhile = input.readWhile;
        return {
            next: next,
            peek: peek,
            eof: eof,
            croak: input.croak,
            ahead: ahead,
            skip: skip
        };
        function isDigit(ch) {
            return /[0-9]/i.test(ch);
        }
        function isIdStart(ch) {
            return /[a-z$_]/i.test(ch) || util.isUnicodeLetter(ch);
        }
        function isId(ch) {
            return isIdStart(ch) || isDigit(ch) || ch == '.';
        }
        function isOpChar(ch) {
            return ch in OPERATORS;
        }
        function isPunc(ch) {
            return '\\!;(){}[]'.indexOf(ch) >= 0;
        }
        function readNumber() {
            var has_dot = false;
            var number = readWhile(function (ch) {
                if (ch == SEPARATORS.DEC) {
                    if (has_dot) {
                        return false;
                    }
                    has_dot = true;
                    return true;
                }
                return isDigit(ch);
            });
            if (number == SEPARATORS.DEC) {
                return {
                    type: 'punc',
                    value: SEPARATORS.DEC
                };
            } else {
                return {
                    type: 'num',
                    value: parseFloat(number.replace(SEPARATORS.DEC, '.'))
                };
            }
        }
        function symbol(id, quote) {
            return {
                type: 'sym',
                value: id,
                upper: id.toUpperCase(),
                space: isWhitespace(input.peek()),
                quote: quote
            };
        }
        function getRC(a, b, c) {
            if (!a && !b && !c) {
                return null;
            }
            if (!a && !c || a && c) {
                var num = b ? parseInt(b, 10) : 0;
                return a ? num : num - 1;
            }
        }
        function readSymbol() {
            var m = input.lookingAt(/^R(\[)?(-?[0-9]+)?(\])?C(\[)?(-?[0-9]+)?(\])?/i);
            if (m) {
                var row = getRC(m[1], m[2], m[3]);
                var col = getRC(m[4], m[5], m[6]);
                if (row != null && col != null) {
                    input.skip(m);
                    return {
                        type: 'rc',
                        row: row,
                        col: col,
                        rel: (m[4] || !(m[4] || m[5] || m[6]) ? 1 : 0) | (m[1] || !(m[1] || m[2] || m[3]) ? 2 : 0)
                    };
                }
            }
            return symbol(readWhile(isId));
        }
        function readString() {
            input.next();
            return {
                type: 'str',
                value: input.readEscaped('"')
            };
        }
        function readSheetName() {
            input.next();
            return symbol(input.readEscaped('\''), true);
        }
        function readOperator() {
            return {
                type: 'op',
                value: readWhile(function (ch, op) {
                    return op + ch in OPERATORS;
                })
            };
        }
        function readPunc() {
            return {
                type: 'punc',
                value: input.next()
            };
        }
        function readNext() {
            if (input.eof()) {
                return null;
            }
            var ch = input.peek(), m;
            if (ch == '"') {
                return readString();
            }
            if (ch == '\'') {
                return readSheetName();
            }
            if (isDigit(ch) || ch == SEPARATORS.DEC) {
                return readNumber();
            }
            if (isIdStart(ch)) {
                return readSymbol();
            }
            if (isOpChar(ch)) {
                return readOperator();
            }
            if (isPunc(ch)) {
                return readPunc();
            }
            if (m = input.lookingAt(/^#([a-z\/]+)[?!]?/i)) {
                input.skip(m);
                return {
                    type: 'error',
                    value: m[1]
                };
            }
            if (!options.forEditor) {
                input.croak('Can\'t handle character with code: ' + ch.charCodeAt(0));
            }
            return {
                type: 'error',
                value: input.next()
            };
        }
        function peek() {
            while (tokens.length <= index) {
                readWhile(isWhitespace);
                var begin = input.pos();
                var tok = readNext();
                if (options.forEditor && tok) {
                    tok.begin = begin;
                    tok.end = input.pos();
                }
                tokens.push(tok);
            }
            return tokens[index];
        }
        function next() {
            var tok = peek();
            if (tok) {
                index++;
            }
            return tok;
        }
        function ahead(n, f) {
            var pos = index, a = [];
            while (n-- > 0) {
                a.push(next() || EOF);
            }
            index = pos;
            return f.apply(a, a);
        }
        function skip(n) {
            index += n;
        }
        function eof() {
            return peek() == null;
        }
    }
    function InputStream(input) {
        var pos = 0, line = 1, col = 0;
        return {
            next: next,
            peek: peek,
            eof: eof,
            croak: croak,
            readWhile: readWhile,
            readEscaped: readEscaped,
            lookingAt: lookingAt,
            skip: skip,
            forward: forward,
            pos: location
        };
        function location() {
            return pos;
        }
        function next() {
            var ch = input.charAt(pos++);
            if (ch == '\n') {
                line++;
                col = 0;
            } else {
                col++;
            }
            return ch;
        }
        function peek() {
            return input.charAt(pos);
        }
        function eof() {
            return peek() === '';
        }
        function croak(msg) {
            throw new ParseError(msg + ' (input: ' + input + ')', pos);
        }
        function skip(ch) {
            if (typeof ch == 'string') {
                if (input.substr(pos, ch.length) != ch) {
                    croak('Expected ' + ch);
                }
                forward(ch.length);
            } else if (ch instanceof RegExp) {
                var m = ch.exec(input.substr(pos));
                if (m) {
                    forward(m[0].length);
                    return m;
                }
            } else {
                forward(ch[0].length);
            }
        }
        function forward(n) {
            while (n-- > 0) {
                next();
            }
        }
        function readEscaped(end) {
            var escaped = false, str = '';
            while (!eof()) {
                var ch = next();
                if (escaped) {
                    str += ch;
                    escaped = false;
                } else if (ch == '\\') {
                    escaped = true;
                } else if (ch == end) {
                    break;
                } else {
                    str += ch;
                }
            }
            return str;
        }
        function readWhile(predicate) {
            var str = '';
            while (!eof() && predicate(peek(), str)) {
                str += next();
            }
            return str;
        }
        function lookingAt(rx) {
            return rx.exec(input.substr(pos));
        }
    }
    var FORMAT_PARSERS = [];
    var registerFormatParser = exports.registerFormatParser = function (p) {
        FORMAT_PARSERS.push(p);
    };
    exports.parse = function (sheet, row, col, input, format) {
        if (input instanceof Date) {
            return {
                type: 'date',
                value: runtime.dateToSerial(input)
            };
        }
        if (typeof input == 'number') {
            return {
                type: 'number',
                value: input
            };
        }
        if (typeof input == 'boolean') {
            return {
                type: 'boolean',
                value: input
            };
        }
        input += '';
        if (/^'/.test(input)) {
            return {
                type: 'string',
                value: input.substr(1)
            };
        }
        if (/^-?[0-9]+%$/.test(input)) {
            var str = input.substr(0, input.length - 1);
            var num = parseFloat(str);
            if (!isNaN(num) && num == str) {
                return {
                    type: 'percent',
                    value: num / 100
                };
            }
        }
        if (/^=/.test(input)) {
            input = input.substr(1);
            if (/\S/.test(input)) {
                return parseFormula(sheet, row, col, input);
            } else {
                return {
                    type: 'string',
                    value: '=' + input
                };
            }
        }
        for (var i = 0; i < FORMAT_PARSERS.length; ++i) {
            var result = FORMAT_PARSERS[i](input);
            if (result) {
                return result;
            }
        }
        if (input.toLowerCase() == 'true') {
            return {
                type: 'boolean',
                value: true
            };
        }
        if (input.toLowerCase() == 'false') {
            return {
                type: 'boolean',
                value: false
            };
        }
        var date = runtime.parseDate(input, format);
        if (date) {
            return {
                type: 'date',
                value: runtime.dateToSerial(date)
            };
        }
        var num = parseFloat(input);
        if (!isNaN(num) && input.length > 0 && num == input) {
            format = null;
            if (num != Math.floor(num)) {
                format = '0.' + String(num).split('.')[1].replace(/\d/g, '0');
            }
            return {
                type: 'number',
                value: num,
                format: format
            };
        }
        return {
            type: 'string',
            value: input
        };
    };
    function tokenize(input, row, col) {
        var tokens = [];
        input = TokenStream(input, {
            forEditor: true,
            row: row,
            col: col
        });
        while (!input.eof()) {
            tokens.push(next());
        }
        var tok = tokens[0];
        if (tok.type == 'op' && tok.value == '=') {
            tok.type = 'startexp';
        }
        return tokens;
        function next() {
            var tok = input.next();
            if (tok.type == 'sym') {
                if (tok.upper == 'TRUE') {
                    tok.type = 'bool';
                    tok.value = true;
                } else if (tok.upper == 'FALSE') {
                    tok.type = 'bool';
                    tok.value = false;
                }
            } else if (tok.type == 'ref') {
                tok = {
                    type: 'ref',
                    ref: row != null && col != null ? tok.absolute(row, col) : tok,
                    begin: tok.begin,
                    end: tok.end
                };
            }
            return tok;
        }
    }
    function parseSqref(input, row, col) {
        row = row || 0;
        col = col || 0;
        input = TokenStream(input, {
            row: row,
            col: col
        });
        var refs = [];
        while (!input.eof()) {
            var ref = input.next();
            if (ref.type != 'ref') {
                throw new ParseError('Expecting a reference but got: ' + JSON.stringify(ref));
            }
            refs.push(ref.absolute(row, col));
        }
        return refs;
    }
    exports.parseNameDefinition = parseNameDefinition;
    exports.parseFormula = parseFormula;
    exports.parseReference = parseReference;
    exports.compile = makeFormula;
    exports.parseSqref = parseSqref;
    exports.InputStream = InputStream;
    exports.ParseError = ParseError;
    exports.tokenize = tokenize;
    registerFormatParser(function (input) {
        var m, date = 0, format = '';
        if (m = /^(\d+)([-\/.])(\d+)\2(\d{2}(?:\d{2})?)(\s*)/.exec(input)) {
            var mo = parseInt(m[1], 10);
            var sep = m[2];
            var da = parseInt(m[3], 10);
            var yr = parseInt(m[4], 10);
            if (yr < 30) {
                yr += 2000;
            } else if (yr < 100) {
                yr += 1900;
            }
            var monthFirst = true;
            if (mo > 12) {
                var tmp = mo;
                mo = da;
                da = tmp;
                monthFirst = false;
            }
            if (!runtime.validDate(yr, mo, da)) {
                return null;
            }
            date = runtime.packDate(yr, mo - 1, da);
            if (date < 0) {
                date--;
            }
            if (monthFirst) {
                format = [
                    'mm',
                    'dd',
                    'yyyy'
                ].join(sep);
            } else {
                format = [
                    'dd',
                    'mm',
                    'yyyy'
                ].join(sep);
            }
            format += m[5];
            input = input.substr(m[0].length);
        }
        if (m = /^(\d+):(\d+)$/.exec(input)) {
            var hh = parseInt(m[1], 10);
            var mm = parseInt(m[2], 10);
            return {
                type: 'date',
                format: format + 'hh:mm',
                value: date + runtime.packTime(hh, mm, 0, 0)
            };
        }
        if (m = /^(\d+):(\d+)(\.\d+)$/.exec(input)) {
            var mm = parseInt(m[1], 10);
            var ss = parseInt(m[2], 10);
            var ms = parseFloat(m[3]) * 1000;
            return {
                type: 'date',
                format: format + 'mm:ss.00',
                value: date + runtime.packTime(0, mm, ss, ms)
            };
        }
        if (m = /^(\d+):(\d+):(\d+)$/.exec(input)) {
            var hh = parseInt(m[1], 10);
            var mm = parseInt(m[2], 10);
            var ss = parseInt(m[3], 10);
            return {
                type: 'date',
                format: format + 'hh:mm:ss',
                value: date + runtime.packTime(hh, mm, ss, 0)
            };
        }
        if (m = /^(\d+):(\d+):(\d+)(\.\d+)$/.exec(input)) {
            var hh = parseInt(m[1], 10);
            var mm = parseInt(m[2], 10);
            var ss = parseInt(m[3], 10);
            var ms = parseFloat(m[4]) * 1000;
            return {
                type: 'date',
                format: format + 'hh:mm:ss.00',
                value: date + runtime.packTime(hh, mm, ss, ms)
            };
        }
    });
    registerFormatParser(function (input) {
        var m, n;
        var culture = kendo.culture();
        var comma = culture.numberFormat[','];
        var dot = culture.numberFormat['.'];
        var currency = culture.numberFormat.currency.symbol;
        var rxnum = getNumberRegexp(comma, dot);
        var rxcur = new RegExp('^\\s*\\' + currency + '\\s*');
        var sign = 1;
        var format = '';
        var suffix = '';
        var has_currency = false;
        var has_percent = false;
        input = InputStream(input.replace(/^\s+|\s+$/g, ''));
        if (input.skip(/^-\s*/)) {
            sign = -1;
        }
        if (m = input.skip(rxcur)) {
            has_currency = true;
            format += '"' + m[0] + '"';
        }
        if (input.skip(/^-\s*/)) {
            if (sign < 0) {
                return null;
            }
            sign = -1;
        }
        if (!(n = input.skip(rxnum))) {
            return null;
        }
        format += '0';
        if (m = input.skip(rxcur)) {
            if (has_currency) {
                return null;
            }
            has_currency = true;
            suffix = '"' + m[0] + '"';
        }
        if (!has_currency && (m = input.skip(/^\s*%\s*/))) {
            has_percent = true;
            suffix = m[0];
        }
        if (!input.eof()) {
            return null;
        }
        if (n[2] || has_currency) {
            format = format.replace('0', '#');
            format += ',0';
        }
        if (n[3]) {
            format += '.' + repeat('0', n[3].length - 1);
        }
        var value = n[0].replace(new RegExp('\\' + comma, 'g'), '').replace(new RegExp('\\' + dot, 'g'), '.');
        value = parseFloat(value);
        if (has_percent) {
            value /= 100;
        }
        format += suffix;
        if (has_currency) {
            format += ';-' + format;
        }
        return {
            type: 'number',
            currency: has_currency,
            format: format,
            value: sign * value
        };
    });
    registerFormatParser(function (input) {
        var m;
        if (m = /^([0-9]*)\.([0-9]+)(\s*%)$/.exec(input)) {
            return {
                type: 'number',
                value: parseFloat(input) / 100,
                format: '0.' + repeat('0', m[2].length) + m[3]
            };
        }
    });
    var NUMBER_FORMAT_RX = {};
    function getNumberRegexp(comma, dot) {
        var id = comma + dot;
        var rx = NUMBER_FORMAT_RX[id];
        if (!rx) {
            rx = '^(\\d+(COM\\d{3})*(DOT\\d+)?)';
            rx = rx.replace(/DOT/g, '\\' + dot).replace(/COM/g, '\\' + comma);
            rx = new RegExp(rx);
            NUMBER_FORMAT_RX[id] = rx;
        }
        return rx;
    }
    function repeat(str, len) {
        var out = '';
        while (len-- > 0) {
            out += str;
        }
        return out;
    }
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/excel-reader', [
        'kendo.core',
        'kendo.color',
        'util/parse-xml',
        'spreadsheet/calc'
    ], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var $ = kendo.jQuery;
    var parseXML = kendo.util.parseXML;
    var parseReference = kendo.spreadsheet.calc.parseReference;
    var MAP_EXCEL_OPERATOR = {
        greaterThanOrEqual: 'greaterThanOrEqualTo',
        lessThanOrEqual: 'lessThanOrEqualTo'
    };
    var ERROR_LOG = null;
    function readExcel(file, workbook, deferred) {
        var reader = new FileReader();
        reader.onload = function (e) {
            var zip = new JSZip(e.target.result);
            readWorkbook(zip, workbook, deferred);
        };
        reader.readAsArrayBuffer(file);
    }
    var SEL_CELL = [
        'sheetData',
        'row',
        'c'
    ];
    var SEL_COL = [
        'cols',
        'col'
    ];
    var SEL_DEFINED_NAME = [
        'definedNames',
        'definedName'
    ];
    var SEL_FORMULA = [
        'sheetData',
        'row',
        'c',
        'f'
    ];
    var SEL_MERGE = [
        'mergeCells',
        'mergeCell'
    ];
    var SEL_PANE = [
        'sheetViews',
        'sheetView',
        'pane'
    ];
    var SEL_ROW = [
        'sheetData',
        'row'
    ];
    var SEL_SELECTION = [
        'sheetViews',
        'sheetView',
        'selection'
    ];
    var SEL_SHEET = [
        'sheets',
        'sheet'
    ];
    var SEL_STRING = [
        'sheetData',
        'row',
        'c',
        'is'
    ];
    var SEL_TEXT = ['t'];
    var SEL_SHARED_STRING = ['si'];
    var SEL_VALUE = [
        'sheetData',
        'row',
        'c',
        'v'
    ];
    var SEL_VIEW = [
        'bookViews',
        'workbookView'
    ];
    var SEL_SHEET_VIEW = [
        'sheetViews',
        'sheetView'
    ];
    var SEL_HYPERLINK = [
        'hyperlinks',
        'hyperlink'
    ];
    var SEL_VALIDATION = [
        'dataValidations',
        'dataValidation'
    ];
    var SEL_VALIDATION_FORMULA1 = [
        'dataValidations',
        'dataValidation',
        'formula1'
    ];
    var SEL_VALIDATION_FORMULA2 = [
        'dataValidations',
        'dataValidation',
        'formula2'
    ];
    var SEL_VALIDATION_INSANE = [
        'x14:dataValidations',
        'x14:dataValidation'
    ];
    var SEL_VALIDATION_SQREF_INSANE = [
        'x14:dataValidations',
        'x14:dataValidation',
        'xm:sqref'
    ];
    var SEL_VALIDATION_FORMULA1_INSANE = [
        'x14:dataValidations',
        'x14:dataValidation',
        'x14:formula1',
        'xm:f'
    ];
    var SEL_VALIDATION_FORMULA2_INSANE = [
        'x14:dataValidations',
        'x14:dataValidation',
        'x14:formula2',
        'xm:f'
    ];
    var SEL_COMMENT = [
        'commentList',
        'comment'
    ];
    var SEL_AUTHOR = [
        'authors',
        'author'
    ];
    var SEL_COMMENT_TEXT = ['t'];
    function xl(file) {
        if (!/^\//.test(file)) {
            if (!/^xl\//.test(file)) {
                file = 'xl/' + file;
            }
        } else {
            file = file.substr(1);
        }
        return file;
    }
    function readWorkbook(zip, workbook, progress) {
        ERROR_LOG = workbook.excelImportErrors = [];
        var strings = readStrings(zip);
        var relationships = readRelationships(zip, '_rels/workbook.xml');
        var theme = readTheme(zip, relationships.byType.theme[0]);
        var styles = readStyles(zip, theme);
        var items = [];
        var activeSheet = 0;
        parse(zip, 'xl/workbook.xml', {
            enter: function (tag, attrs) {
                if (this.is(SEL_SHEET)) {
                    var relId = attrs['r:id'];
                    var file = relationships.byId[relId];
                    var name = attrs.name;
                    var dim = sheetDimensions(zip, file);
                    workbook.options.columnWidth = dim.columnWidth || workbook.options.columnWidth;
                    workbook.options.rowHeight = dim.rowHeight || workbook.options.rowHeight;
                    items.push({
                        workbook: workbook,
                        zip: zip,
                        strings: strings,
                        styles: styles,
                        file: file,
                        options: {
                            name: name,
                            rows: Math.max(workbook.options.rows || 0, dim.rows),
                            columns: Math.max(workbook.options.columns || 0, dim.cols),
                            columnWidth: dim.columnWidth,
                            rowHeight: dim.rowHeight
                        }
                    });
                } else if (this.is(SEL_VIEW)) {
                    if (attrs.activeTab) {
                        activeSheet = integer(attrs.activeTab);
                    }
                }
            },
            text: function (text) {
                var attrs = this.is(SEL_DEFINED_NAME);
                if (attrs && !(bool(attrs['function']) || bool(attrs.vbProcedure))) {
                    var localSheetId = attrs.localSheetId;
                    var sheet = null;
                    if (localSheetId != null) {
                        sheet = items[localSheetId].options.name;
                    }
                    var name = attrs.name;
                    if (name != '_xlnm._FilterDatabase') {
                        if (sheet) {
                            name = '\'' + sheet.replace(/\'/g, '\\\'') + '\'!' + name;
                        }
                        withErrorLog(sheet, null, function () {
                            workbook.defineName(name, text, bool(attrs.hidden));
                        }, 'reading user-defined name: ' + name);
                    }
                }
            }
        });
        var loading = new $.Deferred();
        loading.progress(function (args) {
            if (progress) {
                progress.notify(args);
            }
        }).then(function () {
            var sheets = workbook.sheets();
            recalcSheets(sheets);
            workbook.activeSheet(sheets[activeSheet]);
            if (progress) {
                progress.resolve();
            }
        });
        loadSheets(items, workbook, loading);
    }
    function loadSheets(items, workbook, progress) {
        var ready = new $.Deferred().resolve();
        for (var i = 0; i < items.length; i++) {
            (function (entry, i) {
                ready = ready.then(function () {
                    var sheet = workbook.insertSheet(entry.options);
                    sheet.suspendChanges(true);
                    var promise = queueSheet(sheet, entry);
                    var args = {
                        sheet: sheet,
                        progress: i / (items.length - 1)
                    };
                    promise.then(function () {
                        progress.notify(args);
                    });
                    return promise;
                });
            }(items[i], i));
        }
        ready.then(function () {
            progress.resolve();
        });
    }
    function queueSheet(sheet, ctx) {
        var deferred = new $.Deferred();
        setTimeout(function () {
            readSheet(ctx.zip, ctx.file, sheet, ctx.strings, ctx.styles);
            deferred.resolve();
        }, 0);
        return deferred;
    }
    function recalcSheets(sheets) {
        for (var i = 0; i < sheets.length; i++) {
            sheets[i].suspendChanges(false).triggerChange({ recalc: true });
        }
    }
    function sheetDimensions(zip, file) {
        var dim = {
            rows: 0,
            cols: 0
        };
        parse(zip, xl(file), {
            enter: function (tag, attrs) {
                if (tag == 'dimension') {
                    var ref = parseReference(attrs.ref);
                    if (ref.bottomRight) {
                        dim.cols = ref.bottomRight.col + 1;
                        dim.rows = ref.bottomRight.row + 1;
                    }
                } else if (tag === 'sheetFormatPr') {
                    if (attrs.defaultColWidth) {
                        dim.columnWidth = toColWidth(parseFloat(attrs.defaultColWidth));
                    }
                    if (attrs.defaultRowHeight) {
                        dim.rowHeight = toRowHeight(parseFloat(attrs.defaultRowHeight));
                    }
                } else if (this.is(SEL_ROW)) {
                    this.exit();
                }
            }
        });
        return dim;
    }
    function toColWidth(size) {
        var maximumDigitWidth = 7;
        var fraction = (256 * size + Math.floor(128 / maximumDigitWidth)) / 256;
        return fraction * maximumDigitWidth;
    }
    function toRowHeight(pts) {
        return pts * (4 / 3);
    }
    function readSheet(zip, file, sheet, strings, styles) {
        var sharedFormulas = {};
        var ref, type, value, formula, formulaRange, isArrayFormula;
        var nCols = sheet._columns._count;
        var prevCellRef = null;
        var relsFile = file.replace(/worksheets\//, 'worksheets/_rels/');
        var relationships = readRelationships(zip, relsFile);
        var formula1, formula2;
        var filterRef;
        var filterColumn;
        var customFilterLogic;
        var customFilterCriteria;
        var valueFilterBlanks;
        var valueFilterValues;
        var filters = [];
        ERROR_LOG = sheet._workbook.excelImportErrors;
        file = xl(file);
        parse(zip, file, {
            enter: function (tag, attrs, closed) {
                var tmp;
                if (this.is(SEL_FORMULA)) {
                    if (closed) {
                        if (attrs.t == 'shared' && attrs.si != null) {
                            formula = sheet.range(sharedFormulas[attrs.si])._get('formula');
                        }
                    }
                } else if (this.is(SEL_CELL)) {
                    value = null;
                    formula = null;
                    ref = attrs.r;
                    formulaRange = null;
                    if (ref == null) {
                        ref = parseReference(prevCellRef);
                        ref.col++;
                        ref = ref.toString();
                    }
                    prevCellRef = ref;
                    type = attrs.t;
                    var styleIndex = attrs.s;
                    if (styleIndex != null) {
                        applyStyle(sheet, ref, styles, styleIndex);
                    }
                } else if (this.is(SEL_MERGE)) {
                    sheet.range(attrs.ref).merge();
                } else if (this.is(SEL_COL)) {
                    var start = integer(attrs.min) - 1;
                    var stop = Math.min(nCols, integer(attrs.max)) - 1;
                    var width;
                    if (attrs.width) {
                        width = toColWidth(parseFloat(attrs.width));
                        if (width !== 0) {
                            sheet._columns.values.value(start, stop, width);
                        }
                    }
                    if (attrs.hidden === '1' || width === 0) {
                        for (var ci = start; ci <= stop; ci++) {
                            sheet.hideColumn(ci);
                        }
                    }
                    if (attrs.style != null) {
                        applyStyle(sheet, new kendo.spreadsheet.RangeRef(new kendo.spreadsheet.CellRef(-Infinity, start), new kendo.spreadsheet.CellRef(+Infinity, stop)), styles, attrs.style);
                    }
                } else if (this.is(SEL_ROW)) {
                    var row = integer(attrs.r) - 1;
                    var height;
                    if (attrs.ht) {
                        height = toRowHeight(parseFloat(attrs.ht));
                        if (height !== 0) {
                            sheet._rows.values.value(row, row, height);
                        }
                    }
                    if (attrs.hidden === '1' || height === 0) {
                        sheet.hideRow(row);
                    }
                } else if (this.is(SEL_SELECTION)) {
                    if (attrs.activeCell) {
                        var acRef = parseReference(attrs.activeCell);
                        sheet.select(acRef, true);
                    }
                } else if (this.is(SEL_PANE)) {
                    if (attrs.state == 'frozen') {
                        if (attrs.xSplit) {
                            sheet.frozenColumns(integer(attrs.xSplit));
                        }
                        if (attrs.ySplit) {
                            sheet.frozenRows(integer(attrs.ySplit));
                        }
                    }
                } else if (this.is(SEL_SHEET_VIEW)) {
                    sheet.showGridLines(bool(attrs.showGridLines, true));
                } else if (this.is(SEL_HYPERLINK)) {
                    var relId = attrs['r:id'];
                    var target = relationships.byId[relId];
                    if (target) {
                        sheet.range(attrs.ref).link(target);
                    }
                } else if (this.is(['autoFilter'])) {
                    filterRef = attrs.ref;
                    if (closed) {
                        addAutoFilter();
                    }
                } else if (filterRef) {
                    if (this.is(['filterColumn'])) {
                        filterColumn = parseInt(attrs.colId, 10);
                    } else if (this.is(['customFilters'])) {
                        customFilterLogic = bool(attrs.and) ? 'and' : 'or';
                        customFilterCriteria = [];
                    } else if (this.is(['customFilter'])) {
                        tmp = getCustomFilter(attrs.operator, attrs.val);
                        if (tmp) {
                            customFilterCriteria.push({
                                operator: tmp.operator,
                                value: tmp.value
                            });
                        }
                    } else if (this.is(['dynamicFilter'])) {
                        filters.push({
                            column: filterColumn,
                            filter: new kendo.spreadsheet.DynamicFilter({ type: dynamicFilterType(attrs.type) })
                        });
                    } else if (this.is(['top10'])) {
                        filters.push({
                            column: filterColumn,
                            filter: new kendo.spreadsheet.TopFilter({
                                value: getFilterVal(attrs.val),
                                type: function (percent, top) {
                                    return percent && top ? 'topPercent' : top ? 'topNumber' : percent ? 'bottomPercent' : 'bottomNumber';
                                }(bool(attrs.percent), bool(attrs.top))
                            })
                        });
                    } else if (this.is(['filters'])) {
                        valueFilterBlanks = bool(attrs.blank);
                        valueFilterValues = [];
                    } else if (this.is(['filter'])) {
                        valueFilterValues.push(getFilterVal(attrs.val));
                    }
                }
            },
            leave: function (tag, attrs) {
                if (this.is(SEL_FORMULA)) {
                    if (!formula && attrs.t == 'shared' && attrs.si != null) {
                        formula = sheet.range(sharedFormulas[attrs.si])._get('formula');
                    }
                } else if (this.is(SEL_CELL)) {
                    if (formula != null) {
                        var failed = withErrorLog(sheet, formulaRange || ref, function () {
                            sheet.range(formulaRange || ref).formula(formula, isArrayFormula);
                        }, 'parsing formula');
                        if (failed) {
                            sheet.range(formulaRange || ref).value(formula).background('#ffaaaa');
                        }
                    } else if (value != null) {
                        var range = sheet.range(ref);
                        if (!range._get('formula')) {
                            if (!type || type == 'n') {
                                value = parseFloat(value);
                            } else if (type == 's') {
                                value = strings[integer(value)];
                            } else if (type == 'b') {
                                value = value === '1';
                            } else if (type == 'd') {
                                value = kendo.parseDate(value);
                            }
                            if (value != null) {
                                range.value(value);
                            }
                        }
                    }
                } else if (this.is(SEL_VALIDATION) || this.is(SEL_VALIDATION_INSANE)) {
                    (function () {
                        var refs = kendo.spreadsheet.calc.parseSqref(attrs.sqref);
                        var type = attrs.type.toLowerCase();
                        var operator = attrs.operator;
                        if (/^(?:whole|decimal)$/.test(type)) {
                            type = 'number';
                        } else if (type == 'list') {
                            operator = 'list';
                        }
                        if (!operator && /^(?:number|date)$/.test(type)) {
                            operator = 'between';
                        }
                        refs.forEach(function (ref) {
                            withErrorLog(sheet, ref, function () {
                                sheet.range(ref).validation({
                                    type: bool(attrs.showErrorMessage, true) ? 'reject' : 'warning',
                                    from: formula1,
                                    to: formula2,
                                    dataType: type,
                                    comparerType: MAP_EXCEL_OPERATOR[operator] || operator,
                                    allowNulls: bool(attrs.allowBlank),
                                    showButton: bool(attrs.showDropDown) || type == 'date' || type == 'list',
                                    messageTemplate: attrs.error,
                                    titleTemplate: attrs.errorTitle
                                });
                            }, 'parsing validation');
                        });
                    }());
                } else if (tag == 'cols') {
                    sheet._columns._refresh();
                } else if (tag == 'sheetData') {
                    sheet._rows._refresh();
                } else if (tag == 'autoFilter') {
                    addAutoFilter();
                } else if (filterRef) {
                    if (tag == 'customFilters') {
                        filters.push({
                            column: filterColumn,
                            filter: new kendo.spreadsheet.CustomFilter({
                                logic: customFilterLogic,
                                criteria: customFilterCriteria
                            })
                        });
                    } else if (tag == 'filters') {
                        filters.push({
                            column: filterColumn,
                            filter: new kendo.spreadsheet.ValueFilter({
                                values: valueFilterValues,
                                blanks: valueFilterBlanks
                            })
                        });
                    }
                }
            },
            text: function (text) {
                var attrs;
                if (this.is(SEL_VALUE) || this.is(SEL_STRING)) {
                    value = text;
                } else if (attrs = this.is(SEL_FORMULA)) {
                    formula = text;
                    isArrayFormula = attrs.t == 'array';
                    if (isArrayFormula) {
                        formulaRange = attrs.ref;
                    } else if (attrs.t == 'shared') {
                        sharedFormulas[attrs.si] = ref;
                    }
                } else if (this.is(SEL_VALIDATION_FORMULA1) || this.is(SEL_VALIDATION_FORMULA1_INSANE)) {
                    formula1 = text;
                } else if (this.is(SEL_VALIDATION_FORMULA2) || this.is(SEL_VALIDATION_FORMULA2_INSANE)) {
                    formula2 = text;
                } else if (this.is(SEL_VALIDATION_SQREF_INSANE)) {
                    this.stack[this.stack.length - 2].sqref = text;
                }
            }
        });
        if (relationships.byType.comments) {
            var commentFile = relative_file(file, relationships.byType.comments[0]);
            readComments(zip, commentFile, sheet);
        }
        if (relationships.byType.drawing) {
            var drawingFile = relative_file(file, relationships.byType.drawing[0]);
            readDrawings(zip, drawingFile, sheet);
        }
        function addAutoFilter() {
            sheet.range(filterRef).filter(filters);
            filterRef = null;
        }
    }
    function getContentType(filename) {
        var m = /\.([^.]+)$/.exec(filename);
        if (m && m[1]) {
            return {
                jpg: 'image/jpeg',
                jpeg: 'image/jpeg',
                png: 'image/png',
                gif: 'image/gif'
            }[m[1].toLowerCase()];
        }
    }
    function getFileName(filename) {
        var m = /[^\/]+$/.exec(filename);
        return m && m[0];
    }
    function readDrawings(zip, file, sheet) {
        var sel_two_cell_anchor = ['xdr:twoCellAnchor'];
        var sel_ext = ['xdr:ext'];
        var sel_one_cell_anchor = ['xdr:oneCellAnchor'];
        var sel_from = ['xdr:from'];
        var sel_to = ['xdr:to'];
        var sel_row = ['xdr:row'];
        var sel_col = ['xdr:col'];
        var sel_row_offset = ['xdr:rowOff'];
        var sel_col_offset = ['xdr:colOff'];
        var sel_blip = [
            'xdr:blipFill',
            'a:blip'
        ];
        var relsFile = file.replace(/drawings\//, 'drawings/_rels/');
        var relationships = readRelationships(zip, relsFile);
        if (relationships.byType.image) {
            Object.keys(relationships.byId).forEach(function (id) {
                var img = relative_file(file, relationships.byId[id]);
                var type = getContentType(img);
                if (type) {
                    var data = zip.files[img].asArrayBuffer();
                    var name = getFileName(img);
                    var blob = name && !(kendo.support.browser.msie || kendo.support.browser.edge) ? new window.File([data], name, { type: type }) : new window.Blob([data], { type: type });
                    relationships.byId[id] = sheet._workbook.addImage(blob);
                }
            });
        }
        var cdr, ref, width, height;
        parse(zip, file, {
            enter: function (tag, attrs) {
                if (this.is(sel_two_cell_anchor) || this.is(sel_one_cell_anchor)) {
                    cdr = {};
                } else if (this.is(sel_from) || this.is(sel_to)) {
                    ref = {};
                } else if (this.is(sel_blip)) {
                    var id = attrs['r:embed'];
                    cdr.image = relationships.byId[id];
                } else if (this.is(sel_ext)) {
                    width = excelToPixels(parseFloat(attrs.cx));
                    height = excelToPixels(parseFloat(attrs.cy));
                }
            },
            leave: function () {
                if (this.is(sel_from)) {
                    cdr.topLeftCell = new kendo.spreadsheet.CellRef(ref.row, ref.col);
                    cdr.offsetX = excelToPixels(ref.colOffset);
                    cdr.offsetY = excelToPixels(ref.rowOffset);
                } else if (this.is(sel_to)) {
                    cdr.brCell = new kendo.spreadsheet.CellRef(ref.row, ref.col);
                    cdr.brX = excelToPixels(ref.colOffset);
                    cdr.brY = excelToPixels(ref.rowOffset);
                } else if (this.is(sel_two_cell_anchor)) {
                    var left = sheet._columns.sum(0, cdr.topLeftCell.col - 1) + cdr.offsetX;
                    var top = sheet._rows.sum(0, cdr.topLeftCell.row - 1) + cdr.offsetY;
                    var right = sheet._columns.sum(0, cdr.brCell.col - 1) + cdr.brX;
                    var bottom = sheet._rows.sum(0, cdr.brCell.row - 1) + cdr.brY;
                    sheet.addDrawing({
                        topLeftCell: cdr.topLeftCell,
                        offsetX: cdr.offsetX,
                        offsetY: cdr.offsetY,
                        width: width != null ? width : right - left,
                        height: height != null ? height : bottom - top,
                        image: cdr.image,
                        opacity: 1
                    });
                } else if (this.is(sel_one_cell_anchor)) {
                    sheet.addDrawing({
                        topLeftCell: cdr.topLeftCell,
                        offsetX: cdr.offsetX,
                        offsetY: cdr.offsetY,
                        width: width,
                        height: height,
                        image: cdr.image,
                        opacity: 1
                    });
                }
            },
            text: function (text) {
                if (this.is(sel_row)) {
                    ref.row = parseFloat(text);
                } else if (this.is(sel_col)) {
                    ref.col = parseFloat(text);
                } else if (this.is(sel_row_offset)) {
                    ref.rowOffset = parseFloat(text);
                } else if (this.is(sel_col_offset)) {
                    ref.colOffset = parseFloat(text);
                }
            }
        });
    }
    function readComments(zip, file, sheet) {
        var authors = [];
        var author;
        var comment;
        parse(zip, file, {
            enter: function (tag, attrs) {
                if (this.is(SEL_COMMENT)) {
                    comment = {
                        author: authors[attrs.authorId],
                        ref: attrs.ref,
                        text: ''
                    };
                } else if (this.is(SEL_AUTHOR)) {
                    author = '';
                }
            },
            leave: function () {
                if (this.is(SEL_COMMENT)) {
                    sheet.range(comment.ref).comment(comment.text);
                } else if (this.is(SEL_AUTHOR)) {
                    authors.push(author);
                }
            },
            text: function (text) {
                if (this.is(SEL_COMMENT_TEXT)) {
                    comment.text += text;
                } else if (this.is(SEL_AUTHOR)) {
                    author += text;
                }
            }
        });
    }
    function getCustomFilter(op, value) {
        var ourOp = {
            equal: 'eq',
            notEqual: 'ne',
            greaterThan: 'gt',
            greaterThanOrEqual: 'gte',
            lessThan: 'lt',
            lessThanOrEqual: 'lte'
        }[op];
        value = getFilterVal(value);
        if (ourOp && typeof value == 'number') {
            return {
                operator: ourOp,
                value: value
            };
        }
        if ((op == 'notEqual' || !op) && typeof value == 'string') {
            return {
                operator: op ? 'doesnotmatch' : 'matches',
                value: value
            };
        }
    }
    function dynamicFilterType(type) {
        return {
            Q1: 'quarter1',
            Q2: 'quarter2',
            Q3: 'quarter3',
            Q4: 'quarter4',
            M1: 'january',
            M2: 'february',
            M3: 'march',
            M4: 'april',
            M5: 'may',
            M6: 'june',
            M7: 'july',
            M8: 'august',
            M9: 'september',
            M10: 'october',
            M11: 'november',
            M12: 'december'
        }[type.toUpperCase()] || type;
    }
    function getFilterVal(val) {
        var tmp = parseFloat(val);
        if (!isNaN(tmp) && tmp == val) {
            return tmp;
        }
        return val;
    }
    function withErrorLog(sheet, ref, func, context) {
        try {
            func();
            return false;
        } catch (ex) {
            var err = {
                context: context,
                error: String(ex)
            };
            if (sheet) {
                err.sheet = sheet.name();
            }
            if (ref) {
                err.location = String(ref);
            }
            ERROR_LOG.push(err);
            return true;
        }
    }
    var BORDER_WIDTHS = {
        'none': 0,
        'thin': 1,
        'medium': 2,
        'dashed': 1,
        'dotted': 1,
        'thick': 3,
        'double': 3,
        'hair': 1,
        'mediumDashed': 2,
        'dashDot': 1,
        'mediumDashDot': 2,
        'dashDotDot': 1,
        'mediumDashDotDot': 2,
        'slantDashDot': 1
    };
    var DEFAULT_FORMATS = {
        0: 'General',
        1: '0',
        2: '0.00',
        3: '#,##0',
        4: '#,##0.00',
        9: '0%',
        10: '0.00%',
        11: '0.00E+00',
        12: '# ?/?',
        13: '# ??/??',
        14: 'mm-dd-yy',
        15: 'd-mmm-yy',
        16: 'd-mmm',
        17: 'mmm-yy',
        18: 'h:mm AM/PM',
        19: 'h:mm:ss AM/PM',
        20: 'h:mm',
        21: 'h:mm:ss',
        22: 'm/d/yy h:mm',
        37: '#,##0 ;(#,##0)',
        38: '#,##0 ;[Red](#,##0)',
        39: '#,##0.00;(#,##0.00)',
        40: '#,##0.00;[Red](#,##0.00)',
        45: 'mm:ss',
        46: '[h]:mm:ss',
        47: 'mmss.0',
        48: '##0.0E+0',
        49: '@'
    };
    function applyStyle(sheet, ref, styles, styleIndex) {
        var range = sheet.range(ref);
        var xf = styles.inlineStyles[styleIndex], base, value;
        if (xf.xfId) {
            base = styles.namedStyles[xf.xfId];
        }
        if (shouldSet('applyBorder', 'borderId')) {
            setBorder(styles.borders[value]);
        }
        if (shouldSet('applyFont', 'fontId')) {
            setFont(styles.fonts[value]);
        }
        if (shouldSet('applyAlignment', 'textAlign')) {
            range.textAlign(value);
        }
        if (shouldSet('applyAlignment', 'verticalAlign')) {
            range.verticalAlign(value);
        }
        if (shouldSet('applyAlignment', 'indent')) {
            range.indent(value);
        }
        if (shouldSet('applyAlignment', 'wrapText')) {
            range._property('wrap', value);
        }
        if (shouldSet('applyFill', 'fillId')) {
            setFill(styles.fills[value]);
        }
        if (shouldSet('applyNumberFormat', 'numFmtId')) {
            setFormat(styles.numFmts[value] || DEFAULT_FORMATS[value]);
        }
        function setFormat(f) {
            var format = typeof f == 'string' ? f : f.formatCode;
            if (format != null && !/^general$/i.test(format)) {
                format = format.replace(/^\[\$-[0-9]+\]/, '');
                range.format(format);
            }
        }
        function setFill(f) {
            if (f.type == 'solid') {
                range.background(f.color);
            }
        }
        function setFont(f) {
            range.fontFamily(f.name);
            if (f.size) {
                range._property('fontSize', f.size * 4 / 3);
            }
            if (f.bold) {
                range.bold(true);
            }
            if (f.italic) {
                range.italic(true);
            }
            if (f.underline) {
                range.underline(true);
            }
            if (f.color) {
                range.color(f.color);
            }
        }
        function setBorder(b) {
            function set(side, prop) {
                var border = b[side];
                if (!border) {
                    return;
                }
                var width = BORDER_WIDTHS[border.style];
                if (width === 0) {
                    return;
                }
                var color = border.color;
                if (color == null) {
                    color = '#000';
                }
                range._property(prop, {
                    size: width,
                    color: color
                });
            }
            set('left', 'borderLeft');
            set('top', 'borderTop');
            set('right', 'borderRight');
            set('bottom', 'borderBottom');
        }
        function shouldSet(applyName, propName) {
            var t = xf[applyName];
            if (t != null && !t) {
                return false;
            }
            value = xf[propName];
            if (base && value == null) {
                t = base[applyName];
                if (t != null && !t) {
                    return false;
                }
                value = base[propName];
            }
            return value != null;
        }
    }
    function parse(zip, file, callbacks) {
        var part = zip.files[file];
        if (part) {
            parseXML(part.asUint8Array(), callbacks);
        }
    }
    function readStrings(zip) {
        var strings = [];
        var current = null;
        parse(zip, 'xl/sharedStrings.xml', {
            leave: function () {
                if (this.is(SEL_SHARED_STRING)) {
                    strings.push(current);
                    current = null;
                }
            },
            text: function (text) {
                if (this.is(SEL_TEXT)) {
                    if (current == null) {
                        current = '';
                    }
                    current += text;
                }
            }
        });
        return strings;
    }
    function readRelationships(zip, file) {
        var map = {
            byId: {},
            byType: { theme: [] }
        };
        parse(zip, xl(file) + '.rels', {
            enter: function (tag, attrs) {
                if (tag == 'Relationship') {
                    map.byId[attrs.Id] = attrs.Target;
                    var type = attrs.Type.match(/\w+$/)[0];
                    var entries = map.byType[type] || [];
                    entries.push(attrs.Target);
                    map.byType[type] = entries;
                }
            }
        });
        return map;
    }
    var SEL_BORDER = [
        'borders',
        'border'
    ];
    var SEL_FILL = [
        'fills',
        'fill'
    ];
    var SEL_FONT = [
        'fonts',
        'font'
    ];
    var SEL_INLINE_STYLE = [
        'cellXfs',
        'xf'
    ];
    var SEL_NAMED_STYLE = [
        'cellStyleXfs',
        'xf'
    ];
    var SEL_NUM_FMT = [
        'numFmts',
        'numFmt'
    ];
    var INDEXED_COLORS = [
        toCSSColor('FF000000'),
        toCSSColor('FFFFFFFF'),
        toCSSColor('FFFF0000'),
        toCSSColor('FF00FF00'),
        toCSSColor('FF0000FF'),
        toCSSColor('FFFFFF00'),
        toCSSColor('FFFF00FF'),
        toCSSColor('FF00FFFF'),
        toCSSColor('FF000000'),
        toCSSColor('FFFFFFFF'),
        toCSSColor('FFFF0000'),
        toCSSColor('FF00FF00'),
        toCSSColor('FF0000FF'),
        toCSSColor('FFFFFF00'),
        toCSSColor('FFFF00FF'),
        toCSSColor('FF00FFFF'),
        toCSSColor('FF800000'),
        toCSSColor('FF008000'),
        toCSSColor('FF000080'),
        toCSSColor('FF808000'),
        toCSSColor('FF800080'),
        toCSSColor('FF008080'),
        toCSSColor('FFC0C0C0'),
        toCSSColor('FF808080'),
        toCSSColor('FF9999FF'),
        toCSSColor('FF993366'),
        toCSSColor('FFFFFFCC'),
        toCSSColor('FFCCFFFF'),
        toCSSColor('FF660066'),
        toCSSColor('FFFF8080'),
        toCSSColor('FF0066CC'),
        toCSSColor('FFCCCCFF'),
        toCSSColor('FF000080'),
        toCSSColor('FFFF00FF'),
        toCSSColor('FFFFFF00'),
        toCSSColor('FF00FFFF'),
        toCSSColor('FF800080'),
        toCSSColor('FF800000'),
        toCSSColor('FF008080'),
        toCSSColor('FF0000FF'),
        toCSSColor('FF00CCFF'),
        toCSSColor('FFCCFFFF'),
        toCSSColor('FFCCFFCC'),
        toCSSColor('FFFFFF99'),
        toCSSColor('FF99CCFF'),
        toCSSColor('FFFF99CC'),
        toCSSColor('FFCC99FF'),
        toCSSColor('FFFFCC99'),
        toCSSColor('FF3366FF'),
        toCSSColor('FF33CCCC'),
        toCSSColor('FF99CC00'),
        toCSSColor('FFFFCC00'),
        toCSSColor('FFFF9900'),
        toCSSColor('FFFF6600'),
        toCSSColor('FF666699'),
        toCSSColor('FF969696'),
        toCSSColor('FF003366'),
        toCSSColor('FF339966'),
        toCSSColor('FF003300'),
        toCSSColor('FF333300'),
        toCSSColor('FF993300'),
        toCSSColor('FF993366'),
        toCSSColor('FF333399'),
        toCSSColor('FF333333'),
        toCSSColor('FF000000'),
        toCSSColor('FFFFFFFF')
    ];
    function readStyles(zip, theme) {
        var styles = {
            fonts: [],
            numFmts: {},
            fills: [],
            borders: [],
            namedStyles: [],
            inlineStyles: []
        };
        var font = null;
        var fill = null;
        var border = null;
        var xf = null;
        parse(zip, 'xl/styles.xml', {
            enter: function (tag, attrs, closed) {
                if (this.is(SEL_NUM_FMT)) {
                    styles.numFmts[attrs.numFmtId] = attrs;
                } else if (this.is(SEL_FONT)) {
                    styles.fonts.push(font = {});
                } else if (font) {
                    if (tag == 'sz') {
                        font.size = parseFloat(attrs.val);
                    } else if (tag == 'name') {
                        font.name = attrs.val;
                    } else if (tag == 'b') {
                        font.bold = bool(attrs.val, true);
                    } else if (tag == 'i') {
                        font.italic = bool(attrs.val, true);
                    } else if (tag == 'u') {
                        font.underline = attrs.val == null || attrs.val == 'single';
                    } else if (tag == 'color') {
                        font.color = getColor(attrs);
                    }
                } else if (this.is(SEL_FILL)) {
                    styles.fills.push(fill = {});
                } else if (fill) {
                    if (tag == 'patternFill') {
                        fill.type = attrs.patternType;
                    } else if (tag == 'fgColor' && fill.type === 'solid') {
                        fill.color = getColor(attrs);
                    } else if (tag == 'bgColor' && fill.type !== 'solid') {
                        fill.color = getColor(attrs);
                    }
                } else if (this.is(SEL_BORDER)) {
                    styles.borders.push(border = {});
                } else if (border) {
                    if (/^(?:left|top|right|bottom)$/.test(tag)) {
                        border[tag] = { style: attrs.style || 'none' };
                    }
                    if (tag == 'color') {
                        var side = this.stack[this.stack.length - 2].$tag;
                        border[side].color = getColor(attrs);
                    }
                } else if (this.is(SEL_NAMED_STYLE)) {
                    xf = getXf(attrs);
                    styles.namedStyles.push(xf);
                    if (closed) {
                        xf = null;
                    }
                } else if (this.is(SEL_INLINE_STYLE)) {
                    xf = getXf(attrs);
                    styles.inlineStyles.push(xf);
                    if (closed) {
                        xf = null;
                    }
                } else if (xf) {
                    if (tag == 'alignment') {
                        if (/^(?:left|center|right|justify)$/.test(attrs.horizontal)) {
                            xf.textAlign = attrs.horizontal;
                        }
                        if (/^(?:top|center|bottom)$/.test(attrs.vertical)) {
                            xf.verticalAlign = attrs.vertical;
                        }
                        if (attrs.wrapText != null) {
                            xf.wrapText = bool(attrs.wrapText);
                        }
                        if (attrs.indent != null) {
                            xf.indent = integer(attrs.indent);
                        }
                    }
                }
            },
            leave: function (tag) {
                if (this.is(SEL_FONT)) {
                    font = null;
                } else if (this.is(SEL_FILL)) {
                    fill = null;
                } else if (this.is(SEL_BORDER)) {
                    border = null;
                } else if (tag == 'xf') {
                    xf = null;
                }
            }
        });
        function getXf(attrs) {
            var xf = {
                borderId: integer(attrs.borderId),
                fillId: integer(attrs.fillId),
                fontId: integer(attrs.fontId),
                numFmtId: integer(attrs.numFmtId),
                pivotButton: bool(attrs.pivotButton),
                quotePrefix: bool(attrs.quotePrefix),
                xfId: integer(attrs.xfId)
            };
            addBool('applyAlignment');
            addBool('applyBorder');
            addBool('applyFill');
            addBool('applyFont');
            addBool('applyNumberFormat');
            addBool('applyProtection');
            function addBool(name) {
                if (attrs[name] != null) {
                    xf[name] = bool(attrs[name]);
                }
            }
            return xf;
        }
        function getColor(attrs) {
            if (attrs.rgb) {
                return toCSSColor(attrs.rgb);
            } else if (attrs.indexed) {
                return INDEXED_COLORS[integer(attrs.indexed)];
            } else if (attrs.theme) {
                var themeColor = theme.colorScheme[integer(attrs.theme)];
                if (!themeColor) {
                    return INDEXED_COLORS[0];
                }
                var color = kendo.parseColor(themeColor);
                if (attrs.tint) {
                    color = color.toHSL();
                    var tint = parseFloat(attrs.tint);
                    if (tint < 0) {
                        color.l = color.l * (1 + tint);
                    } else {
                        color.l = color.l * (1 - tint) + (100 - 100 * (1 - tint));
                    }
                }
                return color.toCssRgba();
            }
        }
        return styles;
    }
    var SEL_SCHEME_RGBCLR = [
        'a:clrScheme',
        '*',
        'a:srgbClr'
    ];
    var SEL_SCHEME_SYSCLR = [
        'a:clrScheme',
        '*',
        'a:sysClr'
    ];
    function readTheme(zip, rel) {
        var scheme = [];
        var theme = { colorScheme: scheme };
        var file = xl(rel);
        if (zip.files[file]) {
            parse(zip, file, {
                enter: function (tag, attrs) {
                    if (this.is(SEL_SCHEME_SYSCLR)) {
                        scheme.push(toCSSColor(attrs.val == 'window' ? 'FFFFFFFF' : 'FF000000'));
                    } else if (this.is(SEL_SCHEME_RGBCLR)) {
                        scheme.push(toCSSColor('FF' + attrs.val));
                    }
                }
            });
            if (scheme.length > 3) {
                swap(scheme, 0, 1);
                swap(scheme, 2, 3);
            }
        }
        function swap(arr, a, b) {
            var tmp = arr[a];
            arr[a] = arr[b];
            arr[b] = tmp;
        }
        return theme;
    }
    function integer(val) {
        return val == null ? null : parseInt(val, 10);
    }
    function bool(val, def) {
        if (val == null) {
            return def;
        }
        return val == 'true' || val === true || val == 1;
    }
    function toCSSColor(rgb) {
        var m = /^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(rgb);
        return 'rgba(' + parseInt(m[2], 16) + ', ' + parseInt(m[3], 16) + ', ' + parseInt(m[4], 16) + ', ' + parseInt(m[1], 16) / 255 + ')';
    }
    function relative_file(base, name) {
        base = base.split(/\/+/);
        name = name.split(/\/+/);
        base.pop();
        while (name.length) {
            var part = name.shift();
            if (part === '') {
                base = [];
            } else if (part === '.') {
                continue;
            } else if (part === '..') {
                base.pop();
            } else {
                base.push(part);
            }
        }
        return base.join('/');
    }
    function excelToPixels(val) {
        return val / 9525;
    }
    kendo.spreadsheet.readExcel = readExcel;
    kendo.spreadsheet._readSheet = readSheet;
    kendo.spreadsheet._readStrings = readStrings;
    kendo.spreadsheet._readStyles = readStyles;
    kendo.spreadsheet._readTheme = readTheme;
    kendo.spreadsheet._readWorkbook = readWorkbook;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/workbook', [
        'kendo.core',
        'spreadsheet/runtime',
        'spreadsheet/references',
        'spreadsheet/excel-reader'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var Formula = kendo.spreadsheet.calc.runtime.Formula;
        var Ref = kendo.spreadsheet.Ref;
        var CalcError = kendo.spreadsheet.CalcError;
        kendo.spreadsheet.messages.workbook = { defaultSheetName: 'Sheet' };
        function loadBinary(url, callback) {
            var xhr = new XMLHttpRequest();
            xhr.onload = function () {
                callback(xhr.response, xhr.getResponseHeader('Content-Type'));
            };
            xhr.onerror = function () {
                callback(null);
            };
            xhr.open('GET', url);
            xhr.responseType = 'arraybuffer';
            xhr.send();
        }
        var Workbook = kendo.Observable.extend({
            options: {},
            init: function (options, view) {
                kendo.Observable.fn.init.call(this);
                this.options = options;
                this._view = view;
                this._sheets = [];
                this._images = {};
                this._imgID = 0;
                this._sheetsSearchCache = {};
                this._sheet = this.insertSheet({
                    rows: this.options.rows,
                    columns: this.options.columns,
                    rowHeight: this.options.rowHeight,
                    columnWidth: this.options.columnWidth,
                    headerHeight: this.options.headerHeight,
                    headerWidth: this.options.headerWidth,
                    dataSource: this.options.dataSource
                });
                this.undoRedoStack = new kendo.util.UndoRedoStack();
                this.undoRedoStack.bind([
                    'undo',
                    'redo'
                ], this._onUndoRedo.bind(this));
                this._context = new kendo.spreadsheet.FormulaContext(this);
                this._validationContext = new kendo.spreadsheet.ValidationFormulaContext(this);
                this._names = Object.create(null);
                this.fromJSON(this.options);
            },
            clipboard: function () {
                if (!this._clipboard) {
                    this._clipboard = new kendo.spreadsheet.Clipboard(this);
                }
                return this._clipboard;
            },
            destroy: function () {
                this.unbind();
                if (this._clipboard) {
                    this._clipboard.destroy();
                }
            },
            events: [
                'cut',
                'copy',
                'paste',
                'changing',
                'change',
                'excelImport',
                'excelExport',
                'insertSheet',
                'removeSheet',
                'selectSheet',
                'renameSheet',
                'insertRow',
                'insertColumn',
                'deleteRow',
                'deleteColumn',
                'hideRow',
                'hideColumn',
                'unhideRow',
                'unhideColumn',
                'select',
                'changeFormat',
                'dataBinding',
                'dataBound'
            ],
            _sheetChanging: function (e) {
                if (this.trigger('changing', e)) {
                    e.preventDefault();
                }
            },
            _sheetChange: function (e) {
                this.trigger('change', e);
            },
            _sheetInsertRow: function (e) {
                if (this.trigger('insertRow', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetInsertColumn: function (e) {
                if (this.trigger('insertColumn', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetDeleteRow: function (e) {
                if (this.trigger('deleteRow', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetDeleteColumn: function (e) {
                if (this.trigger('deleteColumn', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetHideRow: function (e) {
                if (this.trigger('hideRow', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetHideColumn: function (e) {
                if (this.trigger('hideColumn', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetUnhideRow: function (e) {
                if (this.trigger('unhideRow', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetUnhideColumn: function (e) {
                if (this.trigger('unhideColumn', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetSelect: function (e) {
                this.trigger('select', e);
            },
            _sheetDataBinding: function (e) {
                if (this.trigger('dataBinding', { sheet: e.sender })) {
                    e.preventDefault();
                }
            },
            _sheetDataBound: function (e) {
                this.trigger('dataBound', { sheet: e.sender });
            },
            _sheetCommandRequest: function (e) {
                this.trigger('commandRequest', e);
            },
            _inputForRef: function (ref) {
                var self = this;
                return self._sheet.withCultureDecimals(function () {
                    return new kendo.spreadsheet.Range(ref, self._sheet).input();
                });
            },
            _onUndoRedo: function (e) {
                e.command.range().select();
            },
            execute: function (options) {
                var commandOptions = $.extend({ workbook: this }, options.options);
                var command = new kendo.spreadsheet[options.command](commandOptions);
                var sheet = this.activeSheet();
                if (commandOptions.origin) {
                    command.origin(commandOptions.origin);
                }
                if (commandOptions.operatingRange) {
                    command.range(commandOptions.operatingRange);
                } else {
                    command.range(sheet.selection());
                }
                var result = command.exec();
                if (!result || result.reason !== 'error') {
                    if (command.cannotUndo) {
                        this.undoRedoStack.clear();
                    } else {
                        this.undoRedoStack.push(command);
                    }
                }
                this.cleanupImages();
                return result;
            },
            resetFormulas: function () {
                this._sheets.forEach(function (sheet) {
                    sheet.resetFormulas();
                });
            },
            resetValidations: function () {
                this._sheets.forEach(function (sheet) {
                    sheet.resetValidations();
                });
            },
            refresh: function (reason) {
                if (reason.recalc) {
                    this.resetFormulas();
                    this.resetValidations();
                    this._sheet.recalc(this._context);
                    this._sheet.revalidate(this._validationContext);
                }
            },
            activeSheet: function (sheet) {
                if (sheet === undefined) {
                    return this._sheet;
                }
                if (!this.sheetByName(sheet.name())) {
                    return;
                }
                this._sheet = sheet;
                sheet.triggerChange(kendo.spreadsheet.ALL_REASONS);
            },
            moveSheetToIndex: function (sheet, toIndex) {
                var fromIndex = this.sheetIndex(sheet);
                var sheets = this._sheets;
                if (fromIndex === -1) {
                    return;
                }
                this._sheetsSearchCache = {};
                sheets.splice(toIndex, 0, sheets.splice(fromIndex, 1)[0]);
                this.trigger('change', { sheetSelection: true });
            },
            insertSheet: function (options) {
                options = options || {};
                var that = this;
                var insertIndex = typeof options.index === 'number' ? options.index : that._sheets.length;
                var sheetName;
                var sheets = that._sheets;
                var getUniqueSheetName = function (sheetNameSuffix) {
                    sheetNameSuffix = sheetNameSuffix ? sheetNameSuffix : 1;
                    var name = kendo.spreadsheet.messages.workbook.defaultSheetName + sheetNameSuffix;
                    if (!that.sheetByName(name)) {
                        return name;
                    }
                    return getUniqueSheetName(sheetNameSuffix + 1);
                };
                if (options.name && that.sheetByName(options.name)) {
                    return;
                }
                this._sheetsSearchCache = {};
                sheetName = options.name || getUniqueSheetName();
                var sheet = new kendo.spreadsheet.Sheet(options.rows || this.options.rows, options.columns || this.options.columns, options.rowHeight || this.options.rowHeight, options.columnWidth || this.options.columnWidth, options.headerHeight || this.options.headerHeight, options.headerWidth || this.options.headerWidth, options.defaultCellStyle || this.options.defaultCellStyle);
                sheet._workbook = this;
                sheet._name(sheetName);
                this._bindSheetEvents(sheet);
                sheets.splice(insertIndex, 0, sheet);
                if (options.data) {
                    sheet.fromJSON(options.data);
                }
                if (options.dataSource) {
                    sheet.setDataSource(options.dataSource);
                }
                this.trigger('change', { sheetSelection: true });
                return sheet;
            },
            _bindSheetEvents: function (sheet) {
                sheet.bind('changing', this._sheetChanging.bind(this));
                sheet.bind('change', this._sheetChange.bind(this));
                sheet.bind('insertRow', this._sheetInsertRow.bind(this));
                sheet.bind('insertColumn', this._sheetInsertColumn.bind(this));
                sheet.bind('deleteRow', this._sheetDeleteRow.bind(this));
                sheet.bind('deleteColumn', this._sheetDeleteColumn.bind(this));
                sheet.bind('hideRow', this._sheetHideRow.bind(this));
                sheet.bind('hideColumn', this._sheetHideColumn.bind(this));
                sheet.bind('unhideRow', this._sheetUnhideRow.bind(this));
                sheet.bind('unhideColumn', this._sheetUnhideColumn.bind(this));
                sheet.bind('select', this._sheetSelect.bind(this));
                sheet.bind('commandRequest', this._sheetCommandRequest.bind(this));
                sheet.bind('dataBinding', this._sheetDataBinding.bind(this));
                sheet.bind('dataBound', this._sheetDataBound.bind(this));
            },
            sheets: function () {
                return this._sheets.slice();
            },
            sheetByName: function (sheetName) {
                return this._sheets[this.sheetIndex(sheetName)];
            },
            sheetByIndex: function (index) {
                return this._sheets[index];
            },
            sheetIndex: function (sheet) {
                var sheets = this._sheets;
                var sheetName = (typeof sheet == 'string' ? sheet : sheet.name()).toLowerCase();
                var idx = this._sheetsSearchCache[sheetName];
                if (idx >= 0) {
                    return idx;
                }
                for (idx = 0; idx < sheets.length; idx++) {
                    var name = sheets[idx].name().toLowerCase();
                    this._sheetsSearchCache[name] = idx;
                    if (name === sheetName) {
                        return idx;
                    }
                }
                return -1;
            },
            renameSheet: function (sheet, newSheetName) {
                var oldSheetName = sheet.name().toLowerCase();
                if (!newSheetName || oldSheetName === newSheetName.toLowerCase() || this.sheetByName(newSheetName)) {
                    return;
                }
                sheet = this.sheetByName(oldSheetName);
                if (!sheet) {
                    return;
                }
                this._sheetsSearchCache = {};
                if (this.trigger('renameSheet', {
                        sheet: sheet,
                        newSheetName: newSheetName
                    })) {
                    return;
                }
                this._sheets.forEach(function (sheet) {
                    sheet._forFormulas(function (formula) {
                        formula.renameSheet(oldSheetName, newSheetName);
                    });
                });
                this.forEachName(function (def, name) {
                    if (def.nameref.renameSheet(oldSheetName, newSheetName)) {
                        this.undefineName(name);
                        def.name = def.nameref.print();
                        this.nameDefinition(def.name, def);
                    }
                    if (def.value instanceof Ref || def.value instanceof Formula) {
                        def.value.renameSheet(oldSheetName, newSheetName);
                    }
                }.bind(this));
                sheet._name(newSheetName);
                this.trigger('change', { sheetSelection: true });
                return sheet;
            },
            removeSheet: function (sheet) {
                var that = this;
                var sheets = that._sheets;
                var name = sheet.name();
                var index = that.sheetIndex(sheet);
                if (sheets.length === 1) {
                    return;
                }
                if (this.trigger('removeSheet', { sheet: sheet })) {
                    return;
                }
                this._sheetsSearchCache = {};
                if (index > -1) {
                    sheet.unbind();
                    sheets.splice(index, 1);
                    if (that.activeSheet().name() === name) {
                        var newSheet = sheets[index === sheets.length ? index - 1 : index];
                        that.activeSheet(newSheet);
                    } else {
                        this.trigger('change', {
                            recalc: true,
                            sheetSelection: true
                        });
                    }
                }
            },
            _clearSheets: function () {
                for (var i = 0; i < this._sheets.length; i++) {
                    this._sheets[i]._activeDrawing = [];
                    this._sheets[i]._drawings = [];
                    this._sheets[i].unbind();
                }
                this._sheets = [];
                this._sheetsSearchCache = {};
                this._names = {};
                this._images = {};
                this._imgID = 0;
            },
            fromJSON: function (json) {
                if (json.sheets) {
                    this._clearSheets();
                    if (json.images) {
                        this._imgID = 0;
                        this._images = {};
                        Object.keys(json.images).forEach(function (id) {
                            if (!isNaN(id)) {
                                var num = parseFloat(id);
                                if (isFinite(num)) {
                                    this._imgID = Math.max(this._imgID, num);
                                }
                            }
                            this._images[id] = { url: json.images[id] };
                        }, this);
                    }
                    for (var idx = 0; idx < json.sheets.length; idx++) {
                        var data = json.sheets[idx];
                        var args = sheetParamsFromJSON(data, this.options);
                        var sheet = this.insertSheet({
                            rows: args.rowCount,
                            columns: args.columnCount,
                            rowHeight: args.rowHeight,
                            columnWidth: args.columnWidth,
                            headerHeight: args.headerHeight,
                            headerWidth: args.headerWidth,
                            data: data
                        });
                        if (data.dataSource) {
                            sheet.setDataSource(data.dataSource);
                        }
                    }
                }
                if (json.activeSheet) {
                    this.activeSheet(this.sheetByName(json.activeSheet));
                } else {
                    this.activeSheet(this._sheets[0]);
                }
                if (json.names) {
                    json.names.forEach(function (def) {
                        this.defineName(def.name, def.value, def.hidden);
                    }, this);
                }
            },
            toJSON: function () {
                this.resetFormulas();
                this.resetValidations();
                var names = Object.keys(this._names).map(function (name) {
                    var def = this._names[name];
                    var val = def.value;
                    if (val instanceof Ref || val instanceof Formula) {
                        val = val.print(0, 0, true);
                    } else if (val instanceof CalcError) {
                        val = val + '';
                    } else {
                        val = JSON.stringify(val);
                    }
                    return {
                        value: val,
                        hidden: def.hidden,
                        name: def.name,
                        sheet: def.nameref.sheet,
                        localName: def.nameref.name
                    };
                }, this);
                return {
                    activeSheet: this.activeSheet().name(),
                    sheets: this._sheets.map(function (sheet) {
                        sheet.recalc(this._context);
                        sheet.revalidate(this._validationContext);
                        return sheet.toJSON();
                    }, this),
                    names: names,
                    columnWidth: this.options.columnWidth,
                    rowHeight: this.options.rowHeight
                };
            },
            saveJSON: function () {
                var self = this;
                var deferred = new $.Deferred();
                var data = self.toJSON();
                var ids = Object.keys(self._images).filter(function (id) {
                    return self.usesImage(id) === 1;
                });
                var count = ids.length;
                data.images = {};
                if (count) {
                    ids.forEach(function (id) {
                        var img = self._images[id];
                        if (img.blob) {
                            var reader = new FileReader();
                            reader.onload = function () {
                                data.images[id] = reader.result;
                                next();
                            };
                            reader.readAsDataURL(img.blob);
                        } else {
                            data.images[id] = img.url;
                            next();
                        }
                    });
                } else {
                    next();
                }
                return deferred.promise();
                function next() {
                    if (--count <= 0) {
                        deferred.resolve(data);
                    }
                }
            },
            fromFile: function (file) {
                var deferred = new $.Deferred();
                var promise = deferred.promise();
                var args = {
                    file: file,
                    promise: promise
                };
                if (file && !this.trigger('excelImport', args)) {
                    this._clearSheets();
                    kendo.spreadsheet.readExcel(file, this, deferred);
                } else {
                    deferred.reject();
                }
                return promise;
            },
            saveAsExcel: function (options) {
                var self = this;
                options = $.extend({}, self.options.excel, options);
                var data = self.toJSON();
                if (self.trigger('excelExport', { workbook: data })) {
                    return;
                }
                var ids = Object.keys(self._images).filter(function (id) {
                    return self.usesImage(id) === 1;
                });
                var count = ids.length;
                var images = count ? {} : null;
                if (count) {
                    ids.forEach(function (id) {
                        var img = self._images[id];
                        if (img.blob) {
                            var reader = new FileReader();
                            reader.onload = function () {
                                images[id] = {
                                    type: img.blob.type,
                                    name: img.blob.name,
                                    data: reader.result
                                };
                                next();
                            };
                            reader.readAsArrayBuffer(img.blob);
                        } else {
                            loadBinary(img.url, function (data, type) {
                                images[id] = {
                                    type: type,
                                    data: data
                                };
                                next();
                            });
                        }
                    });
                } else {
                    next();
                }
                function next() {
                    if (--count <= 0) {
                        data.images = images;
                        var workbook = new kendo.ooxml.Workbook(data);
                        kendo.saveAs({
                            dataURI: options.forceProxy ? workbook.toDataURL() : workbook.toBlob(),
                            fileName: data.fileName || options.fileName,
                            proxyURL: options.proxyURL,
                            forceProxy: options.forceProxy
                        });
                    }
                }
            },
            draw: function (options, callback) {
                if (typeof options == 'function' && !callback) {
                    callback = options;
                    options = {};
                }
                var parts = [], sheets = this._sheets;
                (function loop(i) {
                    if (i < sheets.length) {
                        sheets[i].draw(kendo.spreadsheet.SHEETREF, options, function (group) {
                            parts.push(group);
                            loop(i + 1);
                        });
                    } else {
                        var group = parts[0];
                        for (i = 1; i < parts.length; ++i) {
                            group.children = group.children.concat(parts[i].children);
                        }
                        callback(group);
                    }
                }(0));
            },
            nameForRef: function (ref, sheet) {
                if (sheet === undefined) {
                    sheet = ref.sheet;
                }
                sheet = sheet.toLowerCase();
                var str = ref + '';
                for (var name in this._names) {
                    var def = this._names[name];
                    var val = def.value;
                    if (val instanceof Ref) {
                        if (!val.sheet || val.sheet && sheet == val.sheet.toLowerCase()) {
                            if (val + '' == str) {
                                return def;
                            }
                        }
                    }
                }
                return { name: str };
            },
            defineName: function (name, value, hidden) {
                var x = kendo.spreadsheet.calc.parseNameDefinition(name, value);
                name = x.name.print();
                this._names[name.toLowerCase()] = {
                    value: x.value,
                    hidden: hidden,
                    name: name,
                    nameref: x.name
                };
            },
            undefineName: function (name) {
                delete this._names[name.toLowerCase()];
            },
            nameValue: function (name) {
                name = name.toLowerCase();
                if (name in this._names) {
                    return this._names[name].value;
                }
                return null;
            },
            nameDefinition: function (name, def) {
                name = name.toLowerCase();
                if (arguments.length > 1) {
                    if (def === undefined) {
                        delete this._names[name];
                    } else {
                        this._names[name] = def;
                    }
                }
                return this._names[name];
            },
            forEachName: function (func) {
                Object.keys(this._names).forEach(function (name) {
                    func(this._names[name], name);
                }, this);
            },
            adjustNames: function (affectedSheet, forRow, start, delta) {
                affectedSheet = affectedSheet.toLowerCase();
                Object.keys(this._names).forEach(function (name) {
                    var def = this._names[name];
                    var x = def.value;
                    if (x instanceof Ref && x.sheet.toLowerCase() == affectedSheet) {
                        def.value = x.adjust(null, null, null, null, forRow, start, delta);
                    } else if (x instanceof Formula) {
                        x.adjust(affectedSheet, forRow ? 'row' : 'col', start, delta);
                    }
                }, this);
            },
            addImage: function (image) {
                var id = String(++this._imgID);
                if (typeof image == 'string') {
                    this._images[id] = { url: image };
                } else {
                    this._images[id] = { blob: image };
                }
                return id;
            },
            imageUrl: function (id) {
                var img = this._images[id];
                var url = img.url;
                if (!url) {
                    url = img.url = window.URL.createObjectURL(img.blob);
                }
                return url;
            },
            cleanupImages: function () {
                Object.keys(this._images).forEach(function (id) {
                    if (!this.usesImage(id)) {
                        var url = this._images[id].url;
                        if (url) {
                            window.URL.revokeObjectURL(url);
                        }
                        delete this._images[id];
                    }
                }, this);
            },
            usesImage: function (img) {
                var i;
                var sheets = this._sheets;
                for (i = sheets.length; --i >= 0;) {
                    if (sheets[i].usesImage(img)) {
                        return 1;
                    }
                }
                var stack = this.undoRedoStack.stack;
                for (i = stack.length; --i >= 0;) {
                    if (stack[i].usesImage(img)) {
                        return 2;
                    }
                }
                return false;
            }
        });
        function sheetParamsFromJSON(data, options) {
            function or(a, b, c) {
                return a !== undefined ? a : b !== undefined ? b : c;
            }
            var rowCount = or(data.rowCount, options.rows, 200), columnCount = or(data.columnCount, options.columns, 50), rowHeight = or(data.rowHeight, options.rowHeight, 20), columnWidth = or(data.columnWidth, options.columnWidth, 64), headerHeight = or(data.headerHeight, options.headerHeight, 20), headerWidth = or(data.headerWidth, options.headerWidth, 32);
            if (data.rows !== undefined) {
                for (var i = 0; i < data.rows.length; ++i) {
                    var row = data.rows[i];
                    var ri = or(row.index, i);
                    if (ri >= rowCount) {
                        rowCount = ri + 1;
                    }
                    if (row.cells) {
                        for (var j = 0; j < row.cells.length; ++j) {
                            var cell = row.cells[j];
                            var ci = or(cell.index, j);
                            if (ci >= columnCount) {
                                columnCount = ci + 1;
                            }
                        }
                    }
                }
            }
            return {
                rowCount: rowCount,
                columnCount: columnCount,
                rowHeight: rowHeight,
                columnWidth: columnWidth,
                headerHeight: headerHeight,
                headerWidth: headerWidth
            };
        }
        kendo.spreadsheet.Workbook = Workbook;
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(Workbook.prototype);
            Workbook.prototype.saveAsPDF = function (options) {
                var progress = new $.Deferred();
                var promise = progress.promise();
                var args = { promise: promise };
                if (this.trigger('pdfExport', args)) {
                    return;
                }
                this._drawPDF(options, progress).then(function (root) {
                    return options.forceProxy ? kendo.pdf.exportPDF(root) : kendo.pdf.exportPDFToBlob(root);
                }).done(function (dataURI) {
                    kendo.saveAs({
                        dataURI: dataURI,
                        fileName: options.fileName,
                        proxyURL: options.proxyURL,
                        forceProxy: options.forceProxy,
                        proxyTarget: options.proxyTarget
                    });
                    progress.resolve();
                }).fail(function (err) {
                    progress.reject(err);
                });
                return promise;
            };
            Workbook.prototype._drawPDF = function (options) {
                var result = new $.Deferred();
                var callback = function (group) {
                    result.resolve(group);
                };
                switch (options.area) {
                case 'workbook':
                    options.workbook.draw(options, callback);
                    break;
                case 'sheet':
                    options.workbook.activeSheet().draw(options, callback);
                    break;
                case 'selection':
                    options.workbook.activeSheet().selection().draw(options, callback);
                    break;
                }
                return result.promise();
            };
        }
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/formulacontext', ['kendo.core'], f);
}(function () {
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var spreadsheet = kendo.spreadsheet;
    var CellRef = spreadsheet.CellRef;
    var RangeRef = spreadsheet.RangeRef;
    var UnionRef = spreadsheet.UnionRef;
    var NameRef = spreadsheet.NameRef;
    var Ref = spreadsheet.Ref;
    var FormulaContext = kendo.Class.extend({
        init: function (workbook) {
            this.workbook = workbook;
        },
        getRefCells: function (ref, hiddenInfo, fsheet, frow, fcol, wantNulls) {
            var sheet, formula, value, i;
            if (ref instanceof CellRef) {
                sheet = this.workbook.sheetByName(ref.sheet);
                if (!sheet || !ref.valid()) {
                    return [{ value: new kendo.spreadsheet.calc.runtime.CalcError('REF') }];
                }
                formula = sheet.formula(ref);
                value = sheet.range(ref.row, ref.col).value();
                if (wantNulls || formula != null || value != null) {
                    return [{
                            formula: formula,
                            value: value,
                            row: ref.row,
                            col: ref.col,
                            sheet: ref.sheet,
                            hidden: hiddenInfo ? sheet.columnWidth(ref.col) === 0 || sheet.rowHeight(ref.row) === 0 : false
                        }];
                } else {
                    return [];
                }
            }
            if (ref instanceof RangeRef) {
                i = this.workbook.sheetIndex(ref.sheet);
                var states = [], n = i;
                if (ref.endSheet) {
                    n = this.workbook.sheetIndex(ref.endSheet);
                    if (i > n) {
                        var tmp = i;
                        i = n;
                        n = tmp;
                    }
                }
                if (i < 0 || n < 0 || !ref.valid()) {
                    return [{ value: new kendo.spreadsheet.calc.runtime.CalcError('REF') }];
                }
                while (i <= n) {
                    sheet = this.workbook.sheetByIndex(i++);
                    var tl = sheet._grid.normalize(ref.topLeft);
                    var br = sheet._grid.normalize(ref.bottomRight);
                    var startCellIndex = sheet._grid.cellRefIndex(tl);
                    var endCellIndex = sheet._grid.cellRefIndex(br);
                    var values = sheet._properties.iterator('value', startCellIndex, endCellIndex);
                    for (var col = tl.col; col <= br.col; ++col) {
                        for (var row = tl.row; row <= br.row; ++row) {
                            var index = sheet._grid.index(row, col);
                            formula = sheet._properties.get('formula', index);
                            value = values.at(index);
                            if (wantNulls || formula != null || value != null) {
                                states.push({
                                    formula: formula,
                                    value: value,
                                    row: row,
                                    col: col,
                                    sheet: sheet.name(),
                                    hidden: hiddenInfo ? sheet.columnWidth(col) === 0 || sheet.rowHeight(row) === 0 : false
                                });
                            }
                        }
                    }
                }
                return states;
            }
            if (ref instanceof UnionRef) {
                var a = [];
                for (i = 0; i < ref.refs.length; ++i) {
                    a = a.concat(this.getRefCells(ref.refs[i], hiddenInfo, fsheet, frow, fcol));
                }
                return a;
            }
            if (ref instanceof NameRef) {
                var val = this.nameValue(ref, fsheet, frow, fcol);
                if (val instanceof Ref) {
                    return this.getRefCells(val, hiddenInfo, fsheet, frow, fcol);
                }
                return [{ value: val == null ? new kendo.spreadsheet.calc.runtime.CalcError('NAME') : val }];
            }
            return [];
        },
        nameValue: function (ref, fsheet, frow, fcol) {
            var val;
            if (ref.hasSheet()) {
                val = this.workbook.nameValue(ref.print());
            } else {
                ref = ref.clone().setSheet(fsheet, true);
                val = this.workbook.nameValue(ref.print());
                if (val == null) {
                    val = this.workbook.nameValue(ref.name);
                }
            }
            if (val instanceof Ref) {
                val = val.absolute(frow, fcol);
            }
            return val;
        },
        getData: function (ref, fsheet, frow, fcol, wantNulls) {
            var single = ref instanceof CellRef;
            if (ref instanceof NameRef) {
                single = this.workbook.nameValue(ref.name) instanceof CellRef;
            }
            var data = this.getRefCells(ref, false, fsheet, frow, fcol, wantNulls).map(function (cell) {
                var val = cell.value;
                if (val instanceof kendo.spreadsheet.calc.runtime.Formula) {
                    val = val.value;
                }
                return val;
            });
            return single ? data[0] : data;
        },
        onFormula: function (f) {
            var sheet = this.workbook.sheetByName(f.sheet);
            var row = f.row, col = f.col, value = f.value;
            var currentFormula = sheet.formula({
                row: row,
                col: col
            });
            if (currentFormula !== f) {
                return false;
            }
            var arrayRange = f.arrayFormulaRange;
            if (arrayRange) {
                var tlRow, tlCol;
                var width = value.width;
                var height = value.height;
                sheet.forEach(arrayRange, function (row, col) {
                    if (tlRow === undefined) {
                        tlRow = row;
                        tlCol = col;
                    }
                    var vrow = row - tlRow;
                    var vcol = col - tlCol;
                    var val;
                    if (vrow < height && vcol < width) {
                        val = value.get(vrow, vcol);
                    } else {
                        val = new kendo.spreadsheet.calc.runtime.CalcError('N/A');
                    }
                    sheet._value(row, col, val);
                });
            } else {
                if (value instanceof Ref) {
                    value = this.getData(value, f.sheet, row, col);
                    if (Array.isArray(value)) {
                        value = value[0];
                    }
                    if (value === undefined) {
                        value = null;
                    }
                }
                if (value instanceof kendo.spreadsheet.calc.runtime.Matrix) {
                    value = value.get(0, 0);
                }
                sheet._value(row, col, value);
            }
            clearTimeout(sheet._formulaContextRefresh);
            sheet._formulaContextRefresh = setTimeout(function () {
                sheet.batch(function () {
                }, { layout: true });
            }, 50);
            return true;
        }
    });
    var ValidationFormulaContext = FormulaContext.extend({
        onFormula: function () {
            return true;
        }
    });
    spreadsheet.FormulaContext = FormulaContext;
    spreadsheet.ValidationFormulaContext = ValidationFormulaContext;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/controller', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        'use strict';
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var alphaNumRegExp = /:alphanum$/;
        var ACTIONS = {
            'up': 'up',
            'down': 'down',
            'left': 'left',
            'right': 'right',
            'home': 'first-col',
            'ctrl+left': 'first-col',
            'end': 'last-col',
            'ctrl+right': 'last-col',
            'ctrl+up': 'first-row',
            'ctrl+down': 'last-row',
            'ctrl+home': 'first',
            'ctrl+end': 'last',
            'pageup': 'prev-page',
            'pagedown': 'next-page'
        };
        var ENTRY_ACTIONS = {
            'tab': 'next',
            'shift+tab': 'previous',
            'enter': 'lower',
            'shift+enter': 'upper',
            'delete': 'clearContents',
            'backspace': 'clearContents',
            'shift+:alphanum': 'edit',
            'alt+:alphanum': 'edit',
            ':alphanum': 'edit',
            'ctrl+:alphanum': 'ctrl',
            'alt+ctrl+:alphanum': 'edit',
            ':edit': 'edit'
        };
        var CONTAINER_EVENTS = {
            'wheel': 'onWheel',
            '*+mousedown': 'onMouseDown',
            'contextmenu': 'onContextMenu',
            '*+mousedrag': 'onMouseDrag',
            '*+mouseup': 'onMouseUp',
            '*+dblclick': 'onDblClick',
            'mousemove': 'onMouseMove',
            'touchmove': 'onTouchMove',
            'touchend': 'onTouchEnd'
        };
        var CLIPBOARD_EVENTS = {
            'pageup': 'onPageUp',
            'pagedown': 'onPageDown',
            'mouseup': 'onMouseUp',
            '*+cut': 'onCut',
            '*+paste': 'onPaste',
            '*+copy': 'onCopy'
        };
        var EDITOR_EVENTS = {
            'esc': 'onEditorEsc',
            'enter': 'onEditorBlur',
            'alt+enter': 'insertNewline',
            'shift+enter': 'onEditorBlur',
            'tab': 'onEditorBlur',
            'shift+tab': 'onEditorBlur',
            'shift+ctrl+enter': 'onEditorArrayFormula'
        };
        var FORMULABAR_EVENTS = $.extend({ focus: 'onEditorBarFocus' }, EDITOR_EVENTS);
        var FORMULAINPUT_EVENTS = $.extend({ focus: 'onEditorCellFocus' }, EDITOR_EVENTS);
        var SELECTION_MODES = {
            cell: 'range',
            rowheader: 'row',
            columnheader: 'column',
            topcorner: 'sheet',
            autofill: 'autofill'
        };
        function toActionSelector(selectors) {
            return selectors.map(function (action) {
                return '[data-action="' + action + '"]';
            }).join(',');
        }
        var COMPOSITE_UNAVAILABLE_ACTION_SELECTORS = toActionSelector([
            'cut',
            'copy',
            'paste',
            'insert-left',
            'insert-right',
            'insert-above',
            'insert-below'
        ]);
        var UNHIDE_ACTION_SELECTORS = toActionSelector([
            'unhide-row',
            'unhide-column'
        ]);
        var ACTION_KEYS = [];
        var SHIFT_ACTION_KEYS = [];
        var ENTRY_ACTION_KEYS = [];
        for (var key in ACTIONS) {
            ACTION_KEYS.push(key);
            SHIFT_ACTION_KEYS.push('shift+' + key);
        }
        for (key in ENTRY_ACTIONS) {
            ENTRY_ACTION_KEYS.push(key);
        }
        CLIPBOARD_EVENTS[ACTION_KEYS] = 'onAction';
        CLIPBOARD_EVENTS[SHIFT_ACTION_KEYS] = 'onShiftAction';
        CLIPBOARD_EVENTS[ENTRY_ACTION_KEYS] = 'onEntryAction';
        FORMULAINPUT_EVENTS[ACTION_KEYS] = 'onEditorAction';
        FORMULAINPUT_EVENTS[SHIFT_ACTION_KEYS] = 'onEditorShiftAction';
        var Controller = kendo.Class.extend({
            init: function (view, workbook) {
                this.view = view;
                this.workbook(workbook);
                this.container = $(view.container);
                this.clipboardElement = $(view.clipboard);
                this.cellContextMenu = view.cellContextMenu;
                this.rowHeaderContextMenu = view.rowHeaderContextMenu;
                this.colHeaderContextMenu = view.colHeaderContextMenu;
                this.drawingContextMenu = view.drawingContextMenu;
                this.scroller = view.scroller;
                this.tabstrip = view.tabstrip;
                this.sheetsbar = view.sheetsbar;
                view.nameEditor.bind('enter', this.onNameEditorEnter.bind(this));
                view.nameEditor.bind('cancel', this.onNameEditorCancel.bind(this));
                view.nameEditor.bind('select', this.onNameEditorSelect.bind(this));
                view.nameEditor.bind('delete', this.onNameEditorDelete.bind(this));
                this.editor = view.editor;
                this.editor.bind('change', this.onEditorChange.bind(this));
                this.editor.bind('activate', this.onEditorActivate.bind(this));
                this.editor.bind('deactivate', this.onEditorDeactivate.bind(this));
                this.editor.bind('update', this.onEditorUpdate.bind(this));
                $(view.scroller).on('scroll', this.onScroll.bind(this));
                this.listener = new kendo.spreadsheet.EventListener(this.container, this, CONTAINER_EVENTS);
                this._enableEditorEvents();
                if (this.sheetsbar) {
                    this.sheetsbar.bind('select', this.onSheetBarSelect.bind(this));
                    this.sheetsbar.bind('reorder', this.onSheetBarReorder.bind(this));
                    this.sheetsbar.bind('rename', this.onSheetBarRename.bind(this));
                    this.sheetsbar.bind('remove', this.onSheetBarRemove.bind(this));
                }
                this.cellContextMenu.bind('select', this.onContextMenuSelect.bind(this));
                this.rowHeaderContextMenu.bind('select', this.onContextMenuSelect.bind(this));
                this.colHeaderContextMenu.bind('select', this.onContextMenuSelect.bind(this));
                this.drawingContextMenu.bind('select', this.onContextMenuSelect.bind(this));
                this.cellContextMenu.element.add(this.rowHeaderContextMenu.element).add(this.colHeaderContextMenu.element).add(this.drawingContextMenu.element).on('contextmenu', false);
                if (this.tabstrip) {
                    this.tabstrip.bind('action', this.onCommandRequest.bind(this));
                    this.tabstrip.bind('dialog', this.onDialogRequest.bind(this));
                }
            },
            _enableEditorEvents: function (enable) {
                if (enable === undefined || enable) {
                    this.keyListener = new kendo.spreadsheet.EventListener(this.clipboardElement, this, CLIPBOARD_EVENTS);
                    this.barKeyListener = new kendo.spreadsheet.EventListener(this.editor.barElement(), this, FORMULABAR_EVENTS);
                    this.inputKeyListener = new kendo.spreadsheet.EventListener(this.editor.cellElement(), this, FORMULAINPUT_EVENTS);
                } else {
                    this.keyListener.destroy();
                    this.barKeyListener.destroy();
                    this.inputKeyListener.destroy();
                }
            },
            _execute: function (options) {
                var result = this._workbook.execute(options);
                if (options.command === 'EditCommand' && !result) {
                    this._workbook.trigger('change', { editorClose: true });
                }
                if (result) {
                    this._preventNavigation = true;
                    if (result.reason === 'error') {
                        this.editor.deactivate(true);
                        this.view.showError(result, function () {
                            this.activateEditor(false);
                            this.editor.value(this._lastEditorValue);
                            this.editor._value = this._workbook._inputForRef(this._workbook.activeSheet()._viewActiveCell());
                            this.editor.select();
                        }.bind(this));
                    } else {
                        this.view.openDialog(result.reason);
                    }
                }
                return result;
            },
            _activeTooltip: function () {
                return this._workbook.activeSheet().activeCell().simplify().toString();
            },
            onContextMenuSelect: function (e) {
                var action = $(e.item).data('action');
                var command;
                switch (action) {
                case 'cut':
                    command = {
                        command: 'ToolbarCutCommand',
                        options: { workbook: this._workbook }
                    };
                    break;
                case 'copy':
                    command = {
                        command: 'ToolbarCopyCommand',
                        options: { workbook: this._workbook }
                    };
                    break;
                case 'paste':
                    command = {
                        command: 'ToolbarPasteCommand',
                        options: { workbook: this._workbook }
                    };
                    break;
                case 'delete-drawing':
                    command = {
                        command: 'DeleteDrawingCommand',
                        options: { drawing: this.navigator._sheet._activeDrawing }
                    };
                    break;
                case 'bring-to-front':
                    command = {
                        command: 'BringToFrontCommand',
                        options: { drawing: this.navigator._sheet._activeDrawing }
                    };
                    break;
                case 'send-to-back':
                    command = {
                        command: 'SendToBackCommand',
                        options: { drawing: this.navigator._sheet._activeDrawing }
                    };
                    break;
                case 'unmerge':
                    command = {
                        command: 'MergeCellCommand',
                        options: { value: 'unmerge' }
                    };
                    break;
                case 'merge':
                    this.view.openDialog('merge');
                    break;
                case 'hide-row':
                    command = {
                        command: 'HideLineCommand',
                        options: { axis: 'row' }
                    };
                    break;
                case 'hide-column':
                    command = {
                        command: 'HideLineCommand',
                        options: { axis: 'column' }
                    };
                    break;
                case 'unhide-row':
                    command = {
                        command: 'UnHideLineCommand',
                        options: { axis: 'row' }
                    };
                    break;
                case 'unhide-column':
                    command = {
                        command: 'UnHideLineCommand',
                        options: { axis: 'column' }
                    };
                    break;
                case 'delete-row':
                    command = { command: 'DeleteRowCommand' };
                    break;
                case 'delete-column':
                    command = { command: 'DeleteColumnCommand' };
                    break;
                }
                if (command) {
                    this._execute(command);
                }
            },
            onSheetBarRemove: function (e) {
                var sheet = this._workbook.sheetByName(e.name);
                if (!sheet) {
                    return;
                }
                this._workbook.removeSheet(sheet);
            },
            destroy: function () {
                this.listener.destroy();
                this._enableEditorEvents(false);
                this.keyListener.destroy();
                this.inputKeyListener.destroy();
            },
            onSheetBarSelect: function (e) {
                var sheet;
                var workbook = this._workbook;
                if (e.isAddButton) {
                    if (this._workbook.trigger('insertSheet')) {
                        return;
                    }
                    sheet = workbook.insertSheet();
                } else {
                    sheet = workbook.sheetByName(e.name);
                }
                if (workbook.activeSheet().name() !== sheet.name()) {
                    if (this._workbook.trigger('selectSheet', { sheet: sheet })) {
                        return;
                    }
                    if (!this.editor.canInsertRef(false)) {
                        this.editor.deactivate();
                    }
                    workbook.activeSheet(sheet);
                }
            },
            onSheetBarReorder: function (e) {
                var sheet = this._workbook.sheetByIndex(e.oldIndex);
                this._workbook.moveSheetToIndex(sheet, e.newIndex);
                this._workbook.activeSheet(sheet);
            },
            onSheetBarRename: function (e) {
                var sheet = this._workbook.sheetByIndex(e.sheetIndex);
                if (this._workbook.sheetByName(e.name)) {
                    this.view.showError({
                        reason: 'error',
                        type: 'duplicateSheetName'
                    });
                    return;
                }
                this._workbook.renameSheet(sheet, e.name);
                this.clipboardElement.focus();
            },
            sheet: function (sheet) {
                this.navigator = sheet.navigator();
                this.axisManager = sheet.axisManager();
            },
            workbook: function (workbook) {
                this._workbook = workbook;
                this.clipboard = workbook.clipboard();
                workbook.bind('commandRequest', this.onCommandRequest.bind(this));
            },
            refresh: function () {
                var editor = this.editor;
                var workbook = this._workbook;
                var sheet = workbook.activeSheet();
                this._viewPortHeight = this.view.scroller.clientHeight;
                this.navigator.height(this._viewPortHeight);
                if (!editor.isActive() && !this.isEditorDisabled) {
                    editor.enable(sheet.selection().enable() !== false);
                    this.resetEditorValue();
                }
                var ref = sheet.selection()._ref.simplify();
                var def = this._workbook.nameForRef(ref, sheet.name());
                this.view.nameEditor.value(def.name);
            },
            onScroll: function () {
                this.view.render({ scroll: true });
            },
            onWheel: function (event) {
                var deltaX = event.originalEvent.deltaX;
                var deltaY = event.originalEvent.deltaY;
                if (event.originalEvent.deltaMode === 1) {
                    deltaX *= 10;
                    deltaY *= 10;
                }
                this.scrollWith(deltaX, deltaY);
                event.preventDefault();
            },
            onTouchMove: function () {
                this.view.forceScrollerStackingOrder(2);
            },
            onTouchEnd: function () {
                this.view.forceScrollerStackingOrder(1);
            },
            onAction: function (event, action) {
                var sheet = this._workbook.activeSheet();
                sheet._activeDrawing = null;
                this.navigator.moveActiveCell(ACTIONS[action]);
                event.preventDefault();
            },
            onPageUp: function () {
                this.scrollDown(-this._viewPortHeight);
            },
            onPageDown: function () {
                this.scrollDown(this._viewPortHeight);
            },
            onEntryAction: function (event, action) {
                var sheet = this._workbook.activeSheet();
                if (event.mod) {
                    var shouldPrevent = true;
                    var key = String.fromCharCode(event.keyCode);
                    switch (key) {
                    case 'A':
                        sheet._activeDrawing = null;
                        this.navigator.selectAll();
                        break;
                    case 'Y':
                        this._workbook.undoRedoStack.redo();
                        break;
                    case 'Z':
                        this._workbook.undoRedoStack.undo();
                        break;
                    default:
                        shouldPrevent = false;
                        break;
                    }
                    if (shouldPrevent) {
                        event.preventDefault();
                    }
                } else {
                    var disabled = sheet.selection().enable() === false;
                    var casual = action !== ':edit';
                    if (action == 'delete' || action == 'backspace') {
                        if (sheet._activeDrawing) {
                            this._execute({
                                command: 'DeleteDrawingCommand',
                                options: { drawing: sheet._activeDrawing }
                            });
                        } else if (!disabled) {
                            this._execute({ command: 'ClearContentCommand' });
                        }
                        event.preventDefault();
                    } else if (alphaNumRegExp.test(action) || !casual) {
                        sheet._activeDrawing = null;
                        if (disabled) {
                            event.preventDefault();
                            return;
                        }
                        if (casual) {
                            this.editor.value('');
                        }
                        this.activateEditor(casual);
                    } else {
                        this.navigator.navigateInSelection(ENTRY_ACTIONS[action]);
                        event.preventDefault();
                    }
                }
            },
            onShiftAction: function (event, action) {
                this.navigator.modifySelection(ACTIONS[action.replace('shift+', '')], this.appendSelection);
                event.preventDefault();
            },
            onMouseMove: function (event) {
                var sheet = this._workbook.activeSheet();
                if (sheet.resizingInProgress() || sheet.selectionInProgress()) {
                    return;
                }
                var object = this.objectAt(event);
                if (object.type === 'columnresizehandle' || object.type === 'rowresizehandle') {
                    sheet.positionResizeHandle(object.ref);
                } else {
                    sheet.removeResizeHandle();
                }
                sheet._renderComment(object.type == 'cell' ? object.ref : null);
            },
            onMouseDown: function (event) {
                var object = this.objectAt(event);
                if (object.pane) {
                    this.originFrame = object.pane;
                }
                if (this._startResizingDrawing(event, object)) {
                    event.stopPropagation();
                    return;
                }
                var sheet = this._workbook.activeSheet();
                var win = this.container.closest('[data-role="window"]');
                if (win.length) {
                    win = kendo.widgetInstance(win);
                    if (win && win.options.modal) {
                        event.stopPropagation();
                    }
                }
                sheet._activeDrawing = null;
                if (object.type === 'drawing') {
                    sheet._activeDrawing = object.drawing;
                    object.copy = object.drawing.clone();
                    object.startBox = sheet.drawingBoundingBox(object.copy);
                    sheet.startDragging(object);
                    sheet.triggerChange({ dragging: true });
                    event.preventDefault();
                    return;
                }
                if (object.type === 'editor') {
                    this.onEditorEsc();
                    this.openCustomEditor();
                    event.preventDefault();
                    return;
                }
                if (this.editor.canInsertRef(false) && object.ref) {
                    this._workbook.activeSheet()._setFormulaSelections(this.editor.highlightedRefs());
                    this.navigator.startSelection(object.ref, this._selectionMode, this.appendSelection, event.shiftKey);
                    event.preventDefault();
                    return;
                } else {
                    this._preventNavigation = false;
                    this.editor.deactivate();
                    if (this._preventNavigation) {
                        return;
                    }
                }
                if (object.type === 'columnresizehandle' || object.type === 'rowresizehandle') {
                    sheet.startResizing({
                        x: object.x,
                        y: object.y
                    });
                    event.preventDefault();
                    return;
                }
                if (object.type === 'filtericon') {
                    this.openFilterMenu(event);
                    event.preventDefault();
                    return;
                }
                this._selectionMode = SELECTION_MODES[object.type];
                this.appendSelection = event.mod;
                this.navigator.startSelection(object.ref, this._selectionMode, this.appendSelection, event.shiftKey);
            },
            _startResizingDrawing: function (event) {
                var handle = $(event.target).closest('.k-spreadsheet-drawing-handle');
                if (handle.length) {
                    var location = this.translateCoords(event);
                    var direction = handle.data('direction');
                    var sheet = this._workbook.activeSheet();
                    var drawing = sheet._activeDrawing;
                    sheet.startDragging({
                        pane: this.originFrame,
                        drawing: drawing,
                        copy: drawing.clone(),
                        startBox: sheet.drawingBoundingBox(drawing),
                        resize: direction,
                        startX: location.x,
                        startY: location.y
                    });
                    return true;
                }
            },
            onContextMenu: function (event) {
                var sheet = this._workbook.activeSheet();
                event.preventDefault();
                if (sheet.resizingInProgress() || sheet.draggingInProgress()) {
                    return;
                }
                this.cellContextMenu.close();
                this.colHeaderContextMenu.close();
                this.rowHeaderContextMenu.close();
                this.drawingContextMenu.close();
                var menu;
                var object = this.objectAt(event);
                if (object.type === 'columnresizehandle' || object.type === 'rowresizehandle') {
                    return;
                }
                if (object.ref) {
                    this.navigator.selectForContextMenu(object.ref, SELECTION_MODES[object.type]);
                } else if (object.type == 'drawing') {
                    this.navigator.selectDrawingForContextMenu(object.drawing);
                }
                var isComposite = this.navigator._sheet.select() instanceof kendo.spreadsheet.UnionRef;
                var showUnhide = false;
                var showUnmerge = false;
                if (object.type == 'columnheader') {
                    menu = this.colHeaderContextMenu;
                    showUnhide = !isComposite && this.axisManager.selectionIncludesHiddenColumns();
                } else if (object.type == 'rowheader') {
                    menu = this.rowHeaderContextMenu;
                    showUnhide = !isComposite && this.axisManager.selectionIncludesHiddenRows();
                } else if (object.type == 'drawing') {
                    menu = this.drawingContextMenu;
                } else {
                    menu = this.cellContextMenu;
                    showUnmerge = this.navigator.selectionIncludesMergedCells();
                }
                menu.element.find(COMPOSITE_UNAVAILABLE_ACTION_SELECTORS).toggle(!isComposite);
                menu.element.find(UNHIDE_ACTION_SELECTORS).toggle(showUnhide);
                menu.element.find('[data-action=unmerge]').toggle(showUnmerge);
                setTimeout(function () {
                    menu.open(event.pageX, event.pageY);
                });
            },
            prevent: function (event) {
                event.preventDefault();
            },
            constrainResize: function (type, ref) {
                var sheet = this._workbook.activeSheet();
                var resizeHandle = sheet.resizeHandlePosition();
                return !resizeHandle || type === 'outside' || type === 'topcorner' || ref.col < resizeHandle.col || ref.row < resizeHandle.row;
            },
            _dragDrawing: function (event) {
                var sheet = this._workbook.activeSheet();
                var drag = sheet.draggingInProgress();
                if (!drag) {
                    return false;
                }
                var location = this.translateCoords(event);
                var drawing = drag.drawing;
                var deltaX = location.x - drag.startX;
                var deltaY = location.y - drag.startY;
                if (drag.resize == 'SE') {
                    if (drag.aspect) {
                        if (Math.abs(deltaX) > Math.abs(deltaY)) {
                            drawing.width = Math.max(drag.copy.width + deltaX, 20);
                            drawing.height = drawing.width / drag.aspect;
                        } else {
                            drawing.height = Math.max(drag.copy.height + deltaY, 20);
                            drawing.width = drawing.height * drag.aspect;
                        }
                    } else {
                        drawing.width = Math.max(drag.copy.width + deltaX, 20);
                        drawing.height = Math.max(drag.copy.height + deltaY, 20);
                    }
                } else if (drag.resize == 'E') {
                    drawing.width = Math.max(drag.copy.width + deltaX, 20);
                } else if (drag.resize == 'S') {
                    drawing.height = Math.max(drag.copy.height + deltaY, 20);
                } else if (drag.resize == 'N') {
                    if (drag.copy.height - deltaY > 20) {
                        drawing.height = drag.copy.height - deltaY;
                        drawing.offsetY = drag.copy.offsetY + deltaY;
                    }
                } else if (drag.resize == 'W') {
                    if (drag.copy.width - deltaX > 20) {
                        drawing.width = drag.copy.width - deltaX;
                        drawing.offsetX = drag.copy.offsetX + deltaX;
                    }
                } else if (drag.resize == 'NE') {
                    drawing.width = Math.max(drag.copy.width + deltaX, 20);
                    if (drag.copy.height - deltaY > 20) {
                        drawing.height = drag.copy.height - deltaY;
                        drawing.offsetY = drag.copy.offsetY + deltaY;
                    }
                } else if (drag.resize == 'SW') {
                    drawing.height = Math.max(drag.copy.height + deltaY, 20);
                    if (drag.copy.width - deltaX > 20) {
                        drawing.width = drag.copy.width - deltaX;
                        drawing.offsetX = drag.copy.offsetX + deltaX;
                    }
                } else if (drag.resize == 'NW') {
                    if (drag.copy.height - deltaY > 20) {
                        drawing.height = drag.copy.height - deltaY;
                        drawing.offsetY = drag.copy.offsetY + deltaY;
                    }
                    if (drag.copy.width - deltaX > 20) {
                        drawing.width = drag.copy.width - deltaX;
                        drawing.offsetX = drag.copy.offsetX + deltaX;
                    }
                } else {
                    drawing.offsetX = drag.copy.offsetX + deltaX;
                    drawing.offsetY = drag.copy.offsetY + deltaY;
                }
                sheet.triggerChange({ dragging: true });
                return true;
            },
            onMouseDrag: function (event) {
                if (this._selectionMode === 'sheet') {
                    return;
                }
                var location = {
                    clientX: event.clientX,
                    clientY: event.clientY
                };
                var sheet = this._workbook.activeSheet();
                if (this._dragDrawing(event)) {
                    return;
                }
                var object = this.objectAt(location);
                if (sheet.resizingInProgress()) {
                    if (!this.constrainResize(object.type, object.ref)) {
                        sheet.resizeHintPosition({
                            x: object.x,
                            y: object.y
                        });
                    }
                    return;
                }
                if (object.type === 'outside') {
                    this.startAutoScroll(object);
                    return;
                }
                if (this.originFrame === object.pane) {
                    this.selectToLocation(location);
                } else {
                    var frame = this.originFrame._grid;
                    if (object.x > frame.right) {
                        this.scrollLeft();
                    }
                    if (object.y > frame.bottom) {
                        this.scrollTop();
                    }
                    if (object.y < frame.top || object.x < frame.left) {
                        this.startAutoScroll(object, location);
                    } else {
                        this.selectToLocation(location);
                    }
                }
                event.preventDefault();
            },
            onMouseUp: function (event) {
                var sheet = this._workbook.activeSheet();
                sheet.completeResizing();
                sheet.completeDragging();
                this.navigator.completeSelection();
                this.stopAutoScroll();
                var editor = this.editor.activeEditor();
                if (!editor) {
                    return;
                }
                var el = event.target;
                while (el) {
                    if (el === editor.element[0]) {
                        return;
                    }
                    el = el.parentNode;
                }
                var object = this.objectAt(event);
                if (object && object.ref && editor.canInsertRef(false)) {
                    editor.refAtPoint(sheet);
                    sheet._setFormulaSelections(editor.highlightedRefs());
                }
            },
            onDblClick: function (event) {
                var object = this.objectAt(event);
                var disabled = this._workbook.activeSheet().selection().enable() === false;
                if (object.type !== 'cell' || disabled) {
                    return;
                }
                var sel = this._workbook.activeSheet().selection();
                this.activateEditor(!sel.value() && !sel.formula());
                this.onEditorUpdate();
            },
            onCut: function (e) {
                if (e) {
                    var table = this.clipboardElement.find('table.kendo-clipboard-' + this.clipboard._uid).detach();
                    this.clipboardElement.append(table.clone(false));
                    setTimeout(function () {
                        this.clipboardElement.empty().append(table);
                    }.bind(this));
                }
                this._execute({
                    command: 'CutCommand',
                    options: {
                        workbook: this.view._workbook,
                        event: e.originalEvent || e
                    }
                });
            },
            clipBoardValue: function () {
                return this.clipboardElement.html();
            },
            _pasteImage: function (dataTransferItem) {
                var self = this;
                var blob = dataTransferItem.getAsFile();
                var img = new window.Image();
                img.src = window.URL.createObjectURL(blob);
                img.onload = function () {
                    self._execute({
                        command: 'InsertImageCommand',
                        options: {
                            blob: blob,
                            width: img.width,
                            height: img.height
                        }
                    });
                };
                setTimeout(function () {
                    window.URL.revokeObjectURL(img.src);
                }, 10);
            },
            onPaste: function (e) {
                var self = this;
                var html = '';
                var plain = '';
                self.clipboard.menuInvoked = e === undefined;
                if (e) {
                    var clipboardData = e.originalEvent.clipboardData;
                    if (clipboardData && clipboardData.getData) {
                        e.preventDefault();
                        var hasHTML = false;
                        var hasPlainText = false;
                        if (window.DOMStringList && clipboardData.types instanceof window.DOMStringList) {
                            hasHTML = clipboardData.types.contains('text/html');
                            hasPlainText = clipboardData.types.contains('text/plain');
                        } else {
                            hasHTML = /text\/html/.test(clipboardData.types);
                            hasPlainText = /text\/plain/.test(clipboardData.types);
                        }
                        if (hasHTML) {
                            html = clipboardData.getData('text/html');
                        }
                        if (hasPlainText) {
                            plain = clipboardData.getData('text/plain').trim();
                        }
                        if (!hasHTML && !hasPlainText && clipboardData.items && clipboardData.items.length) {
                            for (var i = 0; i < clipboardData.items.length; ++i) {
                                var item = clipboardData.items[i];
                                if (item.kind == 'file' && /^image\/(?:png|jpe?g|gif)$/i.test(item.type)) {
                                    return self._pasteImage(item);
                                }
                            }
                        }
                    } else {
                        var table = self.clipboardElement.find('table.kendo-clipboard-' + self.clipboard._uid).detach();
                        self.clipboardElement.empty();
                        setTimeout(function () {
                            var html = self.clipboardElement.html();
                            var plain = window.clipboardData.getData('Text').trim();
                            if (!html && !plain) {
                                return;
                            }
                            self.clipboard.external({
                                html: html,
                                plain: plain
                            });
                            self.clipboardElement.empty().append(table);
                            self._execute({
                                command: 'PasteCommand',
                                options: {
                                    workbook: self.view._workbook,
                                    event: e.originalEvent || e
                                }
                            });
                            self.clipboard.menuInvoked = true;
                        });
                        return;
                    }
                } else {
                    if (kendo.support.browser.msie) {
                        self.clipboardElement.focus().select();
                        document.execCommand('paste');
                        return;
                    } else {
                        self.clipboard.menuInvoked = true;
                    }
                }
                if (!html && !plain) {
                    return;
                }
                self.clipboard.external({
                    html: html,
                    plain: plain
                });
                self._execute({
                    command: 'PasteCommand',
                    options: {
                        workbook: self.view._workbook,
                        event: e.originalEvent || e
                    }
                });
            },
            onCopy: function (e) {
                this.clipboard.menuInvoked = e === undefined;
                this._execute({
                    command: 'CopyCommand',
                    options: {
                        workbook: this.view._workbook,
                        event: e.originalEvent || e
                    }
                });
            },
            scrollTop: function () {
                this.scroller.scrollTop = 0;
            },
            scrollLeft: function () {
                this.scroller.scrollLeft = 0;
            },
            scrollDown: function (value) {
                this.scroller.scrollTop += value;
            },
            scrollRight: function (value) {
                this.scroller.scrollLeft += value;
            },
            scrollWith: function (right, down) {
                this.scroller.scrollTop += down;
                this.scroller.scrollLeft += right;
            },
            translateCoords: function (location) {
                var box = this.container[0].getBoundingClientRect();
                return {
                    x: location.clientX - box.left,
                    y: location.clientY - box.top
                };
            },
            objectAt: function (location, noDrawing) {
                if (!location) {
                    return;
                }
                location = this.translateCoords(location);
                return this.view.objectAt(location.x, location.y, noDrawing);
            },
            selectToLocation: function (cellLocation) {
                var object = this.objectAt(cellLocation, true);
                if (object.pane && object.ref) {
                    this.extendSelection(object);
                    this.lastKnownCellLocation = cellLocation;
                    this.originFrame = object.pane;
                }
                this.stopAutoScroll();
            },
            extendSelection: function (object) {
                this.navigator.extendSelection(object.ref, this._selectionMode, this.appendSelection);
            },
            autoScroll: function () {
                var x = this._autoScrollTarget.x;
                var y = this._autoScrollTarget.y;
                var boundaries = this.originFrame._grid;
                var scroller = this.view.scroller;
                var scrollStep = 8;
                var scrollLeft = scroller.scrollLeft;
                var scrollTop = scroller.scrollTop;
                if (x < boundaries.left) {
                    this.scrollRight(-scrollStep);
                }
                if (x > boundaries.right) {
                    this.scrollRight(scrollStep);
                }
                if (y < boundaries.top) {
                    this.scrollDown(-scrollStep);
                }
                if (y > boundaries.bottom) {
                    this.scrollDown(scrollStep);
                }
                if (scrollTop === scroller.scrollTop && scrollLeft === scroller.scrollLeft) {
                    this.selectToLocation(this.finalLocation);
                } else {
                    this.extendSelection(this.objectAt(this.lastKnownCellLocation));
                }
            },
            startAutoScroll: function (viewObject, location) {
                if (!this._scrollInterval) {
                    this._scrollInterval = setInterval(this.autoScroll.bind(this), 50);
                }
                this.finalLocation = location || this.lastKnownCellLocation;
                this._autoScrollTarget = viewObject;
            },
            stopAutoScroll: function () {
                clearInterval(this._scrollInterval);
                this._scrollInterval = null;
            },
            openCustomEditor: function () {
                this.view.openCustomEditor();
            },
            openFilterMenu: function (event) {
                var object = this.objectAt(event);
                var sheet = this._workbook.activeSheet();
                var column = sheet.filterColumn(object.ref);
                var filterMenu = this.view.createFilterMenu(column);
                filterMenu.bind('action', this.onCommandRequest.bind(this));
                filterMenu.bind('action', filterMenu.close.bind(filterMenu));
                filterMenu.openFor(event.target);
            },
            _saveEditorValue: function (arrayFormula) {
                var sheet = this.editor._range.sheet();
                var value = this.editor.value();
                if (this._workbook.activeSheet() !== sheet) {
                    this._workbook.activeSheet()._setFormulaSelections();
                    this._workbook.activeSheet(sheet);
                }
                sheet.isInEditMode(false);
                this._lastEditorValue = value;
                this._execute({
                    command: 'EditCommand',
                    options: {
                        value: value,
                        arrayFormula: arrayFormula
                    }
                });
            },
            onEditorChange: function () {
                this._saveEditorValue(false);
            },
            onEditorArrayFormula: function () {
                this._saveEditorValue(true);
                this.editor.deactivate(true);
            },
            onEditorActivate: function () {
                var workbook = this._workbook;
                var sheet = workbook.activeSheet();
                sheet._setFormulaSelections(this.editor.highlightedRefs());
                sheet.isInEditMode(true);
            },
            onEditorDeactivate: function () {
                var sheet = this._workbook.activeSheet();
                sheet.isInEditMode(false);
                sheet._setFormulaSelections([]);
            },
            onEditorUpdate: function () {
                this._workbook.activeSheet()._setFormulaSelections(this.editor.highlightedRefs());
            },
            onEditorBarFocus: function () {
                var disabled = this._workbook.activeSheet().selection().enable() === false;
                if (disabled) {
                    return;
                }
                this.editor.activate({
                    range: this._workbook.activeSheet().selection(),
                    rect: this.view.activeCellRectangle(),
                    tooltip: this._activeTooltip()
                });
            },
            onEditorCellFocus: function () {
                this.editor.scale();
            },
            onEditorEsc: function () {
                this.resetEditorValue();
                this.editor.deactivate();
                this.clipboardElement.focus();
            },
            insertNewline: function (e) {
                e.preventDefault();
                this.editor.insertNewline();
            },
            onEditorBlur: function (_, action) {
                if (this.editor.isFiltered()) {
                    return;
                }
                this._preventNavigation = false;
                this.editor.deactivate();
                if (!this._preventNavigation) {
                    this.clipboardElement.focus();
                    this.navigator.navigateInSelection(ENTRY_ACTIONS[action]);
                }
            },
            onEditorAction: function (event, action) {
                var editor = this.editor;
                var sheet = this._workbook.activeSheet();
                if (this._casualEditing && /^(?:up|right|down|left)$/.test(action)) {
                    this.deactivateEditor();
                    this.navigator.moveActiveCell(ACTIONS[action]);
                    event.preventDefault();
                } else if (editor.canInsertRef(true)) {
                    this.navigator.moveActiveCell(ACTIONS[action]);
                    editor.activeEditor().refAtPoint(sheet);
                    sheet._setFormulaSelections(editor.highlightedRefs());
                    event.preventDefault();
                }
            },
            onEditorShiftAction: function (event, action) {
                var editor = this.editor;
                var sheet = this._workbook.activeSheet();
                if (editor.canInsertRef(true)) {
                    this.navigator.modifySelection(ACTIONS[action.replace('shift+', '')], this.appendSelection);
                    editor.activeEditor().refAtPoint(sheet);
                    sheet._setFormulaSelections(editor.highlightedRefs());
                    event.preventDefault();
                }
            },
            resetEditorValue: function () {
                var sheet = this._workbook.activeSheet();
                var ref = sheet.activeCell();
                var input = this._workbook._inputForRef(ref);
                var x = sheet.range(ref).intersectingArrayFormula();
                if (x) {
                    input = '=' + x.formula;
                }
                this.editor.value(input, !!x);
            },
            activateEditor: function (casual) {
                this._casualEditing = casual;
                this.editor.activate({
                    range: this._workbook.activeSheet().selection(),
                    rect: this.view.activeCellRectangle(),
                    tooltip: this._activeTooltip()
                }).focus();
            },
            deactivateEditor: function () {
                this.view.editor.deactivate();
            },
            onCommandRequest: function (e) {
                if (e.command) {
                    this._execute(e);
                } else {
                    this._workbook.undoRedoStack[e.action]();
                }
            },
            onDialogRequest: function (e) {
                var additionalOptions = {
                    pdfExport: this._workbook.options.pdf,
                    excelExport: this._workbook.options.excel
                };
                if (e.options) {
                    $.extend(true, e.options, additionalOptions);
                } else {
                    e.options = additionalOptions;
                }
                this.view.openDialog(e.name, e.options);
            },
            onNameEditorEnter: function () {
                var ref;
                var workbook = this._workbook;
                var sheet = workbook.activeSheet();
                var name = this.view.nameEditor.value();
                ref = kendo.spreadsheet.calc.parseReference(name, true) || workbook.nameValue(name);
                if (ref instanceof kendo.spreadsheet.Ref) {
                    if (ref.sheet && ref.sheet.toLowerCase() != sheet.name().toLowerCase()) {
                        var tmp = workbook.sheetByName(ref.sheet);
                        if (tmp) {
                            workbook.activeSheet(tmp);
                            sheet = tmp;
                        }
                    }
                    sheet.range(ref).select();
                    return;
                }
                ref = sheet.selection()._ref.clone().simplify().setSheet(sheet.name(), true);
                this._execute({
                    command: 'DefineNameCommand',
                    options: {
                        name: name,
                        value: ref
                    }
                });
                this.clipboardElement.focus();
            },
            onNameEditorCancel: function () {
                this.clipboardElement.focus();
            },
            onNameEditorSelect: function (ev) {
                var name = ev.name;
                var workbook = this._workbook;
                var sheet = workbook.activeSheet();
                var ref = workbook.nameValue(name);
                if (ref instanceof kendo.spreadsheet.Ref) {
                    if (ref.sheet && ref.sheet.toLowerCase() != sheet.name().toLowerCase()) {
                        var tmp = workbook.sheetByName(ref.sheet);
                        if (tmp) {
                            workbook.activeSheet(tmp);
                            sheet = tmp;
                        }
                    }
                    sheet.range(ref).select();
                    return;
                }
                this.clipboardElement.focus();
            },
            onNameEditorDelete: function (ev) {
                this._execute({
                    command: 'DeleteNameCommand',
                    options: { name: ev.name }
                });
                this.clipboardElement.focus();
            }
        });
        kendo.spreadsheet.Controller = Controller;
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/view', [
        'kendo.core',
        'kendo.menu',
        'spreadsheet/sheetsbar',
        'util/main'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var CellRef = kendo.spreadsheet.CellRef;
        var DOT = '.';
        var RESIZE_HANDLE_WIDTH = 7;
        var EDIT_BUTTON_WIDTH = 20;
        var viewClassNames = {
            view: 'k-spreadsheet-view',
            fixedContainer: 'k-spreadsheet-fixed-container',
            editContainer: 'k-spreadsheet-edit-container',
            scroller: 'k-spreadsheet-scroller',
            viewSize: 'k-spreadsheet-view-size',
            clipboard: 'k-spreadsheet-clipboard',
            cellEditor: 'k-spreadsheet-cell-editor',
            barEditor: 'k-spreadsheet-editor',
            topCorner: 'k-spreadsheet-top-corner',
            filterHeadersWrapper: 'k-filter-wrapper',
            filterRange: 'k-filter-range',
            filterButton: 'k-spreadsheet-filter',
            filterButtonActive: 'k-state-active',
            horizontalResize: 'k-horizontal-resize',
            verticalResize: 'k-vertical-resize',
            icon: 'k-icon',
            iconFilterDefault: 'k-i-arrow-60-down',
            sheetsBar: 'k-spreadsheet-sheets-bar',
            sheetsBarActive: 'k-spreadsheet-sheets-bar-active',
            sheetsBarInactive: 'k-spreadsheet-sheets-bar-inactive',
            cellContextMenu: 'k-spreadsheet-cell-context-menu',
            rowHeaderContextMenu: 'k-spreadsheet-row-header-context-menu',
            colHeaderContextMenu: 'k-spreadsheet-col-header-context-menu',
            drawingContextMenu: 'k-spreadsheet-drawing-context-menu'
        };
        kendo.spreadsheet.messages.view = {
            nameBox: 'Name Box',
            errors: {
                openUnsupported: 'Unsupported format. Please select an .xlsx file.',
                shiftingNonblankCells: 'Cannot insert cells due to data loss possibility. Select another insert location or delete the data from the end of your worksheet.',
                insertColumnWhenRowIsSelected: 'Cannot insert column when all columns are selected.',
                insertRowWhenColumnIsSelected: 'Cannot insert row when all rows are selected.',
                filterRangeContainingMerges: 'Cannot create a filter within a range containing merges',
                sortRangeContainingMerges: 'Cannot sort a range containing merges',
                cantSortMultipleSelection: 'Cannot sort multiple selection',
                cantSortNullRef: 'Cannot sort empty selection',
                cantSortMixedCells: 'Cannot sort range containing cells of mixed shapes',
                validationError: 'The value that you entered violates the validation rules set on the cell.',
                cannotModifyDisabled: 'Cannot modify disabled cells.'
            },
            tabs: {
                home: 'Home',
                insert: 'Insert',
                data: 'Data'
            }
        };
        kendo.spreadsheet.messages.menus = {
            'cut': 'Cut',
            'copy': 'Copy',
            'paste': 'Paste',
            'merge': 'Merge',
            'unmerge': 'Unmerge',
            'delete': 'Delete',
            'hide': 'Hide',
            'unhide': 'Unhide',
            'bringToFront': 'Bring to front',
            'sendToBack': 'Send to back'
        };
        function selectElementContents(el) {
            var sel = window.getSelection();
            sel.removeAllRanges();
            var range = document.createRange();
            range.selectNodeContents(el);
            sel.addRange(range);
        }
        function cellBefore(table, row) {
            var cells = table.trs[row].children;
            return cells[cells.length - 2];
        }
        function cellAbove(table, row) {
            var prevRow = table.trs[row - 1];
            var index = table.trs[row].children.length - 1;
            if (prevRow && index >= 0) {
                return prevRow.children[index];
            }
        }
        function cellBorder(value) {
            return (value.size || 1) + 'px solid ' + (value.color || '#000');
        }
        function asURL(link) {
            if (!/:\/\//.test(link)) {
                link = 'http://' + link;
            }
            return link;
        }
        function drawCell(collection, cell, cls, showGrid) {
            function maybeLink(el) {
                var link = cell.link;
                if (!link) {
                    if (typeof cell.value == 'object') {
                        link = cell.value.link;
                    }
                }
                if (link) {
                    var style = { textDecoration: 'none' };
                    if (cell.color) {
                        style.color = cell.color;
                    }
                    if (cell.underline) {
                        style.textDecoration = 'underline';
                    }
                    return kendo.dom.element('a', {
                        href: asURL(link),
                        style: style,
                        target: '_blank'
                    }, el ? [el] : []);
                }
                return el;
            }
            var shouldDraw = cell.value != null || cell.validation != null && !cell.validation.value || cell.background || cell.merged || cell.comment;
            if (!cls && !shouldDraw) {
                return;
            }
            var style = {};
            var background = cell.background;
            if (background) {
                var defaultBorder = background;
                if (showGrid) {
                    defaultBorder = kendo.parseColor(defaultBorder).toHSV();
                    defaultBorder.v *= 0.9;
                    defaultBorder = defaultBorder.toCssRgba();
                }
                defaultBorder = cellBorder({ color: defaultBorder });
                style.outline = defaultBorder;
            }
            if (background) {
                style.backgroundColor = background;
            }
            if (cell.color) {
                style.color = cell.color;
            }
            if (cell.fontFamily) {
                style.fontFamily = cell.fontFamily;
            }
            if (cell.underline) {
                style.textDecoration = 'underline';
            }
            if (cell.italic) {
                style.fontStyle = 'italic';
            }
            if (cell.textAlign) {
                style.textAlign = cell.textAlign;
            }
            if (cell.bold) {
                style.fontWeight = 'bold';
            }
            if (cell.fontSize) {
                style.fontSize = cell.fontSize + 'px';
            }
            if (cell.wrap === true) {
                style.whiteSpace = 'pre-wrap';
                style.overflowWrap = 'break-word';
                style.wordWrap = 'break-word';
            } else {
                style.whiteSpace = 'pre';
                style.overflowWrap = 'normal';
                style.wordWrap = 'normal';
            }
            style.left = cell.left + 1 + 'px';
            style.top = cell.top + 1 + 'px';
            style.width = cell.width - 1 + 'px';
            style.height = cell.height - 1 + 'px';
            var data = cell.value, type = typeof data, format = cell.format;
            if (!format && type == 'number' && data != Math.floor(data)) {
                format = '0.##############';
            }
            if (format && data != null) {
                data = kendo.spreadsheet.formatting.format(data, format);
                if (data.__dataType) {
                    type = data.__dataType;
                }
            } else if (data !== null && data !== undefined) {
                data = kendo.dom.text(data);
            }
            if (!style.textAlign) {
                switch (type) {
                case 'number':
                case 'date':
                case 'percent':
                case 'currency':
                    style.textAlign = 'right';
                    break;
                case 'boolean':
                    style.textAlign = 'center';
                    break;
                }
            }
            kendo.spreadsheet.draw.applyIndent(cell, style);
            var classNames = [paneClassNames.cell];
            if (cls) {
                classNames.push(cls);
            }
            if (cell.enable === false) {
                classNames.push('k-state-disabled');
            }
            if (cell.merged) {
                classNames.push('k-spreadsheet-merged-cell');
            }
            if (cell.comment) {
                classNames.push('k-spreadsheet-has-comment');
            }
            var verticalAlign = cell.verticalAlign || 'bottom';
            if (verticalAlign && data) {
                data = kendo.dom.element('div', { className: 'k-vertical-align-' + verticalAlign }, [maybeLink(data)]);
            } else {
                data = maybeLink(data);
            }
            var children = data ? [data] : [];
            var properties = { style: style };
            var validation = cell.validation;
            if (validation && !validation.value) {
                children.push(kendo.dom.element('span', { className: 'k-dirty' }));
                classNames.push('k-dirty-cell');
                properties.title = validation.message;
            }
            properties.className = classNames.join(' ');
            var div = kendo.dom.element('div', properties, children);
            collection.push(div);
            return div;
        }
        function addCell(table, row, cell) {
            var style = {};
            if (cell.background) {
                style.backgroundColor = cell.background;
            }
            if (cell.color) {
                style.color = cell.color;
            }
            if (cell.fontFamily) {
                style.fontFamily = cell.fontFamily;
            }
            if (cell.underline) {
                style.textDecoration = 'underline';
            }
            if (cell.italic) {
                style.fontStyle = 'italic';
            }
            if (cell.textAlign) {
                style.textAlign = cell.textAlign;
            }
            if (cell.verticalAlign) {
                style.verticalAlign = cell.verticalAlign === 'center' ? 'middle' : cell.verticalAlign;
            }
            if (cell.bold) {
                style.fontWeight = 'bold';
            }
            if (cell.fontSize) {
                style.fontSize = cell.fontSize + 'px';
            }
            if (cell.wrap === true) {
                style.whiteSpace = 'pre-wrap';
            }
            if (cell.borderRight) {
                style.borderRight = cellBorder(cell.borderRight);
            } else if (cell.background) {
                style.borderRightColor = cell.background;
            }
            if (cell.borderBottom) {
                style.borderBottom = cellBorder(cell.borderBottom);
            } else if (cell.background) {
                style.borderBottomColor = cell.background;
            }
            var data = cell.value, type = typeof data, format = cell.format;
            if (!format && type == 'number' && data != Math.floor(data)) {
                format = '0.##############';
            }
            if (format && data != null) {
                data = kendo.spreadsheet.formatting.format(data, format);
                if (data.__dataType) {
                    type = data.__dataType;
                }
            }
            if (!style.textAlign) {
                switch (type) {
                case 'number':
                case 'date':
                case 'percent':
                case 'currency':
                    style.textAlign = 'right';
                    break;
                case 'boolean':
                    style.textAlign = 'center';
                    break;
                }
            }
            var className = null;
            if (cell.enable === false) {
                className = 'k-state-disabled';
            }
            var td = table.addCell(row, data, style, className, cell.validation);
            var border, sibling;
            if (cell.borderLeft) {
                sibling = cellBefore(table, row);
                border = cellBorder(cell.borderLeft);
                if (sibling && border) {
                    sibling.attr.style.borderRight = border;
                }
            } else if (cell.background) {
                style.borderLeftColor = cell.background;
            }
            if (cell.borderTop) {
                sibling = cellAbove(table, row);
                border = cellBorder(cell.borderTop);
                if (sibling && border) {
                    sibling.attr.style.borderBottom = border;
                }
            } else if (cell.background) {
                style.borderTopColor = cell.background;
            }
            return td;
        }
        var HtmlTable = kendo.Class.extend({
            init: function () {
                this.cols = [];
                this.trs = [];
                this._height = 0;
                this._width = 0;
            },
            addColumn: function (width) {
                this._width += width;
                var col = kendo.dom.element('col', { style: { width: width + 'px' } });
                col.visible = width > 0;
                this.cols.push(col);
            },
            addRow: function (height) {
                var attr = null;
                attr = { style: { height: height + 'px' } };
                this._height += height;
                var tr = kendo.dom.element('tr', attr);
                tr.visible = height > 0;
                this.trs.push(tr);
            },
            addCell: function (rowIndex, text, style, className, validation) {
                if (text === null || text === undefined) {
                    text = '';
                }
                if (!(text instanceof kendo.dom.Node)) {
                    text = kendo.dom.text(text);
                }
                var children = [text];
                var properties = { style: style };
                if (validation && !validation.value) {
                    children.push(kendo.dom.element('span', { className: 'k-dirty' }));
                    className = (className || '') + (className ? ' ' : '') + 'k-dirty-cell';
                    properties.title = validation.message;
                }
                if (className) {
                    properties.className = className;
                }
                var td = kendo.dom.element('td', properties, children);
                this.trs[rowIndex].children.push(td);
                return td;
            },
            toDomTree: function (x, y, className) {
                this.trs = this.trs.filter(function (tr) {
                    return tr.visible;
                });
                var offset = 0;
                this.cols = this.cols.filter(function (col, ci) {
                    if (!col.visible) {
                        this.trs.forEach(function (tr) {
                            tr.children.splice(ci - offset, 1);
                        });
                        offset++;
                    }
                    return col.visible;
                }, this);
                return kendo.dom.element('table', {
                    style: {
                        left: x + 'px',
                        top: y + 'px',
                        height: this._height + 'px',
                        width: this._width + 'px'
                    },
                    className: className
                }, [
                    kendo.dom.element('colgroup', null, this.cols),
                    kendo.dom.element('tbody', null, this.trs)
                ]);
            }
        });
        var CELL_CONTEXT_MENU = '<ul class="#=classNames.cellContextMenu#">' + '<li data-action=cut>#: messages.cut #</li>' + '<li data-action=copy>#: messages.copy #</li>' + '<li data-action=paste>#: messages.paste #</li>' + '<li class="k-separator"></li>' + '<li data-action=merge>#: messages.merge #</li>' + '<li data-action=unmerge>#: messages.unmerge #</li>' + '</ul>';
        var ROW_HEADER_CONTEXT_MENU = '<ul class="#=classNames.rowHeaderContextMenu#">' + '<li data-action=cut>#: messages.cut #</li>' + '<li data-action=copy>#: messages.copy #</li>' + '<li data-action=paste>#: messages.paste #</li>' + '<li class="k-separator"></li>' + '<li data-action="delete-row">#: messages.delete #</li>' + '<li data-action="hide-row">#: messages.hide #</li>' + '<li data-action="unhide-row">#: messages.unhide #</li>' + '</ul>';
        var COL_HEADER_CONTEXT_MENU = '<ul class="#=classNames.colHeaderContextMenu#">' + '<li data-action=cut>#: messages.cut #</li>' + '<li data-action=copy>#: messages.copy #</li>' + '<li data-action=paste>#: messages.paste #</li>' + '<li class="k-separator"></li>' + '<li data-action="delete-column">#: messages.delete #</li>' + '<li data-action="hide-column">#: messages.hide #</li>' + '<li data-action="unhide-column">#: messages.unhide #</li>' + '</ul>';
        var DRAWING_CONTEXT_MENU = '<ul class="#=classNames.drawingContextMenu#">' + '<li data-action="bring-to-front">#: messages.bringToFront #</li>' + '<li data-action="send-to-back">#: messages.sendToBack #</li>' + '<li class="k-separator"></li>' + '<li data-action="delete-drawing">#: messages.delete #</li>' + '</ul>';
        kendo.spreadsheet.ContextMenu = kendo.ui.ContextMenu;
        var VIEW_CONTENTS = kendo.template('<div class="#=classNames.view#"><div class="#=classNames.fixedContainer#"></div><div class="#=classNames.scroller#"><div class="#=classNames.viewSize#"></div></div>' + '<div tabindex="0" class="#=classNames.clipboard#" contenteditable=true></div><div class="#=classNames.cellEditor#"></div></div><div class="#=classNames.sheetsBar#"></div>' + CELL_CONTEXT_MENU + ROW_HEADER_CONTEXT_MENU + COL_HEADER_CONTEXT_MENU + DRAWING_CONTEXT_MENU);
        function within(value, min, max) {
            return value >= min && value <= max;
        }
        var View = kendo.Class.extend({
            init: function (element, options) {
                var classNames = View.classNames;
                this.element = element;
                this.options = $.extend(true, { messages: kendo.spreadsheet.messages.view }, this.options, options);
                this._chrome();
                this._dialogs = [];
                element.append(VIEW_CONTENTS({
                    classNames: classNames,
                    messages: kendo.spreadsheet.messages.menus
                }));
                this._formulaInput();
                this.wrapper = element.find(DOT + classNames.view);
                this.container = element.find(DOT + classNames.fixedContainer)[0];
                this.scroller = element.find(DOT + classNames.scroller)[0];
                this.clipboard = element.find(DOT + classNames.clipboard);
                this.viewSize = $(this.scroller.firstChild);
                this.tree = new kendo.dom.Tree(this.container);
                this.clipboardContents = new kendo.dom.Tree(this.clipboard[0]);
                this.editor = new kendo.spreadsheet.SheetEditor(this);
                this._sheetsbar();
                var contextMenuConfig = {
                    target: element,
                    animation: false,
                    showOn: 'never'
                };
                this.cellContextMenu = new kendo.spreadsheet.ContextMenu(element.find(DOT + classNames.cellContextMenu), contextMenuConfig);
                this.colHeaderContextMenu = new kendo.spreadsheet.ContextMenu(element.find(DOT + classNames.colHeaderContextMenu), contextMenuConfig);
                this.rowHeaderContextMenu = new kendo.spreadsheet.ContextMenu(element.find(DOT + classNames.rowHeaderContextMenu), contextMenuConfig);
                this.drawingContextMenu = new kendo.spreadsheet.ContextMenu(element.find(DOT + classNames.drawingContextMenu), contextMenuConfig);
            },
            enableClipboard: function (enable) {
                this.isClipboardDeactivated = !enable;
                if (enable) {
                    this.clipboard.attr('contenteditable', enable);
                } else {
                    this.clipboard.removeAttr('contenteditable');
                }
            },
            _resize: function () {
                var actionBar = $(this.formulaBar.element).parents('.k-spreadsheet-action-bar');
                var outerHeight = kendo._outerHeight;
                var tabstripHeight = this.tabstrip ? outerHeight(this.tabstrip.element) : 0;
                var formulaBarHeight = actionBar ? outerHeight(actionBar) : 0;
                var sheetsBarHeight = this.sheetsbar ? outerHeight(this.sheetsbar.element) : 0;
                this.wrapper.height(this.element.height() - (tabstripHeight + formulaBarHeight + sheetsBarHeight));
                if (this.tabstrip) {
                    this.tabstrip.quickAccessAdjust();
                }
            },
            _chrome: function () {
                var wrapper = $('<div class=\'k-spreadsheet-action-bar\' />').prependTo(this.element);
                var nameEditor = $('<div class=\'k-spreadsheet-name-editor\' />').appendTo(wrapper);
                this.nameEditor = new kendo.spreadsheet.NameEditor(nameEditor, this.options);
                var formulaBar = $('<div />').appendTo(wrapper);
                this.formulaBar = new kendo.spreadsheet.FormulaBar(formulaBar);
                if (this.options.toolbar) {
                    this._tabstrip();
                }
            },
            _formulaInput: function () {
                var editor = this.element.find(DOT + View.classNames.cellEditor);
                this.formulaInput = new kendo.spreadsheet.FormulaInput(editor, { autoScale: true });
            },
            _sheetsbar: function () {
                if (this.options.sheetsbar) {
                    var options = $.extend(true, { openDialog: this.openDialog.bind(this) }, this.options.sheetsbar);
                    this.sheetsbar = new kendo.spreadsheet.SheetsBar(this.element.find(DOT + View.classNames.sheetsBar), options);
                }
            },
            _tabstrip: function () {
                var messages = this.options.messages.tabs;
                var options = $.extend(true, {
                    home: true,
                    insert: true,
                    data: true
                }, this.options.toolbar);
                var tabs = [];
                if (this.tabstrip) {
                    this.tabstrip.destroy();
                    this.element.children('.k-tabstrip').remove();
                }
                for (var name in options) {
                    if (options[name] === true || options[name] instanceof Array) {
                        tabs.push({
                            id: name,
                            text: messages[name],
                            content: ''
                        });
                    }
                }
                this.tabstrip = new kendo.spreadsheet.TabStrip($('<div />').prependTo(this.element), {
                    animation: false,
                    dataTextField: 'text',
                    dataContentField: 'content',
                    dataSource: tabs,
                    toolbarOptions: options,
                    view: this
                });
                this.tabstrip.select(0);
            },
            _executeCommand: function (e) {
                this._sheet.trigger('commandRequest', e);
            },
            workbook: function (workbook) {
                this._workbook = workbook;
                workbook._view = this;
                this.nameEditor._workbook = workbook;
            },
            sheet: function (sheet) {
                this._sheet = sheet;
            },
            activeCellRectangle: function () {
                return this.cellRectangle(this._sheet._viewActiveCell());
            },
            _rectangle: function (pane, ref) {
                return pane._grid.boundingRectangle(ref.toRangeRef());
            },
            isColumnResizer: function (x, pane, col) {
                x -= this._sheet._grid._headerWidth;
                if (!pane._grid.columns.frozen) {
                    x += this.scroller.scrollLeft;
                }
                col = this._sheet._grid._columns.locate(0, col, function (w) {
                    return Math.abs(x - w) <= RESIZE_HANDLE_WIDTH / 2;
                });
                return col !== null && !this._sheet.isHiddenColumn(col) ? col : null;
            },
            isRowResizer: function (y, pane, row) {
                y -= this._sheet._grid._headerHeight;
                if (!pane._grid.rows.frozen) {
                    y += this.scroller.scrollTop;
                }
                row = this._sheet._grid._rows.locate(0, row, function (h) {
                    return Math.abs(y - h) <= RESIZE_HANDLE_WIDTH / 2;
                });
                return row !== null && !this._sheet.isHiddenRow(row) ? row : null;
            },
            isFilterIcon: function (x, y, pane, ref) {
                var self = this;
                var theGrid = pane._grid;
                var scrollTop = theGrid.rows.frozen ? 0 : self.scroller.scrollTop;
                var scrollLeft = theGrid.columns.frozen ? 0 : self.scroller.scrollLeft;
                x -= self._sheet._grid._headerWidth - scrollLeft;
                y -= self._sheet._grid._headerHeight - scrollTop;
                return kendo.util.withExit(function (exit) {
                    self._sheet.forEachFilterHeader(ref, function (ref) {
                        var rect = self._rectangle(pane, ref);
                        if (pane.filterIconRect(rect).intersects(x, y)) {
                            exit(true);
                        }
                    });
                });
            },
            isAutoFill: function (x, y, pane) {
                var selection = this._sheet.select();
                if (selection.size > 1) {
                    return false;
                }
                x -= this._sheet._grid._headerWidth;
                y -= this._sheet._grid._headerHeight;
                if (!pane._grid.columns.frozen) {
                    x += this.scroller.scrollLeft;
                }
                if (!pane._grid.rows.frozen) {
                    y += this.scroller.scrollTop;
                }
                var rectangle = this._rectangle(pane, selection);
                return Math.abs(rectangle.right - x) < 8 && Math.abs(rectangle.bottom - y) < 8;
            },
            isEditButton: function (x, y, pane) {
                var ed = this._sheet.activeCellCustomEditor();
                if (ed) {
                    var r = this.activeCellRectangle();
                    if (y >= r.top && y <= r.bottom) {
                        return pane._editorInLastColumn ? x < r.left && x >= r.left - EDIT_BUTTON_WIDTH : x > r.right && x <= r.right + EDIT_BUTTON_WIDTH;
                    }
                }
            },
            drawingAt: function (x, y, pane) {
                x -= this._sheet._grid._headerWidth;
                y -= this._sheet._grid._headerHeight;
                if (!pane._grid.columns.frozen) {
                    x += this.scroller.scrollLeft;
                }
                if (!pane._grid.rows.frozen) {
                    y += this.scroller.scrollTop;
                }
                var sheet = this._sheet;
                var drawings = this._sheet._drawings;
                for (var i = drawings.length; --i >= 0;) {
                    var d = drawings[i];
                    var box = sheet.drawingBoundingBox(d);
                    if (box.intersects(x, y)) {
                        return {
                            drawing: d,
                            drx: box.left - x,
                            dry: box.top - y
                        };
                    }
                }
            },
            objectAt: function (x, y, noDrawing) {
                var grid = this._sheet._grid;
                var object, pane;
                if (x < 0 || y < 0 || x > this.scroller.clientWidth || y > this.scroller.clientHeight) {
                    object = { type: 'outside' };
                } else if (x < grid._headerWidth && y < grid._headerHeight) {
                    object = { type: 'topcorner' };
                } else {
                    pane = this.paneAt(x, y);
                    if (!pane) {
                        object = { type: 'outside' };
                    } else {
                        if (!noDrawing) {
                            var drawing = this.drawingAt(x, y, pane);
                            if (drawing) {
                                return {
                                    type: 'drawing',
                                    drawing: drawing.drawing,
                                    drx: drawing.drx,
                                    dry: drawing.dry,
                                    pane: pane,
                                    startX: x,
                                    startY: y
                                };
                            }
                        }
                        var row = pane._grid.rows.indexVisible(y, this.scroller.scrollTop);
                        var column = pane._grid.columns.indexVisible(x, this.scroller.scrollLeft);
                        var type = 'cell';
                        var ref = new CellRef(row, column);
                        var selecting = this._sheet.selectionInProgress();
                        if (this.isAutoFill(x, y, pane)) {
                            type = 'autofill';
                        } else if (this.isFilterIcon(x, y, pane, ref)) {
                            type = 'filtericon';
                        } else if (!selecting && x < grid._headerWidth) {
                            type = 'rowheader';
                            if ((row = this.isRowResizer(y, pane, row)) !== null) {
                                ref = new CellRef(row, -Infinity);
                                type = 'rowresizehandle';
                            }
                        } else if (!selecting && y < grid._headerHeight) {
                            type = 'columnheader';
                            if ((column = this.isColumnResizer(x, pane, column)) !== null) {
                                ref = new CellRef(-Infinity, column);
                                type = 'columnresizehandle';
                            }
                        } else if (this.isEditButton(x, y, pane)) {
                            type = 'editor';
                        }
                        if (type == 'cell') {
                            this._sheet.forEachMergedCell(ref, function (merged) {
                                ref = merged.topLeft;
                            });
                        }
                        object = {
                            type: type,
                            ref: ref
                        };
                    }
                }
                object.pane = pane;
                object.x = x;
                object.y = y;
                return object;
            },
            paneAt: function (x, y) {
                return this.panes.filter(function paneLocationWithin(pane) {
                    var grid = pane._grid;
                    return within(y, grid.top, grid.bottom) && within(x, grid.left, grid.right);
                })[0];
            },
            containingPane: function (cell) {
                return this.panes.filter(function (pane) {
                    if (pane._grid.contains(cell)) {
                        return true;
                    }
                    return false;
                })[0];
            },
            cellRectangle: function (cell) {
                var theGrid = this.containingPane(cell)._grid;
                var rectangle = this._sheet._grid.rectangle(cell);
                return rectangle.offset(theGrid.headerWidth - (theGrid.columns.frozen ? 0 : this.scroller.scrollLeft), theGrid.headerHeight - (theGrid.rows.frozen ? 0 : this.scroller.scrollTop));
            },
            refresh: function (reason) {
                var sheet = this._sheet;
                if (this.tabstrip) {
                    this.tabstrip.refreshTools(sheet.range(sheet.activeCell()));
                }
                if (reason.sheetSelection && this.sheetsbar) {
                    this.sheetsbar.renderSheets(this._workbook.sheets(), this._workbook.sheetIndex(this._sheet));
                }
                this._resize();
                this.viewSize[0].style.height = sheet._grid.totalHeight() + 'px';
                this.viewSize[0].style.width = sheet._grid.totalWidth() + 'px';
                if (reason.layout) {
                    var frozenColumns = sheet.frozenColumns();
                    var frozenRows = sheet.frozenRows();
                    this.panes = [this._pane(frozenRows, frozenColumns)];
                    if (frozenColumns > 0) {
                        this.panes.push(this._pane(frozenRows, 0, null, frozenColumns));
                    }
                    if (frozenRows > 0) {
                        this.panes.push(this._pane(0, frozenColumns, frozenRows, null));
                    }
                    if (frozenRows > 0 && frozenColumns > 0) {
                        this.panes.push(this._pane(0, 0, frozenRows, frozenColumns));
                    }
                }
                if (reason.filter) {
                    this._destroyFilterMenu();
                }
                if (reason.activeCell) {
                    this._focus = sheet.activeCell().toRangeRef();
                }
            },
            createFilterMenu: function (column) {
                if (this._filterMenu && this._filterMenu.options.column == column) {
                    return this._filterMenu;
                }
                this._destroyFilterMenu();
                var sheet = this._sheet;
                var ref = sheet.filter().ref;
                var range = new kendo.spreadsheet.Range(ref, sheet);
                var element = $('<div />').appendTo(this.element);
                var options = {
                    column: column,
                    range: range
                };
                var filterMenu = new kendo.spreadsheet.FilterMenu(element, options);
                this._filterMenu = filterMenu;
                return filterMenu;
            },
            selectClipboardContents: function () {
                if (!this.isClipboardDeactivated) {
                    this.clipboard.focus();
                    selectElementContents(this.clipboard[0]);
                }
            },
            scrollIntoView: function (cell) {
                var willScroll = false;
                var theGrid = this.containingPane(cell)._grid;
                var boundaries = theGrid.scrollBoundaries(cell);
                var scroller = this.scroller;
                var scrollTop = theGrid.rows.frozen ? 0 : scroller.scrollTop;
                var scrollLeft = theGrid.columns.frozen ? 0 : scroller.scrollLeft;
                if (boundaries.top < scrollTop) {
                    willScroll = true;
                    scroller.scrollTop = boundaries.scrollTop;
                }
                if (boundaries.bottom > scrollTop) {
                    willScroll = true;
                    scroller.scrollTop = boundaries.scrollBottom;
                }
                if (boundaries.left < scrollLeft) {
                    willScroll = true;
                    scroller.scrollLeft = boundaries.scrollLeft;
                }
                if (boundaries.right > scrollLeft) {
                    willScroll = true;
                    scroller.scrollLeft = boundaries.scrollRight;
                }
                return willScroll;
            },
            _destroyDialog: function () {
                this._dialogs.pop();
            },
            openCustomEditor: function () {
                var self = this;
                var cell = self._sheet.activeCell().first();
                var editor = self._sheet.activeCellCustomEditor();
                var range = self._sheet.range(cell);
                editor.edit({
                    range: range,
                    rect: self.activeCellRectangle(),
                    view: this,
                    validation: this._sheet.validation(cell),
                    callback: function (value, parse) {
                        self._executeCommand({
                            command: 'EditCommand',
                            options: {
                                operatingRange: range,
                                property: parse ? 'input' : 'value',
                                value: value
                            }
                        });
                    }
                });
            },
            openDialog: function (name, options) {
                var sheet = this._sheet;
                return sheet.withCultureDecimals(function () {
                    var dialog = kendo.spreadsheet.dialogs.create(name, options);
                    if (dialog) {
                        dialog.bind('action', this._executeCommand.bind(this));
                        dialog.bind('deactivate', this._destroyDialog.bind(this));
                        this._dialogs.push(dialog);
                        var ref = sheet.activeCell();
                        var range = new kendo.spreadsheet.Range(ref, sheet);
                        dialog.open(range);
                        return dialog;
                    }
                }.bind(this));
            },
            showError: function (options, reopenEditor) {
                var errorMessages = this.options.messages.errors;
                var focusButton = function (e) {
                    var cont = e.sender.dialog().element;
                    cont.find('.k-button:first').focus();
                    cont.find('.k-button, input').on('keydown', function (ev) {
                        if (ev.keyCode == kendo.keys.ESC) {
                            e.sender.close();
                        }
                    });
                };
                var onClose = function (e) {
                    var dlg = e.sender;
                    this.selectClipboardContents();
                    if (dlg._retry && reopenEditor) {
                        reopenEditor();
                    }
                }.bind(this);
                if (kendo.spreadsheet.dialogs.registered(options.type)) {
                    var dialogOptions = { close: onClose };
                    if (options.type === 'validationError') {
                        dialogOptions = $.extend(dialogOptions, {
                            title: options.title || 'Error',
                            text: options.body ? options.body : errorMessages[options.type],
                            activate: focusButton
                        });
                    }
                    this.openDialog(options.type, dialogOptions);
                } else {
                    this.openDialog('message', {
                        title: options.title || 'Error',
                        text: options.body ? options.body : errorMessages[options.type],
                        activate: focusButton,
                        close: onClose
                    });
                }
            },
            destroy: function () {
                this._dialogs.forEach(function (dialog) {
                    dialog.destroy();
                });
                this.cellContextMenu.destroy();
                this.rowHeaderContextMenu.destroy();
                this.colHeaderContextMenu.destroy();
                if (this.tabstrip) {
                    this.tabstrip.destroy();
                }
                this._destroyFilterMenu();
            },
            _destroyFilterMenu: function () {
                if (this._filterMenu) {
                    this._filterMenu.destroy();
                    this._filterMenu = undefined;
                    this._filterMenuColumn = undefined;
                }
            },
            render: function (reason) {
                if (!this.element.is(':visible')) {
                    return;
                }
                var sheet = this._sheet;
                var focus = sheet.focus();
                if (focus && this.scrollIntoView(focus)) {
                    return;
                }
                var resizeDirection = !sheet.resizingInProgress() ? 'none' : sheet.resizeHandlePosition().col === -Infinity ? 'column' : 'row';
                this.wrapper.toggleClass(viewClassNames.editContainer, this.editor.isActive()).toggleClass(viewClassNames.horizontalResize, resizeDirection == 'row').toggleClass(viewClassNames.verticalResize, resizeDirection == 'column');
                var grid = sheet._grid;
                var scroller = this.scroller;
                var result = this.panes.map(function (pane) {
                    return pane.render(scroller);
                });
                var topCorner = kendo.dom.element('div', {
                    style: {
                        width: grid._headerWidth + 'px',
                        height: grid._headerHeight + 'px'
                    },
                    className: View.classNames.topCorner
                });
                result.push(topCorner);
                if (sheet.resizeHandlePosition() && sheet.resizeHintPosition()) {
                    result.push(this.renderResizeHint());
                }
                this.tree.render(result);
                var scrollbar = kendo.support.scrollbar();
                $(this.container).css({
                    width: this.wrapper[0].clientWidth - scrollbar,
                    height: this.wrapper[0].clientHeight - scrollbar
                });
                if (this.editor.isActive()) {
                    this.editor.toggleTooltip(this.activeCellRectangle());
                } else if (!(reason.resize || reason.scroll || reason.comment || sheet.selectionInProgress() || sheet.resizingInProgress() || sheet.draggingInProgress() || sheet.isInEditMode())) {
                    this.renderClipboardContents();
                }
            },
            renderResizeHint: function () {
                var sheet = this._sheet;
                var ref = sheet.resizeHandlePosition();
                var horizontal = ref.col !== -Infinity;
                var style;
                if (horizontal) {
                    style = {
                        height: this.scroller.clientHeight + 'px',
                        width: RESIZE_HANDLE_WIDTH + 'px',
                        left: sheet.resizeHintPosition().x + 'px',
                        top: '0px'
                    };
                } else {
                    style = {
                        height: RESIZE_HANDLE_WIDTH + 'px',
                        width: this.scroller.clientWidth + 'px',
                        top: sheet.resizeHintPosition().y + 'px',
                        left: '0px'
                    };
                }
                var classNames = Pane.classNames;
                return kendo.dom.element('div', {
                    className: classNames.resizeHint + (!horizontal ? ' ' + classNames.resizeHintVertical : ''),
                    style: style
                }, [
                    kendo.dom.element('div', { className: classNames.resizeHintHandle }),
                    kendo.dom.element('div', { className: classNames.resizeHintMarker })
                ]);
            },
            renderClipboardContents: function () {
                var sheet = this._sheet;
                var grid = sheet._grid;
                var selection = grid.normalize(sheet.select().toRangeRef());
                var status = this._workbook.clipboard().canCopy();
                if (status.canCopy === false && status.multiSelection) {
                    this.clipboardContents.render([]);
                    this.selectClipboardContents();
                    return;
                }
                selection = sheet.trim(selection);
                var table = new HtmlTable();
                var selectionView = grid.rangeDimensions(selection);
                selectionView.rows.forEach(function (height) {
                    table.addRow(height);
                });
                selectionView.columns.forEach(function (width) {
                    table.addColumn(width);
                });
                var tmp = sheet._getMergedCells(selection);
                var primaryMergedCells = tmp.primary;
                var secondaryMergedCells = tmp.secondary;
                sheet.forEach(selection, function (row, col, cell) {
                    var location = new CellRef(row, col).print();
                    if (!secondaryMergedCells[location]) {
                        var td = addCell(table, row - selection.topLeft.row, cell);
                        var mergedCell = primaryMergedCells[location];
                        if (mergedCell) {
                            td.attr.colspan = mergedCell.width();
                            td.attr.rowspan = mergedCell.height();
                        }
                    }
                });
                this.clipboardContents.render([table.toDomTree(0, 0, 'kendo-clipboard-' + this._workbook.clipboard()._uid)]);
                this.selectClipboardContents();
            },
            _pane: function (row, column, rowCount, columnCount) {
                var pane = new Pane(this._sheet, this._sheet._grid.pane({
                    row: row,
                    column: column,
                    rowCount: rowCount,
                    columnCount: columnCount
                }));
                pane.refresh(this.scroller.clientWidth, this.scroller.clientHeight);
                return pane;
            },
            forceScrollerStackingOrder: function (value) {
                $(this.scroller).css('z-index', value);
            }
        });
        var paneClassNames = {
            cell: 'k-spreadsheet-cell',
            vaxis: 'k-spreadsheet-vaxis',
            haxis: 'k-spreadsheet-haxis',
            vborder: 'k-spreadsheet-vborder',
            hborder: 'k-spreadsheet-hborder',
            rowHeader: 'k-spreadsheet-row-header',
            columnHeader: 'k-spreadsheet-column-header',
            pane: 'k-spreadsheet-pane',
            data: 'k-spreadsheet-data',
            mergedCell: 'k-spreadsheet-merged-cell',
            mergedCellsWrapper: 'k-merged-cells-wrapper',
            activeCell: 'k-spreadsheet-active-cell',
            selection: 'k-spreadsheet-selection',
            selectionWrapper: 'k-selection-wrapper',
            autoFillWrapper: 'k-auto-fill-wrapper',
            single: 'k-single',
            top: 'k-top',
            right: 'k-right',
            bottom: 'k-bottom',
            left: 'k-left',
            resizeHandle: 'k-resize-handle',
            columnResizeHandle: 'k-column-resize-handle',
            rowResizeHandle: 'k-row-resize-handle',
            resizeHint: 'k-resize-hint',
            resizeHintHandle: 'k-resize-hint-handle',
            resizeHintMarker: 'k-resize-hint-marker',
            resizeHintVertical: 'k-resize-hint-vertical',
            selectionHighlight: 'k-spreadsheet-selection-highlight',
            series: [
                'k-series-a',
                'k-series-b',
                'k-series-c',
                'k-series-d',
                'k-series-e',
                'k-series-f'
            ]
        };
        var Pane = kendo.Class.extend({
            init: function (sheet, grid) {
                this._sheet = sheet;
                this._grid = grid;
            },
            refresh: function (width, height) {
                this._grid.refresh(width, height);
            },
            isVisible: function (scrollLeft, scrollTop, ref) {
                return this._grid.view(scrollLeft, scrollTop).ref.intersects(ref);
            },
            render: function (scroller) {
                var scrollLeft = scroller.scrollLeft;
                var scrollTop = scroller.scrollTop;
                if (scrollTop < 0) {
                    scrollTop = 0;
                }
                if (scrollLeft < 0) {
                    scrollLeft = 0;
                }
                var classNames = Pane.classNames;
                var sheet = this._sheet;
                var grid = this._grid;
                var view = grid.view(scrollLeft, scrollTop);
                this._currentView = view;
                this._currentRect = this._rectangle(view.ref);
                this._selectedHeaders = sheet.selectedHeaders();
                var children = [];
                children.push(this.renderData());
                if (!sheet._activeDrawing) {
                    children.push(this.renderSelection(scroller));
                }
                children.push(this.renderAutoFill());
                children.push(this.renderEditorSelection());
                children.push(this.renderFilterHeaders());
                if (grid.hasRowHeader) {
                    var rowHeader = kendo.dom.element('div', {
                        className: classNames.rowHeader,
                        style: {
                            width: grid.headerWidth + 'px',
                            top: view.rowOffset + 'px'
                        }
                    });
                    children.push(rowHeader);
                    sheet.forEach(view.ref.leftColumn(), function (row) {
                        if (!sheet.isHiddenRow(row)) {
                            var text = row + 1, height = sheet.rowHeight(row);
                            rowHeader.children.push(kendo.dom.element('div', {
                                className: this.headerClassName(row, 'row'),
                                style: {
                                    width: grid.headerWidth + 'px',
                                    height: height + 'px'
                                }
                            }, [kendo.dom.element('div', { className: 'k-vertical-align-center' }, [kendo.dom.text(text + '')])]));
                        }
                    }.bind(this));
                }
                if (grid.hasColumnHeader) {
                    var columnHeader = kendo.dom.element('div', {
                        className: classNames.columnHeader,
                        style: {
                            top: '0px',
                            left: view.columnOffset + 'px',
                            width: this._currentRect.width + 'px',
                            height: grid.headerHeight + 'px'
                        }
                    });
                    children.push(columnHeader);
                    var left = 0;
                    sheet.forEach(view.ref.topRow(), function (row, col) {
                        if (!sheet.isHiddenColumn(col)) {
                            var text = kendo.spreadsheet.Ref.display(null, Infinity, col), width = sheet.columnWidth(col);
                            columnHeader.children.push(kendo.dom.element('div', {
                                className: this.headerClassName(col, 'col'),
                                style: {
                                    position: 'absolute',
                                    left: left + 'px',
                                    width: width + 'px',
                                    height: grid.headerHeight + 'px'
                                }
                            }, [kendo.dom.element('div', { className: 'k-vertical-align-center' }, [kendo.dom.text(text + '')])]));
                            left += width;
                        }
                    }.bind(this));
                }
                if (sheet.resizeHandlePosition() && (grid.hasColumnHeader || grid.hasRowHeader)) {
                    if (!sheet.resizeHintPosition()) {
                        this.renderResizeHandle(children);
                    }
                }
                var paneClasses = [classNames.pane];
                if (grid.hasColumnHeader) {
                    paneClasses.push(classNames.top);
                }
                if (grid.hasRowHeader) {
                    paneClasses.push(classNames.left);
                }
                return kendo.dom.element('div', {
                    style: grid.style,
                    className: paneClasses.join(' ')
                }, children);
            },
            headerClassName: function (index, type) {
                var selectedHeaders = this._selectedHeaders;
                var itemSelection;
                var allHeaders;
                if (type === 'row') {
                    itemSelection = selectedHeaders.rows[index];
                    allHeaders = selectedHeaders.allRows;
                } else {
                    itemSelection = selectedHeaders.cols[index];
                    allHeaders = selectedHeaders.allCols;
                }
                var className = itemSelection || (selectedHeaders.all ? 'full' : allHeaders ? 'partial' : 'none');
                if (className) {
                    className = 'k-selection-' + className;
                }
                return className;
            },
            renderData: function () {
                var sheet = this._sheet;
                var view = this._currentView;
                var cont = kendo.dom.element('div', {
                    className: Pane.classNames.data,
                    style: {
                        position: 'relative',
                        left: view.columnOffset + 'px',
                        top: view.rowOffset + 'px'
                    }
                });
                var rect = this._currentRect;
                var layout = kendo.spreadsheet.draw.doLayout(sheet, view.ref, { forScreen: true }), prev;
                var showGridLines = sheet._showGridLines;
                if (showGridLines) {
                    prev = null;
                    layout.xCoords.forEach(function (x) {
                        if (x !== prev) {
                            prev = x;
                            cont.children.push(kendo.dom.element('div', {
                                className: paneClassNames.vaxis,
                                style: {
                                    left: x + 'px',
                                    height: rect.height + 'px',
                                    borderColor: sheet.gridLinesColor()
                                }
                            }));
                        }
                    });
                    prev = null;
                    layout.yCoords.forEach(function (y) {
                        if (y !== prev) {
                            prev = y;
                            cont.children.push(kendo.dom.element('div', {
                                className: paneClassNames.haxis,
                                style: {
                                    top: y + 'px',
                                    width: rect.width + 'px',
                                    borderColor: sheet.gridLinesColor()
                                }
                            }));
                        }
                    });
                }
                var borders = kendo.spreadsheet.draw.Borders();
                var activeCellRange = sheet.activeCell().toRangeRef();
                var activeCell = activeCellRange.topLeft;
                layout.cells.forEach(function (cell) {
                    var cls = null;
                    var absRow = cell.row + view.ref.topLeft.row;
                    var absCol = cell.col + view.ref.topLeft.col;
                    if (sheet._activeDrawing) {
                        var ref = sheet._activeDrawing.topLeftCell;
                        if (ref && ref.row == absRow && ref.col == absCol) {
                            cls = 'k-spreadsheet-drawing-anchor-cell';
                        }
                    } else if (absRow == activeCell.row && absCol == activeCell.col) {
                        cls = [Pane.classNames.activeCell].concat(this._activeFormulaColor(), this._directionClasses(activeCellRange));
                        if (sheet.singleCellSelection()) {
                            cls.push(Pane.classNames.single);
                        }
                        cls = cls.join(' ');
                    }
                    borders.add(cell);
                    drawCell(cont.children, cell, cls, showGridLines);
                    if (cell.comment && sheet._commentRef && absRow == sheet._commentRef.row && absCol == sheet._commentRef.col) {
                        var ttOffset = 4;
                        var div = kendo.dom.element('div', {
                            className: 'k-tooltip k-spreadsheet-cell-comment',
                            style: {
                                left: cell.right + ttOffset + 'px',
                                top: cell.top + 'px'
                            }
                        }, [kendo.dom.text(cell.comment)]);
                        cont.children.push(div);
                    }
                }, this);
                borders.vert.forEach(function (a) {
                    a.forEach(function (b) {
                        if (!b.rendered) {
                            b.rendered = true;
                            var style = {
                                left: b.x + 'px',
                                top: b.top + 'px',
                                height: b.bottom - b.top + 1 + 'px',
                                borderWidth: b.size + 'px',
                                borderColor: b.color
                            };
                            if (b.size != 1) {
                                style.transform = 'translateX(-' + (b.size - 1) / 2 + 'px)';
                            }
                            cont.children.push(kendo.dom.element('div', {
                                className: paneClassNames.vborder,
                                style: style
                            }));
                        }
                    });
                });
                borders.horiz.forEach(function (a) {
                    a.forEach(function (b) {
                        if (!b.rendered) {
                            b.rendered = true;
                            var style = {
                                top: b.y + 'px',
                                left: b.left + 'px',
                                width: b.right - b.left + 'px',
                                borderWidth: b.size + 'px',
                                borderColor: b.color
                            };
                            if (b.size != 1) {
                                style.transform = 'translateY(-' + (b.size - 1) / 2 + 'px)';
                            }
                            cont.children.push(kendo.dom.element('div', {
                                className: paneClassNames.hborder,
                                style: style
                            }));
                        }
                    });
                });
                this.renderDrawings(layout, cont.children);
                return cont;
            },
            renderDrawings: function (layout, container) {
                var sheet = this._sheet;
                var workbook = sheet._workbook;
                layout.drawings.forEach(function (d) {
                    var drawing = d.drawing;
                    var box = d.box;
                    var div = box.toDiv('k-spreadsheet-drawing');
                    if (drawing.image) {
                        div.children.push(kendo.dom.element('div', {
                            className: 'k-spreadsheet-drawing-image',
                            style: {
                                backgroundImage: 'url(\'' + workbook.imageUrl(drawing.image) + '\')',
                                opacity: drawing.opacity
                            }
                        }));
                    }
                    if (drawing === sheet._activeDrawing) {
                        div.attr.className += ' k-spreadsheet-active-drawing';
                        drawingResizeHandles(div.children);
                    }
                    container.push(div);
                });
            },
            renderResizeHandle: function (container) {
                var sheet = this._sheet;
                var ref = sheet.resizeHandlePosition();
                var rectangle = this._rectangle(ref);
                var classNames = [Pane.classNames.resizeHandle];
                var style;
                if (ref.col !== -Infinity) {
                    if (this._grid.rows._start > 0) {
                        return;
                    }
                    style = {
                        height: this._grid.headerHeight + 'px',
                        width: RESIZE_HANDLE_WIDTH + 'px',
                        left: rectangle.right - RESIZE_HANDLE_WIDTH / 2 + 'px',
                        top: '0px'
                    };
                    classNames.push(viewClassNames.horizontalResize);
                } else {
                    if (this._grid.columns._start > 0) {
                        return;
                    }
                    style = {
                        height: RESIZE_HANDLE_WIDTH + 'px',
                        width: this._grid.headerWidth + 'px',
                        top: rectangle.bottom - RESIZE_HANDLE_WIDTH / 2 + 'px',
                        left: '0px'
                    };
                    classNames.push(viewClassNames.verticalResize);
                }
                container.push(kendo.dom.element('div', {
                    className: classNames.join(' '),
                    style: style
                }));
            },
            filterIconRect: function (rect) {
                var BUTTON_SIZE = 16;
                var BUTTON_OFFSET = 3;
                return new kendo.spreadsheet.Rectangle(rect.right - BUTTON_SIZE - BUTTON_OFFSET, rect.top + BUTTON_OFFSET, BUTTON_SIZE, BUTTON_SIZE);
            },
            renderFilterHeaders: function () {
                var sheet = this._sheet;
                var children = [];
                var classNames = View.classNames;
                var filter = sheet.filter();
                function icon(className) {
                    return kendo.dom.element('span', { className: classNames.icon + ' ' + className });
                }
                function filterButton(classNames, position, index) {
                    var style = {
                        left: position.left + 'px',
                        top: position.top + 'px'
                    };
                    var filtered = filter && filter.columns.some(function (c) {
                        return c.index === index;
                    });
                    var classes = classNames.filterButton;
                    if (filtered) {
                        classes += ' ' + classNames.filterButtonActive;
                    }
                    var button = kendo.dom.element('span', {
                        className: classes,
                        style: style
                    }, [icon(classNames.iconFilterDefault)]);
                    return button;
                }
                if (filter) {
                    this._addDiv(children, filter.ref, classNames.filterRange);
                }
                sheet.forEachFilterHeader(this._currentView.ref, function (ref) {
                    var rect = this._rectangle(ref);
                    var position = this.filterIconRect(rect);
                    var column = this._sheet.filterColumn(ref);
                    var button = filterButton(classNames, position, column);
                    children.push(button);
                }.bind(this));
                return kendo.dom.element('div', { className: classNames.filterHeadersWrapper }, children);
            },
            renderEditorSelection: function () {
                var classNames = Pane.classNames;
                var sheet = this._sheet;
                var selections = [];
                sheet._formulaSelections.forEach(function (range) {
                    var ref = range.ref;
                    if (ref === kendo.spreadsheet.NULLREF) {
                        return;
                    }
                    this._addDiv(selections, ref, classNames.selectionHighlight + ' ' + range.colorClass);
                }.bind(this));
                return kendo.dom.element('div', { className: classNames.selectionWrapper }, selections);
            },
            renderSelection: function (scroller) {
                var classNames = Pane.classNames;
                var selections = [];
                var selectionClasses = [classNames.selection];
                var sheet = this._sheet;
                var activeCell = sheet.activeCell().toRangeRef();
                var selection = sheet.select();
                selectionClasses = selectionClasses.concat(this._activeFormulaColor());
                if (selection.size() === 1) {
                    selectionClasses.push('k-single-selection');
                }
                if (this._sheet.autoFillPunch()) {
                    selectionClasses.push('k-dim-auto-fill-handle');
                }
                selection.forEach(function (ref) {
                    if (ref !== kendo.spreadsheet.NULLREF) {
                        this._addDiv(selections, ref, selectionClasses.join(' '));
                    }
                }.bind(this));
                this._renderCustomEditorButton(selections, activeCell, scroller);
                return kendo.dom.element('div', { className: classNames.selectionWrapper }, selections);
            },
            renderAutoFill: function () {
                var autoFillRectangle = [];
                if (this._sheet.autoFillInProgress()) {
                    var autoFillRef = this._sheet.autoFillRef();
                    var punch = this._sheet.autoFillPunch();
                    var direction = this._sheet._autoFillDirection;
                    this._addDiv(autoFillRectangle, autoFillRef, 'k-auto-fill');
                    if (punch) {
                        this._addDiv(autoFillRectangle, punch, 'k-auto-fill-punch');
                    } else if (direction !== undefined) {
                        var ref, cssClass;
                        switch (direction) {
                        case 0:
                            ref = autoFillRef.bottomRight;
                            cssClass = 'k-auto-fill-br-hint';
                            break;
                        case 1:
                            ref = autoFillRef.bottomRight;
                            cssClass = 'k-auto-fill-br-hint';
                            break;
                        case 2:
                            ref = new CellRef(autoFillRef.topLeft.row, autoFillRef.bottomRight.col);
                            cssClass = 'k-auto-fill-tr-hint';
                            break;
                        case 3:
                            ref = new CellRef(autoFillRef.bottomRight.row, autoFillRef.topLeft.col);
                            cssClass = 'k-auto-fill-bl-hint';
                            break;
                        }
                        var rectangle = this._addDiv(autoFillRectangle, ref, cssClass);
                        if (rectangle) {
                            var hint = kendo.dom.element('span', { className: 'k-tooltip' }, [kendo.dom.text(this._sheet._autoFillHint)]);
                            rectangle.children.push(hint);
                        }
                    }
                }
                return kendo.dom.element('div', { className: Pane.classNames.autoFillWrapper }, autoFillRectangle);
            },
            _addDiv: function (collection, ref, className) {
                var view = this._currentView, div;
                if (view.ref.intersects(ref)) {
                    div = this._rectangle(ref).resize(1, 1).toDiv(className);
                    collection.push(div);
                }
                return div;
            },
            _renderCustomEditorButton: function (collection, ref, scroller) {
                var self = this;
                var sheet = self._sheet;
                var view = self._currentView;
                var columnCount = self._grid.columns._axis._count;
                var ed = sheet.activeCellCustomEditor();
                if (ed && view.ref.intersects(ref)) {
                    var rectangle = self._rectangle(ref);
                    sheet.forEach(ref.collapse(), function (row, col, cell) {
                        cell.left = rectangle.left;
                        cell.top = rectangle.top;
                        cell.width = rectangle.width;
                        cell.height = rectangle.height;
                        var btnClass = 'k-button k-spreadsheet-editor-button';
                        var isLastColumn = col == columnCount - 1 || self._buttonOutOfVisiblePane(row, col, scroller);
                        if (isLastColumn) {
                            btnClass += ' k-spreadsheet-last-column';
                        }
                        self._editorInLastColumn = isLastColumn;
                        var btn = kendo.dom.element('div', {
                            className: btnClass,
                            style: {
                                left: cell.left + (isLastColumn ? 0 : cell.width) + 'px',
                                top: cell.top + 'px',
                                height: cell.height + 'px'
                            }
                        });
                        if (ed.icon) {
                            btn.children.push(kendo.dom.element('span', { className: 'k-icon ' + ed.icon }));
                        }
                        collection.push(btn);
                    });
                }
            },
            _activeFormulaColor: function () {
                var activeFormulaSelection;
                var colorClasses = [];
                if (this._sheet.isInEditMode()) {
                    activeFormulaSelection = this._sheet._formulaSelections.filter(function (sel) {
                        return sel.active && sel.type == 'ref';
                    })[0];
                    if (activeFormulaSelection) {
                        colorClasses.push(activeFormulaSelection.colorClass);
                    }
                }
                return colorClasses;
            },
            _directionClasses: function (cell) {
                var cellClasses = [];
                var classNames = Pane.classNames;
                var view = this._currentView.ref;
                if (!cell.move(0, -1).intersects(view)) {
                    cellClasses.push(classNames.left);
                }
                if (!cell.move(-1, 0).intersects(view)) {
                    cellClasses.push(classNames.top);
                }
                if (!cell.move(0, 1).intersects(view)) {
                    cellClasses.push(classNames.right);
                }
                if (!cell.move(1, 0).intersects(view)) {
                    cellClasses.push(classNames.bottom);
                }
                return cellClasses;
            },
            _rectangle: function (ref) {
                return this._grid.boundingRectangle(ref.toRangeRef()).offset(-this._currentView.mergedCellLeft, -this._currentView.mergedCellTop);
            },
            _buttonOutOfVisiblePane: function (row, col, scroller) {
                var self = this;
                var theGrid = self._grid;
                var sheet = self._sheet;
                var ref = sheet.range(row, col)._ref;
                var boundaries = theGrid.scrollBoundaries(ref);
                var scrollLeft = theGrid.columns.frozen ? 0 : scroller.scrollLeft;
                if (boundaries.right + EDIT_BUTTON_WIDTH > scrollLeft || col + 1 === sheet.frozenColumns()) {
                    return true;
                }
            }
        });
        function drawingResizeHandles(container) {
            [
                'N',
                'NE',
                'E',
                'SE',
                'S',
                'SW',
                'W',
                'NW'
            ].forEach(function (direction) {
                container.push(kendo.dom.element('div', {
                    'className': 'k-spreadsheet-drawing-handle ' + direction,
                    'data-direction': direction
                }));
            });
        }
        kendo.spreadsheet.View = View;
        kendo.spreadsheet.Pane = Pane;
        kendo.spreadsheet.drawCell = drawCell;
        $.extend(true, View, { classNames: viewClassNames });
        $.extend(true, Pane, { classNames: paneClassNames });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/customeditors', [
        'kendo.core',
        'kendo.popup',
        'kendo.calendar',
        'kendo.listview',
        'spreadsheet/sheet'
    ], f);
}(function () {
    (function (kendo) {
        'use strict';
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var EDITORS = {};
        var registerEditor = kendo.spreadsheet.registerEditor = function (name, editor) {
            EDITORS[name] = editor;
        };
        kendo.spreadsheet.Sheet.prototype.activeCellCustomEditor = function () {
            var cell = this.activeCell().first();
            if (this.range(cell).enable()) {
                var val = this.validation(cell);
                var key = this._properties.get('editor', this._grid.cellRefIndex(cell));
                var editor;
                if (key != null) {
                    editor = EDITORS[key];
                } else if (val && val.showButton) {
                    key = '_validation_' + val.dataType;
                    editor = EDITORS[key];
                }
                if (typeof editor == 'function') {
                    editor = EDITORS[key] = editor();
                }
                return editor;
            }
        };
        registerEditor('_validation_date', function () {
            var context, calendar, popup;
            function create() {
                if (!calendar) {
                    calendar = $('<div>').kendoCalendar();
                    popup = $('<div>').kendoPopup();
                    calendar.appendTo(popup);
                    calendar = calendar.getKendoCalendar();
                    popup = popup.getKendoPopup();
                    calendar.bind('change', function () {
                        popup.close();
                        var date = calendar.value();
                        if (!context.range.format()) {
                            context.range.format('yyyy-mm-dd');
                        }
                        context.callback(kendo.spreadsheet.dateToNumber(date));
                    });
                }
                popup.setOptions({ anchor: context.view.element.find('.k-spreadsheet-editor-button') });
            }
            function open() {
                create();
                var date = context.range.value();
                if (date != null) {
                    calendar.value(kendo.spreadsheet.numberToDate(date));
                } else {
                    calendar.value(null);
                }
                var val = context.validation;
                if (val) {
                    var min = kendo.ui.Calendar.fn.options.min;
                    var max = kendo.ui.Calendar.fn.options.max;
                    if (/^(?:greaterThan|between)/.test(val.comparerType)) {
                        min = kendo.spreadsheet.numberToDate(val.from.value);
                    }
                    if (val.comparerType == 'between') {
                        max = kendo.spreadsheet.numberToDate(val.to.value);
                    }
                    if (val.comparerType == 'lessThan') {
                        max = kendo.spreadsheet.numberToDate(val.from.value);
                    }
                    calendar.setOptions({
                        disableDates: function (date) {
                            var from = val.from ? val.from.value | 0 : 0;
                            var to = val.to ? val.to.value | 0 : 0;
                            date = kendo.spreadsheet.dateToNumber(date) | 0;
                            return !kendo.spreadsheet.validation.validationComparers[val.comparerType](date, from, to);
                        },
                        min: min,
                        max: max
                    });
                } else {
                    calendar.setOptions({
                        disableDates: null,
                        min: null,
                        max: null
                    });
                }
                popup.open();
            }
            return {
                edit: function (options) {
                    context = options;
                    open();
                },
                icon: 'k-i-calendar'
            };
        });
        registerEditor('_validation_list', function () {
            var context, list, popup;
            function create() {
                if (!list) {
                    list = $('<ul class=\'k-list k-reset\'/>').kendoStaticList({
                        template: '#:value#',
                        selectable: true,
                        autoBind: false
                    });
                    popup = $('<div>').kendoPopup();
                    list.appendTo(popup);
                    popup = popup.getKendoPopup();
                    list = list.getKendoStaticList();
                    list.bind('change', function () {
                        popup.close();
                        var item = list.value()[0];
                        if (item) {
                            context.callback(item.value);
                        }
                    });
                }
                popup.setOptions({ anchor: context.view.element.find('.k-spreadsheet-editor-button') });
            }
            function open() {
                create();
                var items = context.validation.from.value;
                var data = [], add = function (el) {
                        data.push({ value: el });
                    };
                if (items instanceof kendo.spreadsheet.calc.runtime.Matrix) {
                    items.each(add);
                } else {
                    (items + '').split(/\s*,\s*/).forEach(add);
                }
                var dataSource = new kendo.data.DataSource({ data: data });
                list.setDataSource(dataSource);
                dataSource.read();
                popup.open();
            }
            return {
                edit: function (options) {
                    context = options;
                    open();
                },
                icon: 'k-i-arrow-60-down'
            };
        });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/grid', [
        'kendo.core',
        'spreadsheet/references'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var CellRef = kendo.spreadsheet.CellRef;
        var RangeRef = kendo.spreadsheet.RangeRef;
        var UnionRef = kendo.spreadsheet.UnionRef;
        var Rectangle = kendo.Class.extend({
            init: function Rectangle(left, top, width, height) {
                this.left = left;
                this.top = top;
                this.width = width;
                this.height = height;
                this.right = this.left + this.width;
                this.bottom = this.top + this.height;
            },
            offset: function (left, top) {
                return new Rectangle(this.left + left, this.top + top, this.width, this.height);
            },
            resize: function (width, height) {
                return new Rectangle(this.left, this.top, this.width + width, this.height + height);
            },
            intersects: function (x, y) {
                if (x instanceof Rectangle) {
                    return this.intersectsRect(x);
                }
                return this.left < x && x < this.left + this.width && this.top < y && y < this.top + this.height;
            },
            intersectsRect: function (b) {
                var a = this;
                return a.left <= b.right && b.left <= a.right && a.top <= b.bottom && b.top <= a.bottom;
            },
            toDiv: function (className) {
                return kendo.dom.element('div', {
                    className: className,
                    style: {
                        width: this.width + 'px',
                        height: this.height + 'px',
                        top: this.top + 'px',
                        left: this.left + 'px'
                    }
                });
            }
        });
        var Grid = kendo.Class.extend({
            init: function (rows, columns, rowCount, columnCount, headerHeight, headerWidth) {
                this.rowCount = rowCount;
                this.columnCount = columnCount;
                this._columns = columns;
                this._rows = rows;
                this._headerHeight = headerHeight;
                this._headerWidth = headerWidth;
            },
            isAxis: function (ref) {
                ref = ref.toRangeRef();
                var topLeft = ref.topLeft;
                var bottomRight = ref.bottomRight;
                return topLeft.row === 0 && bottomRight.row === this.rowCount - 1 || topLeft.col === 0 && bottomRight.col === this.columnCount - 1;
            },
            width: function (start, end) {
                return this._columns.sum(start, end);
            },
            height: function (start, end) {
                return this._rows.sum(start, end);
            },
            totalHeight: function () {
                return this._rows.total + this._headerHeight;
            },
            totalWidth: function () {
                return this._columns.total + this._headerWidth;
            },
            index: function (row, column) {
                return column * this.rowCount + row;
            },
            cellRef: function (index) {
                return new CellRef(index % this.rowCount, index / this.rowCount >> 0);
            },
            rowRef: function (row) {
                return new RangeRef(new CellRef(row, 0), new CellRef(row, this.columnCount - 1));
            },
            colRef: function (col) {
                return new RangeRef(new CellRef(0, col), new CellRef(this.rowCount - 1, col));
            },
            cellRefIndex: function (ref) {
                return this.index(ref.row, ref.col);
            },
            normalize: function (ref) {
                if (ref instanceof RangeRef) {
                    return new RangeRef(this.normalize(ref.topLeft), this.normalize(ref.bottomRight)).setSheet(ref.sheet, ref.hasSheet());
                }
                if (ref instanceof UnionRef) {
                    return ref.map(function (ref) {
                        return this.normalize(ref);
                    }, this);
                }
                if (ref instanceof CellRef) {
                    ref = ref.clone();
                    ref.col = Math.max(0, Math.min(this.columnCount - 1, ref.col));
                    ref.row = Math.max(0, Math.min(this.rowCount - 1, ref.row));
                }
                return ref;
            },
            rectangle: function (ref) {
                var topLeft = this.normalize(ref.topLeft);
                var bottomRight = this.normalize(ref.bottomRight);
                return new Rectangle(this.width(0, topLeft.col - 1), this.height(0, topLeft.row - 1), this.width(topLeft.col, bottomRight.col), this.height(topLeft.row, bottomRight.row));
            },
            pane: function (options) {
                return new PaneGrid(new kendo.spreadsheet.PaneAxis(this._rows, options.row, options.rowCount, this._headerHeight), new kendo.spreadsheet.PaneAxis(this._columns, options.column, options.columnCount, this._headerWidth), this);
            },
            rangeDimensions: function (rangeRef) {
                return {
                    rows: this._rows.values.iterator(rangeRef.topLeft.row, rangeRef.bottomRight.row),
                    columns: this._columns.values.iterator(rangeRef.topLeft.col, rangeRef.bottomRight.col)
                };
            },
            forEach: function (ref, callback) {
                var topLeft = this.normalize(ref.topLeft);
                var bottomRight = this.normalize(ref.bottomRight);
                for (var ci = topLeft.col; ci <= bottomRight.col; ci++) {
                    for (var ri = topLeft.row; ri <= bottomRight.row; ri++) {
                        callback(new CellRef(ri, ci));
                    }
                }
            },
            trim: function (ref, property) {
                var topLeft = this.normalize(ref.topLeft);
                var bottomRight = this.normalize(ref.bottomRight);
                var bottomRightRow = topLeft.row;
                var bottomRightCol = topLeft.col;
                for (var ci = topLeft.col; ci <= bottomRight.col; ci++) {
                    var start = this.index(topLeft.row, ci);
                    var end = this.index(bottomRight.row, ci);
                    var values = property.tree.intersecting(start, end);
                    if (values.length) {
                        var cell = this.cellRef(values[values.length - 1].end);
                        bottomRightRow = Math.max(bottomRightRow, cell.row);
                        bottomRightCol = ci;
                    }
                }
                return new RangeRef(ref.topLeft, new CellRef(Math.min(bottomRightRow, ref.bottomRight.row), bottomRightCol));
            }
        });
        var PaneGrid = kendo.Class.extend({
            init: function (rows, columns, grid) {
                this.rows = rows;
                this.columns = columns;
                this._grid = grid;
                this.headerHeight = rows.headerSize;
                this.headerWidth = columns.headerSize;
                this.hasRowHeader = columns.hasHeader;
                this.hasColumnHeader = rows.hasHeader;
            },
            refresh: function (width, height) {
                this.columns.viewSize(width);
                this.rows.viewSize(height);
                var x = this.columns.paneSegment();
                var y = this.rows.paneSegment();
                this.left = x.offset;
                this.top = y.offset;
                this.right = x.offset + x.length;
                this.bottom = y.offset + y.length;
                this.style = {
                    top: y.offset + 'px',
                    left: x.offset + 'px',
                    height: y.length + 'px',
                    width: x.length + 'px'
                };
            },
            view: function (left, top) {
                var rows = this.rows.visible(top);
                var columns = this.columns.visible(left);
                return {
                    rows: rows,
                    columns: columns,
                    rowOffset: rows.offset,
                    columnOffset: columns.offset,
                    mergedCellLeft: columns.start,
                    mergedCellTop: rows.start,
                    ref: new RangeRef(new CellRef(rows.values.start, columns.values.start), new CellRef(rows.values.end, columns.values.end))
                };
            },
            contains: function (ref) {
                return this.rows.contains(ref.topLeft.row, ref.bottomRight.row) && this.columns.contains(ref.topLeft.col, ref.bottomRight.col);
            },
            index: function (row, column) {
                return this._grid.index(row, column);
            },
            boundingRectangle: function (ref) {
                return this._grid.rectangle(ref);
            },
            cellRefIndex: function (ref) {
                return this._grid.cellRefIndex(ref);
            },
            scrollBoundaries: function (cell) {
                var position = this.boundingRectangle(cell);
                var boundaries = {
                    top: Math.max(0, position.top - this.top + (this.hasColumnHeader ? 0 : this.headerHeight)),
                    left: Math.max(0, position.left - this.left + (this.hasRowHeader ? 0 : this.headerWidth)),
                    right: position.right - this.columns._viewSize + this.headerWidth,
                    bottom: position.bottom - this.rows._viewSize + this.headerHeight
                };
                var widthCompensation = this.columns.defaultValue / 2;
                var heightCompensation = this.rows.defaultValue / 2;
                boundaries.scrollTop = boundaries.top - heightCompensation;
                boundaries.scrollBottom = boundaries.bottom + heightCompensation;
                boundaries.scrollLeft = boundaries.left - widthCompensation;
                boundaries.scrollRight = boundaries.right + widthCompensation;
                return boundaries;
            }
        });
        kendo.spreadsheet.Grid = Grid;
        kendo.spreadsheet.PaneGrid = PaneGrid;
        kendo.spreadsheet.Rectangle = Rectangle;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/axis', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var Axis = kendo.Class.extend({
            init: function (count, value) {
                this._value = value;
                this._count = count;
                this.values = new kendo.spreadsheet.RangeList(0, count - 1, value);
                this._hidden = new kendo.spreadsheet.RangeList(0, count - 1, 0);
                this.scrollBarSize = kendo.support.scrollbar();
                this._refresh();
            },
            adjust: function (start, delta) {
                if (delta < 0) {
                    this.values.copy(start - delta, this._count - 1, start);
                    this._hidden.copy(start - delta, this._count - 1, start);
                } else {
                    this.values.copy(start, this._count, start + delta);
                    this._hidden.copy(start, this._count, start + delta);
                    this.values.value(start, start + delta - 1, this._value);
                    this._hidden.value(start, start + delta - 1, 0);
                }
                this._refresh();
            },
            toJSON: function (field, positions) {
                var values = [];
                var iterator = this.values.iterator(0, this._count - 1);
                for (var idx = 0; idx < this._count; idx++) {
                    var value = iterator.at(idx);
                    var hidden = this._hidden.value(idx, idx);
                    if (value === this._value && !hidden) {
                        continue;
                    }
                    var position = positions[idx];
                    if (position === undefined) {
                        position = values.length;
                        var item = { index: idx };
                        item[field] = value;
                        if (hidden) {
                            item.hidden = hidden;
                        }
                        values.push(item);
                        positions[idx] = position;
                    }
                }
                return values;
            },
            fromJSON: function (field, values) {
                for (var idx = 0; idx < values.length; idx++) {
                    var el = values[idx];
                    var index = el.index;
                    if (index === undefined) {
                        index = idx;
                    }
                    var value = el[field];
                    if (value === 0) {
                        this._hidden.value(index, index, el.hidden || this._value);
                        this.value(index, index, 0);
                    } else {
                        this.value(index, index, value);
                    }
                }
            },
            hide: function (index) {
                if (!this.hidden(index)) {
                    var value = this.value(index, index);
                    this._hidden.value(index, index, value);
                    this.value(index, index, 0);
                }
            },
            hidden: function (index) {
                return this._hidden.value(index, index) !== 0;
            },
            includesHidden: function (start, end) {
                return this._hidden.intersecting(start, end).length > 1;
            },
            nextVisible: function (index) {
                var end = this._count - 1, i = index;
                while (++i <= end) {
                    if (!this.hidden(i)) {
                        return i;
                    }
                }
                return index;
            },
            nextPage: function (index, pageSize) {
                return this.index(this.sum(0, index - 1) + pageSize);
            },
            prevPage: function (index, pageSize) {
                return this.index(this.sum(0, index) - pageSize);
            },
            firstVisible: function () {
                var firstHidden = this._hidden.first();
                if (firstHidden.value === 0) {
                    return 0;
                } else {
                    return firstHidden.end + 1;
                }
            },
            lastVisible: function () {
                var lastHidden = this._hidden.last();
                if (lastHidden.value === 0) {
                    return this._count - 1;
                } else {
                    return lastHidden.start - 1;
                }
            },
            prevVisible: function (index) {
                var i = index;
                while (--i >= 0) {
                    if (!this.hidden(i)) {
                        return i;
                    }
                }
                return index;
            },
            unhide: function (index) {
                if (this.hidden(index)) {
                    var value = this._hidden.value(index, index);
                    this._hidden.value(index, index, 0);
                    this.value(index, index, value);
                }
            },
            value: function (start, end, value) {
                if (value !== undefined) {
                    this.values.value(start, end, value);
                    this._refresh();
                } else {
                    return this.values.iterator(start, end).at(0);
                }
            },
            sum: function (start, end) {
                var values = this.values.iterator(start, end);
                var sum = 0;
                for (var idx = start; idx <= end; idx++) {
                    sum += values.at(idx);
                }
                return sum;
            },
            locate: function (start, end, predicate) {
                var values = this.values.iterator(start, end);
                var sum = 0;
                for (var idx = start; idx <= end; idx++) {
                    sum += values.at(idx);
                    var val = predicate(sum);
                    if (val) {
                        return idx;
                    }
                }
                return null;
            },
            visible: function (start, end) {
                var startSegment = null;
                var endSegment = null;
                var lastPage = false;
                if (end >= this.total + this.scrollBarSize) {
                    lastPage = true;
                }
                var ranges = this._pixelValues.intersecting(start, end);
                startSegment = ranges[0];
                endSegment = ranges[ranges.length - 1];
                if (!startSegment) {
                    return {
                        values: this.values.iterator(0, 0),
                        offset: 0
                    };
                }
                var startOffset = start - startSegment.start;
                var startIndex = (startOffset / startSegment.value.value >> 0) + startSegment.value.start;
                var offset = startOffset - (startIndex - startSegment.value.start) * startSegment.value.value;
                var endOffset = end - endSegment.start;
                var endIndex = (endOffset / endSegment.value.value >> 0) + endSegment.value.start;
                if (endIndex > endSegment.value.end) {
                    endIndex = endSegment.value.end;
                }
                if (lastPage) {
                    offset += endSegment.value.value - (endOffset - (endIndex - endSegment.value.start) * endSegment.value.value);
                }
                offset = Math.min(-offset, 0);
                return {
                    values: this.values.iterator(startIndex, endIndex),
                    offset: offset
                };
            },
            index: function (value) {
                var index = 0;
                var iterator = this.values.iterator(0, this._count - 1);
                var current = iterator.at(0);
                while (current < value && index < this._count - 1) {
                    current += iterator.at(++index);
                }
                return index;
            },
            indexVisible: function (value) {
                var index = this.index(value);
                if (this.hidden(index)) {
                    index = this.prevVisible(index);
                }
                return index;
            },
            _refresh: function () {
                var current = 0;
                this._pixelValues = this.values.map(function (range) {
                    var start = current;
                    current += (range.end - range.start + 1) * range.value;
                    var end = current - 1;
                    return new kendo.spreadsheet.ValueRange(start, end, range);
                });
                this.total = current;
            },
            getState: function () {
                return {
                    values: this.values.getState(),
                    hidden: this._hidden.getState()
                };
            },
            setState: function (state) {
                this.values.setState(state.values);
                this._hidden.setState(state.hidden);
                this._refresh();
            }
        });
        var PaneAxis = kendo.Class.extend({
            init: function (axis, start, count, headerSize) {
                this._axis = axis;
                this._start = start;
                this._count = count;
                this.hasHeader = start === 0;
                this.headerSize = headerSize;
                this.defaultValue = axis._value;
                this.frozen = count > 0;
            },
            viewSize: function (viewSize) {
                this._viewSize = viewSize;
            },
            sum: function (start, end) {
                return this._axis.sum(start, end - 1);
            },
            start: function () {
                return this.sum(0, this._start);
            },
            size: function () {
                return this.sum(this._start, this._start + this._count);
            },
            index: function (value, offset) {
                return this._axis.index(value + (this.frozen ? 0 : offset) - this.headerSize);
            },
            indexVisible: function (value, offset) {
                return this._axis.indexVisible(value + (this.frozen ? 0 : offset) - this.headerSize);
            },
            paneSegment: function () {
                var offset = this.start();
                var length;
                if (!this.hasHeader) {
                    offset += this.headerSize;
                }
                if (this.frozen) {
                    length = this.size();
                    if (this.hasHeader) {
                        length += this.headerSize;
                    } else {
                        length -= this.headerSize;
                    }
                } else {
                    length = this._viewSize - offset;
                }
                return {
                    offset: offset,
                    length: length
                };
            },
            visible: function (offset) {
                var start = this.start();
                var size;
                if (this.frozen) {
                    size = this.size();
                    if (!this.hasHeader) {
                        size -= this.headerSize;
                    }
                } else {
                    size = this._viewSize - start - this.headerSize;
                    start += offset;
                }
                var result = this._axis.visible(start, start + size - 1);
                if (this.frozen) {
                    result.offset = 0;
                }
                result.start = start;
                if (this.hasHeader) {
                    result.offset += this.headerSize;
                    result.start -= this.headerSize;
                }
                return result;
            },
            contains: function (start, end) {
                if (this.frozen) {
                    if (start > this._start + this._count) {
                        return false;
                    }
                    if (end < this._start) {
                        return false;
                    }
                    return true;
                } else {
                    return end >= this._start;
                }
            }
        });
        kendo.spreadsheet.Axis = Axis;
        kendo.spreadsheet.PaneAxis = PaneAxis;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/filter', [
        'kendo.core',
        'kendo.data'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var Filter = kendo.spreadsheet.Filter = kendo.Class.extend({
            prepare: function () {
            },
            value: function (cell) {
                return cell.value;
            },
            matches: function () {
                throw new Error('The \'matches\' method is not implemented.');
            },
            toJSON: function () {
                throw new Error('The \'toJSON\' method is not implemented.');
            }
        });
        Filter.create = function (options) {
            var filter = options.filter;
            if (!filter) {
                throw new Error('Filter type not specified.');
            }
            var constructor = kendo.spreadsheet[filter.charAt(0).toUpperCase() + filter.substring(1) + 'Filter'];
            if (!constructor) {
                throw new Error('Filter type not recognized.');
            }
            return new constructor(options);
        };
        kendo.spreadsheet.ValueFilter = Filter.extend({
            _values: [],
            _dates: [],
            _blanks: false,
            init: function ValueFilter(options) {
                if (options.values !== undefined) {
                    this._values = options.values;
                }
                if (options.blanks !== undefined) {
                    this._blanks = options.blanks;
                }
                if (options.dates !== undefined) {
                    this._dates = options.dates;
                }
            },
            value: function (cell) {
                var value = cell.value;
                if (this._dates.length > 0 && cell.format && typeof value === 'number') {
                    var type = kendo.spreadsheet.formatting.type(value, cell.format);
                    if (type === 'date') {
                        value = kendo.spreadsheet.numberToDate(value);
                    }
                }
                return value;
            },
            matches: function (value) {
                if (value === null || value === undefined) {
                    return this._blanks;
                }
                if (value instanceof Date) {
                    return this._dates.some(function (date) {
                        return date.year === value.getFullYear() && (date.month === undefined || date.month === value.getMonth()) && (date.day === undefined || date.day === value.getDate()) && (date.hours === undefined || date.hours === value.getHours()) && (date.minutes === undefined || date.minutes === value.getMinutes()) && (date.seconds === undefined || date.seconds === value.getSeconds());
                    });
                }
                return this._values.indexOf(value) >= 0;
            },
            toJSON: function () {
                return {
                    filter: 'value',
                    blanks: this._blanks,
                    values: this._values.slice(0)
                };
            }
        });
        kendo.spreadsheet.CustomFilter = Filter.extend({
            _logic: 'and',
            init: function CustomFilter(options) {
                if (options.logic !== undefined) {
                    this._logic = options.logic;
                }
                if (options.criteria === undefined) {
                    throw new Error('Must specify criteria.');
                }
                this._criteria = options.criteria;
                var expression = kendo.data.Query.filterExpr({
                    logic: this._logic,
                    filters: this._criteria
                }).expression;
                this._matches = new Function('d', 'return ' + expression);
            },
            matches: function (value) {
                if (value === null) {
                    return false;
                }
                return this._matches(value);
            },
            value: function (cell) {
                var value = cell.value;
                var criterionValue = this._criteria[0].value;
                var criterionType = criterionValue instanceof Date ? 'date' : typeof criterionValue;
                var valueType = typeof value;
                if (cell.format) {
                    valueType = kendo.spreadsheet.formatting.type(value, cell.format);
                }
                if (valueType != criterionType) {
                    if (criterionType == 'string') {
                        if (cell.format) {
                            value = kendo.spreadsheet.formatting.text(value, cell.format);
                        }
                        value = value + '';
                    }
                } else if (valueType == 'date') {
                    value = kendo.spreadsheet.numberToDate(value);
                }
                return value;
            },
            toJSON: function () {
                return {
                    filter: 'custom',
                    logic: this._logic,
                    criteria: this._criteria
                };
            }
        });
        kendo.spreadsheet.TopFilter = Filter.extend({
            init: function TopFilter(options) {
                this._type = options.type;
                this._value = options.value;
                this._values = [];
            },
            prepare: function (cells) {
                var values = cells.map(this.value).sort().filter(function (value, index, array) {
                    return index === 0 || value !== array[index - 1];
                });
                if (this._type === 'topNumber' || this._type == 'topPercent') {
                    values.sort(function (x, y) {
                        return y - x;
                    });
                } else {
                    values.sort(function (x, y) {
                        return x - y;
                    });
                }
                var count = this._value;
                if (this._type === 'topPercent' || this._type === 'bottomPercent') {
                    count = values.length * count / 100 >> 0;
                }
                this._values = values.slice(0, count);
            },
            matches: function (value) {
                return this._values.indexOf(value) >= 0;
            },
            toJSON: function () {
                return {
                    filter: 'top',
                    type: this._type,
                    value: this._value
                };
            }
        });
        kendo.spreadsheet.DynamicFilter = Filter.extend({
            init: function DynamicFilter(options) {
                this._type = options.type;
                this._predicate = this[options.type];
                if (typeof this._predicate !== 'function') {
                    throw new Error('DynamicFilter type \'' + options.type + '\' not recognized.');
                }
            },
            value: function (cell) {
                var value = cell.value;
                if (cell.format) {
                    var type = kendo.spreadsheet.formatting.type(value, cell.format);
                    if (type === 'date') {
                        value = kendo.spreadsheet.numberToDate(value);
                    }
                }
                return value;
            },
            prepare: function (cells) {
                var sum = 0;
                var count = 0;
                for (var ci = 0; ci < cells.length; ci++) {
                    var value = this.value(cells[ci]);
                    if (typeof value === 'number') {
                        sum += value;
                        count++;
                    }
                }
                if (count > 0) {
                    this._average = sum / count;
                } else {
                    this._average = 0;
                }
            },
            matches: function (value) {
                return this._predicate(value);
            },
            aboveAverage: function (value) {
                if (value instanceof Date) {
                    value = kendo.spreadsheet.dateToNumber(value);
                }
                if (typeof value !== 'number') {
                    return false;
                }
                return value > this._average;
            },
            belowAverage: function (value) {
                if (value instanceof Date) {
                    value = kendo.spreadsheet.dateToNumber(value);
                }
                if (typeof value !== 'number') {
                    return false;
                }
                return value < this._average;
            },
            tomorrow: function (value) {
                if (value instanceof Date) {
                    var tomorrow = kendo.date.addDays(kendo.date.today(), 1);
                    return kendo.date.getDate(value).getTime() === tomorrow.getTime();
                }
                return false;
            },
            today: function (value) {
                if (value instanceof Date) {
                    return kendo.date.isToday(value);
                }
                return false;
            },
            yesterday: function (value) {
                if (value instanceof Date) {
                    var yesterday = kendo.date.addDays(kendo.date.today(), -1);
                    return kendo.date.getDate(value).getTime() === yesterday.getTime();
                }
                return false;
            },
            nextWeek: function (value) {
                return sameWeek(kendo.date.addDays(kendo.date.today(), 7), value);
            },
            thisWeek: function (value) {
                return sameWeek(kendo.date.today(), value);
            },
            lastWeek: function (value) {
                return sameWeek(kendo.date.addDays(kendo.date.today(), -7), value);
            },
            nextMonth: function (value) {
                return sameMonth(value, 1);
            },
            thisMonth: function (value) {
                return sameMonth(value, 0);
            },
            lastMonth: function (value) {
                return sameMonth(value, -1);
            },
            nextQuarter: function (value) {
                if (value instanceof Date) {
                    var today = kendo.date.today();
                    var diff = quarter(value) - quarter(today);
                    return diff === 1 && today.getFullYear() === value.getFullYear() || diff == -3 && today.getFullYear() + 1 === value.getFullYear();
                }
                return false;
            },
            thisQuarter: function (value) {
                if (value instanceof Date) {
                    var today = kendo.date.today();
                    var diff = quarter(value) - quarter(today);
                    return diff === 0 && today.getFullYear() === value.getFullYear();
                }
                return false;
            },
            lastQuarter: function (value) {
                if (value instanceof Date) {
                    var today = kendo.date.today();
                    var diff = quarter(today) - quarter(value);
                    return diff === 1 && today.getFullYear() === value.getFullYear() || diff == -3 && today.getFullYear() - 1 === value.getFullYear();
                }
                return false;
            },
            nextYear: function (value) {
                return sameYear(value, 1);
            },
            thisYear: function (value) {
                return sameYear(value, 0);
            },
            lastYear: function (value) {
                return sameYear(value, -1);
            },
            yearToDate: function (value) {
                if (value instanceof Date) {
                    var today = kendo.date.today();
                    return value.getFullYear() === today.getFullYear() && value <= today;
                }
                return false;
            },
            toJSON: function () {
                return {
                    filter: 'dynamic',
                    type: this._type
                };
            }
        });
        [
            1,
            2,
            3,
            4
        ].forEach(function (target) {
            kendo.spreadsheet.DynamicFilter.prototype['quarter' + target] = function (value) {
                if (value instanceof Date) {
                    return quarter(value) === target;
                }
                return false;
            };
        });
        kendo.cultures['en-US'].calendar.months.names.forEach(function (month, index) {
            kendo.spreadsheet.DynamicFilter.prototype[month.toLowerCase()] = function (value) {
                if (value instanceof Date) {
                    return value.getMonth() === index;
                }
                return false;
            };
        });
        function quarter(value) {
            var month = value.getMonth() + 1;
            if (month >= 1 && month <= 3) {
                return 1;
            } else if (month >= 4 && month <= 6) {
                return 2;
            } else if (month >= 7 && month <= 9) {
                return 3;
            } else {
                return 4;
            }
        }
        function sameYear(value, offset) {
            if (value instanceof Date) {
                var today = kendo.date.today();
                today.setFullYear(today.getFullYear() + offset);
                return today.getFullYear() === value.getFullYear();
            }
            return false;
        }
        function sameMonth(value, offset) {
            if (value instanceof Date) {
                var today = kendo.date.firstDayOfMonth(kendo.date.today());
                today.setMonth(today.getMonth() + offset, 1);
                return today.getTime() === kendo.date.firstDayOfMonth(value).getTime();
            }
            return false;
        }
        function sameWeek(a, b) {
            if (b instanceof Date) {
                var firstWeek = kendo.date.dayOfWeek(kendo.date.getDate(a), 1);
                var secondWeek = kendo.date.dayOfWeek(kendo.date.getDate(b), 1);
                return firstWeek.getTime() === secondWeek.getTime();
            }
            return false;
        }
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/sorter', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var Sorter = kendo.Class.extend({
            init: function (grid, lists) {
                this._grid = grid;
                this._lists = lists;
            },
            indices: function (rangeRef, list, ascending, indices) {
                var comparer = Sorter.ascendingComparer;
                if (ascending === false) {
                    comparer = Sorter.descendingComparer;
                }
                return list.sortedIndices(this._grid.cellRefIndex(rangeRef.topLeft), this._grid.cellRefIndex(rangeRef.bottomRight), comparer, indices);
            },
            sortBy: function (ref, column, list, ascending, indices) {
                var sortedIndices = this.indices(ref.toColumn(column), list, ascending, indices);
                for (var ci = ref.topLeft.col; ci <= ref.bottomRight.col; ci++) {
                    var start = this._grid.index(ref.topLeft.row, ci);
                    var end = this._grid.index(ref.bottomRight.row, ci);
                    for (var li = 0; li < this._lists.length; li++) {
                        if (start < this._lists[li].lastRangeStart()) {
                            this._lists[li].sort(start, end, sortedIndices);
                        }
                    }
                }
                return sortedIndices;
            }
        });
        Sorter.ascendingComparer = function (a, b) {
            if (a === null && b === null) {
                return 0;
            }
            if (a === null) {
                return 1;
            }
            if (b === null) {
                return -1;
            }
            var typeA = typeof a;
            var typeB = typeof b;
            if (typeA === 'number') {
                if (typeB === 'number') {
                    return a - b;
                } else {
                    return -1;
                }
            }
            if (typeA === 'string') {
                switch (typeB) {
                case 'number':
                    return 1;
                case 'string':
                    return a.localeCompare(b);
                default:
                    return -1;
                }
            }
            if (typeA === 'boolean') {
                switch (typeB) {
                case 'number':
                    return 1;
                case 'string':
                    return 1;
                case 'boolean':
                    return a - b;
                default:
                    return -1;
                }
            }
            if (a instanceof kendo.spreadsheet.calc.runtime.CalcError) {
                if (b instanceof kendo.spreadsheet.calc.runtime.CalcError) {
                    return 0;
                } else {
                    return 1;
                }
            }
            throw new Error('Cannot compare ' + a + ' and ' + b);
        };
        Sorter.descendingComparer = function (a, b) {
            if (a === null && b === null) {
                return 0;
            }
            if (a === null) {
                return 1;
            }
            if (b === null) {
                return -1;
            }
            return Sorter.ascendingComparer(b, a);
        };
        kendo.spreadsheet.Sorter = Sorter;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/numformat', [
        'spreadsheet/calc',
        'kendo.dom',
        'util/main'
    ], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var util = kendo.util;
    var calc = kendo.spreadsheet.calc;
    var dom = kendo.dom;
    var RX_COLORS = /^\[(black|green|white|blue|magenta|yellow|cyan|red)\]/i;
    var RX_CONDITION = /^\[(<=|>=|<>|<|>|=)(-?[0-9.]+)\]/;
    function parse(input) {
        input = calc.InputStream(input);
        var sections = [], haveConditional = false, decimalPart;
        while (!input.eof()) {
            var sec = readSection();
            sections.push(sec);
            if (sec.cond) {
                haveConditional = true;
            }
        }
        if (!haveConditional) {
            if (sections.length == 1) {
                sections[0].cond = 'num';
            } else if (sections.length == 2) {
                sections[0].cond = {
                    op: '>=',
                    value: 0
                };
                sections[1].cond = {
                    op: '<',
                    value: 0
                };
            } else if (sections.length >= 3) {
                sections[0].cond = {
                    op: '>',
                    value: 0
                };
                sections[1].cond = {
                    op: '<',
                    value: 0
                };
                sections[2].cond = {
                    op: '=',
                    value: 0
                };
                if (sections.length > 3) {
                    sections[3].cond = 'text';
                    sections = sections.slice(0, 4);
                }
            }
        }
        return sections;
        function maybeColor() {
            var m = input.skip(RX_COLORS);
            if (m) {
                return m[1].toLowerCase();
            }
        }
        function maybeCondition() {
            var m = input.skip(RX_CONDITION);
            if (m) {
                var val = parseFloat(m[2]);
                if (!isNaN(val)) {
                    return {
                        op: m[1],
                        value: val,
                        custom: true
                    };
                }
            }
        }
        function readFormat() {
            var format = [], tok, prev = null;
            while (!input.eof() && (tok = readNext())) {
                if (tok.type == 'date') {
                    if (prev && /^(el)?time$/.test(prev.type) && prev.part == 'h' && tok.part == 'm' && tok.format < 3) {
                        tok.type = 'time';
                    }
                } else if (/^(el)?time$/.test(tok.type) && tok.part == 's') {
                    if (prev && prev.type == 'date' && prev.part == 'm' && prev.format < 3) {
                        prev.type = 'time';
                    }
                }
                if (!/^(?:str|space|fill)$/.test(tok.type)) {
                    prev = tok;
                }
                format.push(tok);
            }
            return format;
        }
        function maybeFraction(tok) {
            if (tok.type != 'date' || tok.part == 'm' && tok.format < 3) {
                var m = input.skip(/^\.(0+)/);
                if (m) {
                    tok.fraction = m[1].length;
                    if (tok.type == 'date') {
                        tok.type = 'time';
                    }
                }
            }
            return tok;
        }
        function readNext() {
            var ch, m;
            if (m = input.skip(/^([#0?]+)(?:,([#0?]+))+/)) {
                return {
                    type: 'digit',
                    sep: true,
                    format: m[1] + m[2],
                    decimal: decimalPart
                };
            }
            if (m = input.skip(/^[#0?]+/)) {
                return {
                    type: 'digit',
                    sep: false,
                    format: m[0],
                    decimal: decimalPart
                };
            }
            if (m = input.skip(/^(e)([+-])/i)) {
                return {
                    type: 'exp',
                    ch: m[1],
                    sign: m[2]
                };
            }
            if (m = input.skip(/^(d{1,4}|m{1,5}|yyyy|yy)/i)) {
                m = m[1].toLowerCase();
                return maybeFraction({
                    type: 'date',
                    part: m.charAt(0),
                    format: m.length
                });
            }
            if (m = input.skip(/^(hh?|ss?)/i)) {
                m = m[1].toLowerCase();
                return maybeFraction({
                    type: 'time',
                    part: m.charAt(0),
                    format: m.length
                });
            }
            if (m = input.skip(/^\[(hh?|mm?|ss?)\]/i)) {
                m = m[1].toLowerCase();
                return maybeFraction({
                    type: 'eltime',
                    part: m.charAt(0),
                    format: m.length
                });
            }
            if (m = input.skip(/^(a[.]?m[.]?\/p[.]?m[.]?|a\/p)/i)) {
                m = m[1].split('/');
                return {
                    type: 'ampm',
                    am: m[0],
                    pm: m[1]
                };
            }
            switch (ch = input.next()) {
            case ';':
                return null;
            case '\\':
                return {
                    type: 'str',
                    value: input.next()
                };
            case '"':
                return {
                    type: 'str',
                    value: input.readEscaped(ch)
                };
            case '@':
                return { type: 'text' };
            case '_':
                return {
                    type: 'space',
                    value: input.next()
                };
            case '*':
                return {
                    type: 'fill',
                    value: input.next()
                };
            case '.':
                if (input.lookingAt(/^\s*[#0?]/)) {
                    decimalPart = true;
                    return { type: 'dec' };
                }
                return {
                    type: 'str',
                    value: '.'
                };
            case '%':
                return { type: 'percent' };
            case ',':
                return { type: 'comma' };
            }
            return {
                type: 'str',
                value: ch
            };
        }
        function readSection() {
            decimalPart = false;
            var color = maybeColor(), cond = maybeCondition();
            if (!color && cond) {
                color = maybeColor();
            }
            return {
                color: color,
                cond: cond,
                body: readFormat()
            };
        }
    }
    function print(sections) {
        return sections.map(printSection).join(';');
        function printSection(sec) {
            var out = '';
            if (sec.color) {
                out += '[' + sec.color + ']';
            }
            if (sec.cond) {
                if (!(sec.cond == 'text' || sec.cond == 'num')) {
                    out += '[' + sec.cond.op + sec.cond.value + ']';
                }
            }
            out += sec.body.map(printToken).join('');
            return out;
        }
        function maybeFraction(fmt, tok) {
            if (tok.fraction) {
                fmt += '.' + padLeft('', tok.fraction, '0');
            }
            return fmt;
        }
        function printToken(tok) {
            if (tok.type == 'digit') {
                if (tok.sep) {
                    return tok.format.charAt(0) + ',' + tok.format.substr(1);
                } else {
                    return tok.format;
                }
            } else if (tok.type == 'exp') {
                return tok.ch + tok.sign;
            } else if (tok.type == 'date' || tok.type == 'time') {
                return maybeFraction(padLeft('', tok.format, tok.part), tok);
            } else if (tok.type == 'eltime') {
                return maybeFraction('[' + padLeft('', tok.format, tok.part) + ']', tok);
            } else if (tok.type == 'ampm') {
                return tok.am + '/' + tok.pm;
            } else if (tok.type == 'str') {
                return JSON.stringify(tok.value);
            } else if (tok.type == 'text') {
                return '@';
            } else if (tok.type == 'space') {
                return '_' + tok.value;
            } else if (tok.type == 'fill') {
                return '*' + tok.value;
            } else if (tok.type == 'dec') {
                return '.';
            } else if (tok.type == 'percent') {
                return '%';
            } else if (tok.type == 'comma') {
                return ',';
            }
        }
    }
    function adjustDecimals(sections, x) {
        sections.forEach(function (sec) {
            var diff = x;
            if (sec.cond == 'text') {
                return;
            }
            var body = sec.body, adjusted = false, i = body.length;
            while (diff !== 0 && --i >= 0) {
                var tok = body[i];
                if (tok.type == 'digit') {
                    if (tok.decimal) {
                        adjusted = true;
                        if (diff > 0) {
                            tok.format += padLeft('', diff, '0');
                        } else if (diff < 0) {
                            var tmp = tok.format.length;
                            tok.format = tok.format.substr(0, tmp + diff);
                            diff += tmp - tok.format.length;
                        }
                        if (tok.format.length === 0) {
                            body.splice(i, 1);
                            while (--i >= 0) {
                                tok = body[i];
                                if (tok.type == 'digit' && tok.decimal) {
                                    ++i;
                                    break;
                                }
                                if (tok.type == 'dec') {
                                    body.splice(i, 1);
                                    break;
                                }
                            }
                        }
                    }
                    if (diff > 0) {
                        break;
                    }
                }
            }
            if (!adjusted && diff > 0) {
                body.splice(i + 1, 0, { type: 'dec' }, {
                    type: 'digit',
                    sep: false,
                    decimal: true,
                    format: padLeft('', diff, '0')
                });
            }
        });
    }
    function TokenStream(parts) {
        var index = 0;
        return {
            next: function () {
                return parts[index++];
            },
            eof: function () {
                return index >= parts.length;
            },
            ahead: function (n, f) {
                if (index + n <= parts.length) {
                    var val = f.apply(null, parts.slice(index, index + n));
                    if (val) {
                        index += n;
                    }
                    return val;
                }
            },
            restart: function () {
                index = 0;
            }
        };
    }
    function compileFormatPart(format) {
        var input = TokenStream(format.body);
        var hasDate = false;
        var hasTime = false;
        var hasAmpm = false;
        var percentCount = 0;
        var currency = /[\$\xA2-\xA5\u058F\u060B\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u17DB\u20A0-\u20BD\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6]/;
        var scaleCount = 0;
        var code = '';
        var separeThousands = false;
        var declen = 0;
        var intFormat = [], decFormat = [];
        var condition = format.cond;
        var preamble = '';
        if (condition == 'text') {
            preamble = 'if (typeof value == \'string\' || value instanceof kendo.spreadsheet.CalcError) { ';
        } else if (condition == 'num') {
            preamble = 'if (typeof value == \'number\') { ';
        } else if (condition) {
            var op = condition.op == '=' ? '==' : condition.op;
            preamble = 'if (typeof value == \'number\' && value ' + op + ' ' + condition.value + ') { ';
            if (!condition.custom) {
                code += 'value = Math.abs(value); ';
            }
        }
        if (format.color) {
            code += 'result.color = ' + JSON.stringify(format.color) + '; ';
        }
        function checkComma(a, b) {
            if (a.type == 'digit' && b.type == 'comma' || a.type == 'comma' && a.hidden && b.type == 'comma') {
                b.hidden = true;
                scaleCount++;
            }
        }
        while (!input.eof()) {
            input.ahead(2, checkComma);
            var tok = input.next();
            if (tok.type == 'percent') {
                percentCount++;
            } else if (tok.type == 'digit') {
                if (tok.decimal) {
                    declen += tok.format.length;
                    decFormat.push(tok.format);
                } else {
                    intFormat.push(tok.format);
                    if (tok.sep) {
                        separeThousands = true;
                    }
                }
            } else if (tok.type == 'time') {
                hasTime = true;
            } else if (tok.type == 'date') {
                hasDate = true;
            } else if (tok.type == 'ampm') {
                hasAmpm = hasTime = true;
            }
        }
        if (percentCount > 0) {
            code += 'value *= ' + Math.pow(100, percentCount) + '; ';
        }
        if (scaleCount > 0) {
            code += 'value /= ' + Math.pow(1000, scaleCount) + '; ';
        }
        if (intFormat.length) {
            code += 'var intPart = runtime.formatInt(culture, value, ' + JSON.stringify(intFormat) + ', ' + declen + ', ' + separeThousands + '); ';
            code += 'var isNegative = parseInt(intPart[0]) < 0;';
        }
        if (decFormat.length) {
            code += 'var decPart = runtime.formatDec(value, ' + JSON.stringify(decFormat) + ', ' + declen + '); ';
        }
        if (intFormat.length || decFormat.length) {
            code += 'type = \'number\'; ';
        }
        if (hasDate) {
            code += 'var date = runtime.unpackDate(value); ';
        }
        if (hasTime) {
            code += 'var time = runtime.unpackTime(value); ';
        }
        if (hasDate || hasTime) {
            code += 'type = \'date\'; ';
        }
        if (percentCount > 0 || scaleCount > 0 || intFormat.length || decFormat.length || hasDate || hasTime) {
            if (!preamble) {
                preamble = 'if (typeof value == \'number\') { ';
            }
        }
        input.restart();
        code += 'var matchedCurrency = false;';
        while (!input.eof()) {
            var tok = input.next();
            if (tok.type == 'dec') {
                code += 'output += culture.numberFormat[\'.\']; ';
            } else if (tok.type == 'comma' && !tok.hidden) {
                code += 'output += \',\'; ';
            } else if (tok.type == 'percent') {
                code += 'type = \'percent\'; ';
                code += 'output += culture.numberFormat.percent.symbol; ';
            } else if (tok.type == 'str') {
                if (currency.test(tok.value)) {
                    code += 'type = \'currency\'; ';
                    code += 'if (isNegative) { output += \'-\'; matchedCurrency = true; }';
                }
                code += 'output += ' + JSON.stringify(tok.value) + '; ';
            } else if (tok.type == 'text') {
                code += 'type = \'text\'; ';
                code += 'output += value; ';
            } else if (tok.type == 'space') {
                code += 'if (output) result.body.push(output); ';
                code += 'output = \'\'; ';
                code += 'result.body.push({ type: \'space\', value: ' + JSON.stringify(tok.value) + ' }); ';
            } else if (tok.type == 'fill') {
                code += 'output += runtime.fill(' + JSON.stringify(tok.value) + '); ';
            } else if (tok.type == 'digit') {
                code += 'if (isNegative && intPart[0] && matchedCurrency) {intPart[0] = intPart[0].replace(\'-\', \'\');}';
                code += 'output += ' + (tok.decimal ? 'decPart' : 'intPart') + '.shift(); ';
            } else if (tok.type == 'date') {
                code += 'output += runtime.date(culture, date, ' + JSON.stringify(tok.part) + ', ' + tok.format + '); ';
            } else if (tok.type == 'time') {
                code += 'output += runtime.time(time, ' + JSON.stringify(tok.part) + ', ' + tok.format + ', ' + hasAmpm + ', ' + tok.fraction + '); ';
            } else if (tok.type == 'eltime') {
                code += 'output += runtime.eltime(value, ' + JSON.stringify(tok.part) + ', ' + tok.format + ', ' + tok.fraction + '); ';
            } else if (tok.type == 'ampm') {
                code += 'output += time.hours < 12 ? ' + JSON.stringify(tok.am) + ' : ' + JSON.stringify(tok.pm) + '; ';
            }
        }
        code += 'if (output) result.body.push(output); ';
        code += 'result.type = type; ';
        code += 'return result; ';
        if (preamble) {
            code = preamble + code + '}';
        }
        return code;
    }
    var TEXT = compileFormatPart({
        cond: 'text',
        body: [{ type: 'text' }]
    });
    var compile = util.memoize(function (format) {
        var tree = parse(format);
        var code = tree.map(compileFormatPart);
        code.push(TEXT);
        code = code.join('\n');
        code = '\'use strict\'; return function(value, culture){ ' + 'if (!culture) culture = kendo.culture(); ' + 'var output = \'\', type = null, result = { body: [] }; ' + code + '; return result; };';
        return new Function('runtime', code)(runtime);
    });
    var makeDateFormat = util.memoize(function (format) {
        var tree = parse(format);
        var section, found = false, hasAmpm = false;
        for (var i = 0; i < tree.length; ++i) {
            section = tree[i];
            for (var j = 0; j < section.body.length; ++j) {
                if (/^(?:date|time|ampm)$/.test(section.body[j].type)) {
                    found = true;
                    if (section.body[j].type == 'ampm') {
                        hasAmpm = true;
                    }
                }
            }
            if (found) {
                break;
            }
        }
        if (!found) {
            return null;
        }
        return section.body.map(printToken).join('');
        function maybeFraction(fmt, tok) {
            if (tok.fraction) {
                fmt += padLeft('', Math.max(tok.fraction, 3), 'f');
            }
            return fmt;
        }
        function printToken(tok) {
            if (tok.type == 'digit') {
                if (tok.sep) {
                    return tok.format.charAt(0) + ',' + tok.format.substr(1);
                } else {
                    return tok.format;
                }
            } else if (tok.type == 'exp') {
                return tok.ch + tok.sign;
            } else if (tok.type == 'date' || tok.type == 'time') {
                var part = tok.part;
                if (tok.type == 'date' && /^m/.test(part)) {
                    part = 'M';
                } else if (tok.type == 'time' && /^h/.test(part)) {
                    if (!hasAmpm) {
                        part = part.toUpperCase();
                    }
                }
                return maybeFraction(padLeft('', tok.format, part), tok);
            } else if (tok.type == 'ampm') {
                return 'tt';
            } else if (tok.type == 'str') {
                return tok.value;
            } else if (tok.type == 'space') {
                return ' ';
            } else if (tok.type == 'dec') {
                return '.';
            } else if (tok.type == 'percent') {
                return '%';
            } else if (tok.type == 'comma') {
                return ',';
            } else {
                return '';
            }
        }
    });
    var runtime = {
        unpackDate: calc.runtime.unpackDate,
        unpackTime: calc.runtime.unpackTime,
        date: function (culture, d, part, length) {
            switch (part) {
            case 'd':
                switch (length) {
                case 1:
                    return d.date;
                case 2:
                    return padLeft(d.date, 2, '0');
                case 3:
                    return culture.calendars.standard.days.namesAbbr[d.day];
                case 4:
                    return culture.calendars.standard.days.names[d.day];
                }
                break;
            case 'm':
                switch (length) {
                case 1:
                    return d.month + 1;
                case 2:
                    return padLeft(d.month + 1, 2, '0');
                case 3:
                    return culture.calendars.standard.months.namesAbbr[d.month];
                case 4:
                    return culture.calendars.standard.months.names[d.month];
                case 5:
                    return culture.calendars.standard.months.names[d.month].charAt(0);
                }
                break;
            case 'y':
                switch (length) {
                case 2:
                    return d.year % 100;
                case 4:
                    return d.year;
                }
                break;
            }
            return '##';
        },
        time: function (t, part, length, ampm, fraclen) {
            var ret, fraction;
            switch (part) {
            case 'h':
                ret = padLeft(ampm ? t.hours % 12 || 12 : t.hours, length, '0');
                if (fraclen) {
                    fraction = (t.minutes + (t.seconds + t.milliseconds / 1000) / 60) / 60;
                }
                break;
            case 'm':
                ret = padLeft(t.minutes, length, '0');
                if (fraclen) {
                    fraction = (t.seconds + t.milliseconds / 1000) / 60;
                }
                break;
            case 's':
                ret = padLeft(t.seconds, length, '0');
                if (fraclen) {
                    fraction = t.milliseconds / 1000;
                }
                break;
            }
            if (fraction) {
                ret += runtime.toFixed(fraction, fraclen).replace(/^0+/, '');
            }
            return ret;
        },
        eltime: function (value, part, length, fraclen) {
            var ret, fraction;
            switch (part) {
            case 'h':
                ret = value * 24;
                break;
            case 'm':
                ret = value * 24 * 60;
                break;
            case 's':
                ret = value * 24 * 60 * 60;
                break;
            }
            if (fraclen) {
                fraction = ret - (ret | 0);
            }
            ret = padLeft(ret | 0, length, '0');
            if (fraction) {
                ret += runtime.toFixed(fraction, fraclen).replace(/^0+/, '');
            }
            return ret;
        },
        fill: function (ch) {
            return ch;
        },
        formatInt: function (culture, value, parts, declen, sep) {
            value = runtime.toFixed(value, declen).replace(/\..*$/, '');
            var lastPart = parts[parts.length - 1];
            if (declen > 0 && lastPart[parts.length - 1] != '0') {
                if (value === '0') {
                    value = '';
                } else if (value === '-0') {
                    value = '-';
                }
            }
            var shouldInsertMinus = false;
            var iv = value.length - 1;
            var result = [];
            var len = 0, str;
            function add(ch, skipMinus) {
                if (sep && len && len % 3 === 0 && /^[0-9]$/.test(ch)) {
                    str = culture.numberFormat[','] + str;
                }
                if (skipMinus && ch === '-') {
                    shouldInsertMinus = true;
                    ch = '0';
                }
                str = ch + str;
                len++;
            }
            for (var j = parts.length; --j >= 0;) {
                var format = parts[j];
                str = '';
                for (var k = format.length; --k >= 0;) {
                    var chf = format.charAt(k);
                    if (iv < 0) {
                        if (chf == '0') {
                            add('0');
                        } else if (chf == '?') {
                            add(' ');
                        }
                    } else {
                        if (value == '0' && chf == '?') {
                            add(' ');
                        } else if (chf == '0') {
                            add(value.charAt(iv), true);
                        } else {
                            add(value.charAt(iv));
                        }
                        iv--;
                    }
                }
                if (j === 0) {
                    while (iv >= 0) {
                        add(value.charAt(iv--));
                    }
                }
                result.unshift(str);
            }
            if (shouldInsertMinus) {
                result[0] = '-' + result[0];
            }
            return result;
        },
        formatDec: function (value, parts, declen) {
            value = runtime.toFixed(value, declen);
            var pos = value.indexOf('.');
            if (pos >= 0) {
                value = value.substr(pos + 1).replace(/0+$/, '');
            } else {
                value = '';
            }
            var iv = 0;
            var result = [];
            for (var j = 0; j < parts.length; ++j) {
                var format = parts[j];
                var str = '';
                for (var k = 0; k < format.length; ++k) {
                    var chf = format.charAt(k);
                    if (iv < value.length) {
                        str += value.charAt(iv++);
                    } else if (chf == '0') {
                        str += '0';
                    } else if (chf == '?') {
                        str += ' ';
                    }
                }
                result.push(str);
            }
            return result;
        },
        toFixed: function (value, decimals) {
            return function toFixed(value, last) {
                if (!isFinite(value)) {
                    return '#NUM!';
                }
                if (value < 0) {
                    return '-' + toFixed(-value);
                }
                if (decimals === 0) {
                    return String(Math.round(value));
                }
                if (value === Math.round(value) && !/e/i.test(String(value))) {
                    return value.toFixed(decimals);
                }
                var num = digNumber(value);
                var intpart = num.intpart;
                var decpart = num.decpart;
                if (decpart.length <= decimals) {
                    while (decpart.length < decimals) {
                        decpart += '0';
                    }
                    return intpart + '.' + decpart;
                }
                if (last) {
                    return intpart + '.' + decpart.substr(0, decimals);
                }
                var f = Math.pow(10, decimals);
                return toFixed(Math.round(value * f) / f, true);
            }(Number(value.toFixed(14)));
        }
    };
    function padLeft(val, width, ch) {
        val += '';
        while (val.length < width) {
            val = ch + val;
        }
        return val;
    }
    function padRight(val, width, ch) {
        val += '';
        while (val.length < width) {
            val += ch;
        }
        return val;
    }
    function digNumber(num) {
        var str = String(num).toLowerCase();
        var intpart, decpart, m;
        var pos = str.indexOf('.');
        if (pos < 0) {
            pos = str.indexOf('e');
            if (pos < 0) {
                intpart = str;
                decpart = '';
            } else {
                intpart = str.substr(0, pos);
                decpart = str.substr(pos);
            }
        } else {
            intpart = str.substr(0, pos);
            decpart = str.substr(pos + 1);
        }
        if (m = /(\d*)e([-+]?\d+)/.exec(decpart)) {
            var exp = parseInt(m[2], 10);
            if (exp >= 0) {
                decpart = padRight(m[1], exp, '0');
                intpart += decpart.substr(0, exp);
                decpart = decpart.substr(exp);
            } else {
                intpart = padLeft(intpart, -exp, '0');
                decpart = intpart.substr(exp) + m[1];
                intpart = intpart.substr(0, intpart.length + exp);
            }
        }
        return {
            intpart: intpart || '0',
            decpart: decpart
        };
    }
    function text(f) {
        var a = f.body;
        var text = '';
        for (var i = 0; i < a.length; ++i) {
            var el = a[i];
            if (typeof el == 'string') {
                text += el;
            } else if (el.type == 'space') {
                text += ' ';
            }
        }
        return text;
    }
    kendo.spreadsheet.formatting = {
        compile: compile,
        parse: parse,
        format: function (value, format, culture) {
            var f = compile(format)(value, culture);
            var span = dom.element('span');
            span.__dataType = f.type;
            var a = f.body;
            if (f.color) {
                span.attr.style = { color: f.color };
            }
            for (var i = 0; i < a.length; ++i) {
                var el = a[i];
                if (typeof el == 'string') {
                    span.children.push(dom.text(el));
                } else if (el.type == 'space') {
                    span.children.push(dom.element('span', { style: { visibility: 'hidden' } }, [dom.text(el.value)]));
                }
            }
            return span;
        },
        text: function (value, format, culture) {
            var f = compile(format)(value, culture);
            return text(f);
        },
        textAndColor: function (value, format, culture) {
            var f = compile(format)(value, culture);
            return {
                text: text(f),
                color: f.color,
                type: f.type
            };
        },
        type: function (value, format) {
            return compile(format)(value).type;
        },
        adjustDecimals: function (format, diff) {
            var ast = parse(format);
            adjustDecimals(ast, diff);
            return print(ast);
        },
        makeDateFormat: makeDateFormat
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/runtime.functions', [
        'spreadsheet/runtime',
        'util/main'
    ], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var util = kendo.util;
    var spreadsheet = kendo.spreadsheet;
    var calc = spreadsheet.calc;
    var runtime = calc.runtime;
    var defineFunction = runtime.defineFunction;
    var defineAlias = runtime.defineAlias;
    var CalcError = runtime.CalcError;
    var RangeRef = spreadsheet.RangeRef;
    var CellRef = spreadsheet.CellRef;
    var UnionRef = spreadsheet.UnionRef;
    var Matrix = runtime.Matrix;
    var Ref = spreadsheet.Ref;
    var daysInMonth = runtime.daysInMonth;
    var packDate = runtime.packDate;
    var unpackDate = runtime.unpackDate;
    var daysInYear = runtime.daysInYear;
    [
        'abs',
        'cos',
        'sin',
        'acos',
        'asin',
        'tan',
        'atan',
        'exp',
        'sqrt'
    ].forEach(function (name) {
        defineFunction(name, Math[name]).args([[
                '*n',
                'number'
            ]]);
    });
    defineFunction('ln', Math.log).args([[
            '*n',
            'number'
        ]]);
    defineFunction('log', function (num, base) {
        return Math.log(num) / Math.log(base);
    }).args([
        [
            '*num',
            'number++'
        ],
        [
            '*base',
            [
                'or',
                'number++',
                [
                    'null',
                    10
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$base != 1',
                'DIV/0'
            ]
        ]
    ]);
    defineFunction('log10', function (num) {
        return Math.log(num) / Math.log(10);
    }).args([[
            '*num',
            'number++'
        ]]);
    defineFunction('pi', function () {
        return Math.PI;
    }).args([]);
    defineFunction('sqrtpi', function (n) {
        return Math.sqrt(n * Math.PI);
    }).args([[
            '*num',
            'number+'
        ]]);
    defineFunction('degrees', function (rad) {
        return 180 * rad / Math.PI % 360;
    }).args([[
            '*radians',
            'number'
        ]]);
    defineFunction('radians', function (deg) {
        return Math.PI * deg / 180;
    }).args([[
            '*degrees',
            'number'
        ]]);
    function _cosh(n) {
        return (Math.exp(n) + Math.exp(-n)) / 2;
    }
    defineFunction('cosh', _cosh).args([[
            '*num',
            'number'
        ]]);
    defineFunction('acosh', function (n) {
        return Math.log(n + Math.sqrt(n - 1) * Math.sqrt(n + 1));
    }).args([
        [
            '*num',
            'number'
        ],
        [
            '?',
            [
                'assert',
                '$num >= 1'
            ]
        ]
    ]);
    function _sinh(n) {
        return (Math.exp(n) - Math.exp(-n)) / 2;
    }
    defineFunction('sinh', _sinh).args([[
            '*num',
            'number'
        ]]);
    defineFunction('asinh', function (n) {
        return Math.log(n + Math.sqrt(n * n + 1));
    }).args([[
            '*num',
            'number'
        ]]);
    defineFunction('sec', function (n) {
        return 1 / Math.cos(n);
    }).args([[
            '*num',
            'number'
        ]]);
    defineFunction('sech', function (n) {
        return 1 / _cosh(n);
    }).args([[
            '*num',
            'number'
        ]]);
    defineFunction('csc', function (n) {
        return 1 / Math.sin(n);
    }).args([[
            '*num',
            'number'
        ]]);
    defineFunction('csch', function (n) {
        return 1 / _sinh(n);
    }).args([[
            '*num',
            'number'
        ]]);
    defineFunction('atan2', function (x, y) {
        return Math.atan(y / x);
    }).args([
        [
            '*x',
            'divisor'
        ],
        [
            '*y',
            'number'
        ]
    ]);
    function _tanh(n) {
        return _sinh(n) / _cosh(n);
    }
    defineFunction('tanh', _tanh).args([[
            '*num',
            'number'
        ]]);
    defineFunction('atanh', function (n) {
        return Math.log(Math.sqrt(1 - n * n) / (1 - n));
    }).args([[
            '*num',
            [
                'and',
                'number',
                [
                    '(between)',
                    -1,
                    1
                ]
            ]
        ]]);
    defineFunction('cot', function (n) {
        return 1 / Math.tan(n);
    }).args([[
            '*num',
            'divisor'
        ]]);
    defineFunction('coth', function (n) {
        return 1 / _tanh(n);
    }).args([[
            '*num',
            'divisor'
        ]]);
    defineFunction('acot', function (n) {
        return Math.PI / 2 - Math.atan(n);
    }).args([[
            '*num',
            'number'
        ]]);
    defineFunction('acoth', function (n) {
        return Math.log((n + 1) / (n - 1)) / 2;
    }).args([
        [
            '*num',
            'number'
        ],
        [
            '?',
            [
                'or',
                [
                    'assert',
                    '$num < -1'
                ],
                [
                    'assert',
                    '$num > 1'
                ]
            ]
        ]
    ]);
    defineFunction('power', function (a, b) {
        return Math.pow(a, b);
    }).args([
        [
            '*a',
            'number'
        ],
        [
            '*b',
            'number'
        ]
    ]);
    defineFunction('mod', function (a, b) {
        return a % b;
    }).args([
        [
            '*a',
            'number'
        ],
        [
            '*b',
            'divisor'
        ]
    ]);
    defineFunction('quotient', function (a, b) {
        return Math.floor(a / b);
    }).args([
        [
            '*a',
            'number'
        ],
        [
            '*b',
            'divisor'
        ]
    ]);
    defineFunction('ceiling', function (num, s) {
        return s ? s * Math.ceil(num / s) : 0;
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*significance',
            'number'
        ],
        [
            '?',
            [
                'assert',
                '$significance >= 0 || $number < 0'
            ]
        ]
    ]);
    defineFunction('ceiling.precise', function (num, s) {
        s = Math.abs(s);
        return s ? s * Math.ceil(num / s) : 0;
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*significance',
            [
                'or',
                'number',
                [
                    'null',
                    1
                ]
            ]
        ]
    ]);
    defineAlias('iso.ceiling', 'ceiling.precise');
    defineFunction('ceiling.math', function (num, s, mode) {
        if (!s || !num) {
            return 0;
        }
        if (num < 0 && (!mode && s < 0 || mode && s > 0)) {
            s = -s;
        }
        return s ? s * Math.ceil(num / s) : 0;
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*significance',
            [
                'or',
                'number',
                [
                    'null',
                    '$number < 0 ? -1 : 1'
                ]
            ]
        ],
        [
            '*mode',
            [
                'or',
                'logical',
                [
                    'null',
                    0
                ]
            ]
        ]
    ]);
    defineFunction('floor', function (num, s) {
        return s ? s * Math.floor(num / s) : 0;
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*significance',
            'number'
        ],
        [
            '?',
            [
                'assert',
                '$significance >= 0 || $number < 0'
            ]
        ]
    ]);
    defineFunction('floor.precise', function (num, s) {
        s = Math.abs(s);
        return s ? s * Math.floor(num / s) : 0;
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*significance',
            [
                'or',
                'number',
                [
                    'null',
                    1
                ]
            ]
        ]
    ]);
    defineFunction('floor.math', function (num, s, mode) {
        if (!s || !num) {
            return 0;
        }
        if (num < 0 && (!mode && s < 0 || mode && s > 0)) {
            s = -s;
        }
        return s ? s * Math.floor(num / s) : 0;
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*significance',
            [
                'or',
                'number',
                [
                    'null',
                    '$number < 0 ? -1 : 1'
                ]
            ]
        ],
        [
            '*mode',
            [
                'or',
                'logical',
                [
                    'null',
                    0
                ]
            ]
        ]
    ]);
    defineFunction('int', Math.floor).args([[
            '*number',
            'number'
        ]]);
    defineFunction('mround', function (num, mult) {
        return mult ? mult * Math.round(num / mult) : 0;
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*multiple',
            'number'
        ]
    ]);
    defineFunction('round', function (num, digits) {
        var sign = num < 0 ? -1 : 1;
        if (sign < 0) {
            num = -num;
        }
        digits = Math.pow(10, digits);
        num *= digits;
        num = Math.round(num);
        return sign * num / digits;
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*digits',
            'number'
        ]
    ]);
    defineFunction('roundup', function (num, digits) {
        digits = Math.pow(10, digits);
        num *= digits;
        num = num < 0 ? Math.floor(num) : Math.ceil(num);
        return num / digits;
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*digits',
            'number'
        ]
    ]);
    defineFunction('rounddown', function (num, digits) {
        digits = Math.pow(10, digits);
        num *= digits;
        num = num < 0 ? Math.ceil(num) : Math.floor(num);
        return num / digits;
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*digits',
            'number'
        ]
    ]);
    defineFunction('even', function (num) {
        var n = num < 0 ? Math.floor(num) : Math.ceil(num);
        return n % 2 ? n + (n < 0 ? -1 : 1) : n;
    }).args([[
            '*number',
            'number'
        ]]);
    defineFunction('odd', function (num) {
        var n = num < 0 ? Math.floor(num) : Math.ceil(num);
        return n % 2 ? n : n + (n < 0 ? -1 : 1);
    }).args([[
            '*number',
            'number'
        ]]);
    defineFunction('sign', function (num) {
        return num < 0 ? -1 : num > 0 ? 1 : 0;
    }).args([[
            '*number',
            'number'
        ]]);
    function _gcd(a, b) {
        while (b) {
            var r = a % b;
            a = b;
            b = r;
        }
        return a;
    }
    function _lcm(a, b) {
        return Math.abs(a * b) / _gcd(a, b);
    }
    defineFunction('gcd', function (args) {
        var a = args[0];
        for (var i = 1; i < args.length; ++i) {
            a = _gcd(a, args[i]);
        }
        return a;
    }).args([[
            'numbers',
            [
                'collect',
                'number'
            ]
        ]]);
    defineFunction('lcm', function (args) {
        var a = args[0];
        for (var i = 1; i < args.length; ++i) {
            a = _lcm(a, args[i]);
        }
        return a;
    }).args([[
            'numbers',
            [
                'collect',
                'number'
            ]
        ]]);
    defineFunction('sum', function (numbers) {
        return numbers.reduce(function (sum, num) {
            return sum + num;
        }, 0);
    }).args([[
            'numbers',
            [
                'collect',
                'number'
            ]
        ]]);
    defineFunction('product', function (numbers) {
        return numbers.reduce(function (prod, num) {
            return prod * num;
        }, 1);
    }).args([[
            'numbers',
            [
                'collect',
                'number'
            ]
        ]]);
    defineFunction('sumproduct', function (first, rest) {
        var sum = 0;
        first.each(function (p, row, col) {
            if (typeof p == 'number') {
                for (var i = 0; i < rest.length; ++i) {
                    var v = rest[i].get(row, col);
                    if (typeof v != 'number') {
                        return;
                    }
                    p *= v;
                }
                sum += p;
            }
        });
        return sum;
    }).args([
        [
            'a1',
            'matrix'
        ],
        [
            '+',
            [
                'a2',
                [
                    'and',
                    'matrix',
                    [
                        'assert',
                        '$a2.width == $a1.width'
                    ],
                    [
                        'assert',
                        '$a2.height == $a1.height'
                    ]
                ]
            ]
        ]
    ]);
    defineFunction('sumsq', function (numbers) {
        return numbers.reduce(function (sum, num) {
            return sum + num * num;
        }, 0);
    }).args([[
            'numbers',
            [
                'collect',
                'number'
            ]
        ]]);
    defineFunction('sumx2my2', function (a, b) {
        var sum = 0;
        a.each(function (x, row, col) {
            var y = b.get(row, col);
            if (typeof x == 'number' && typeof y == 'number') {
                sum += x * x - y * y;
            }
        });
        return sum;
    }).args([
        [
            'a',
            'matrix'
        ],
        [
            'b',
            [
                'and',
                'matrix',
                [
                    'assert',
                    '$b.width == $a.width'
                ],
                [
                    'assert',
                    '$b.height == $a.height'
                ]
            ]
        ]
    ]);
    defineFunction('sumx2py2', function (a, b) {
        var sum = 0;
        a.each(function (x, row, col) {
            var y = b.get(row, col);
            if (typeof x == 'number' && typeof y == 'number') {
                sum += x * x + y * y;
            }
        });
        return sum;
    }).args([
        [
            'a',
            'matrix'
        ],
        [
            'b',
            [
                'and',
                'matrix',
                [
                    'assert',
                    '$b.width == $a.width'
                ],
                [
                    'assert',
                    '$b.height == $a.height'
                ]
            ]
        ]
    ]);
    defineFunction('sumxmy2', function (a, b) {
        var sum = 0;
        a.each(function (x, row, col) {
            var y = b.get(row, col);
            if (typeof x == 'number' && typeof y == 'number') {
                sum += (x - y) * (x - y);
            }
        });
        return sum;
    }).args([
        [
            'a',
            'matrix'
        ],
        [
            'b',
            [
                'and',
                'matrix',
                [
                    'assert',
                    '$b.width == $a.width'
                ],
                [
                    'assert',
                    '$b.height == $a.height'
                ]
            ]
        ]
    ]);
    defineFunction('seriessum', function (x, n, m, a) {
        var sum = 0;
        a.each(function (coef) {
            if (typeof coef != 'number') {
                throw new CalcError('VALUE');
            }
            sum += coef * Math.pow(x, n);
            n += m;
        });
        return sum;
    }).args([
        [
            'x',
            'number'
        ],
        [
            'y',
            'number'
        ],
        [
            'm',
            'number'
        ],
        [
            'a',
            'matrix'
        ]
    ]);
    defineFunction('min', function (numbers) {
        return numbers.length ? Math.min.apply(Math, numbers) : 0;
    }).args([[
            'numbers',
            [
                'collect',
                'number'
            ]
        ]]);
    defineFunction('max', function (numbers) {
        return numbers.length ? Math.max.apply(Math, numbers) : 0;
    }).args([[
            'numbers',
            [
                'collect',
                'number'
            ]
        ]]);
    defineFunction('counta', function (values) {
        return values.length;
    }).args([[
            'values',
            [
                '#collect',
                'anyvalue'
            ]
        ]]);
    defineFunction('count', function (numbers) {
        return numbers.length;
    }).args([[
            'numbers',
            [
                '#collect',
                'number'
            ]
        ]]);
    defineFunction('countunique', function (values) {
        var count = 0, seen = [];
        values.forEach(function (val) {
            if (seen.indexOf(val) < 0) {
                count++;
                seen.push(val);
            }
        });
        return count;
    }).args([[
            'values',
            [
                '#collect',
                'anyvalue'
            ]
        ]]);
    defineFunction('countblank', function (a) {
        var count = 0;
        function add(val) {
            if (val == null || val === '') {
                count++;
            }
        }
        function loop(args) {
            for (var i = 0; i < args.length; ++i) {
                var x = args[i];
                if (x instanceof Matrix) {
                    x.each(add, true);
                } else {
                    add(x);
                }
            }
        }
        loop(a);
        return count;
    }).args([[
            '+',
            [
                'args',
                [
                    'or',
                    'matrix',
                    'anyvalue'
                ]
            ]
        ]]);
    defineFunction('iseven', function (num) {
        return num % 2 === 0;
    }).args([[
            '*number',
            'number'
        ]]);
    defineFunction('isodd', function (num) {
        return num % 2 !== 0;
    }).args([[
            '*number',
            'number'
        ]]);
    defineFunction('n', function (val) {
        if (typeof val == 'boolean') {
            return val ? 1 : 0;
        }
        if (typeof val == 'number') {
            return val;
        }
        return 0;
    }).args([[
            '*value',
            'anyvalue'
        ]]);
    defineFunction('na', function () {
        return new CalcError('N/A');
    }).args([]);
    function forIFS(args, f) {
        var chunks = [], i = 0, matrix = args[0];
        while (i < args.length) {
            chunks.push({
                matrix: args[i++],
                pred: parseCriteria(args[i++])
            });
        }
        ROW:
            for (var row = 0; row < matrix.height; ++row) {
                COL:
                    for (var col = 0; col < matrix.width; ++col) {
                        for (i = 0; i < chunks.length; ++i) {
                            var val = chunks[i].matrix.get(row, col);
                            if (!chunks[i].pred(val == null || val === '' ? 0 : val)) {
                                continue COL;
                            }
                        }
                        f(row, col);
                    }
            }
    }
    var ARGS_COUNTIFS = [
        [
            'm1',
            'matrix'
        ],
        [
            'c1',
            'anyvalue'
        ],
        [
            [
                'm2',
                'matrix'
            ],
            [
                'c2',
                'anyvalue'
            ]
        ]
    ];
    defineFunction('countifs', function (m1, c1, rest) {
        var count = 0;
        rest.unshift(m1, c1);
        forIFS(rest, function () {
            count++;
        });
        return count;
    }).args(ARGS_COUNTIFS);
    var ARGS_SUMIFS = [[
            'range',
            'matrix'
        ]].concat(ARGS_COUNTIFS);
    defineFunction('sumifs', function (range, m1, c1, args) {
        args.unshift(range, numericPredicate, m1, c1);
        var sum = 0;
        forIFS(args, function (row, col) {
            var val = range.get(row, col);
            if (val) {
                sum += val;
            }
        });
        return sum;
    }).args(ARGS_SUMIFS);
    defineFunction('averageifs', function (range, m1, c1, args) {
        args.unshift(range, numericPredicate, m1, c1);
        var sum = 0, count = 0;
        forIFS(args, function (row, col) {
            var val = range.get(row, col);
            if (val == null || val === '') {
                val = 0;
            }
            sum += val;
            count++;
        });
        return count ? sum / count : new CalcError('DIV/0');
    }).args(ARGS_SUMIFS);
    defineFunction('countif', function (matrix, criteria) {
        criteria = parseCriteria(criteria);
        var count = 0;
        matrix.each(function (val) {
            if (criteria(val)) {
                count++;
            }
        });
        return count;
    }).args([
        [
            'range',
            'matrix'
        ],
        [
            '*criteria',
            'anyvalue'
        ]
    ]);
    var ARGS_SUMIF = [
        [
            'range',
            'matrix'
        ],
        [
            '*criteria',
            'anyvalue'
        ],
        [
            'sumRange',
            [
                'or',
                [
                    'and',
                    'matrix',
                    [
                        'assert',
                        '$sumRange.width == $range.width'
                    ],
                    [
                        'assert',
                        '$sumRange.height == $range.height'
                    ]
                ],
                [
                    'null',
                    '$range'
                ]
            ]
        ]
    ];
    defineFunction('sumif', function (range, criteria, sumRange) {
        var sum = 0;
        criteria = parseCriteria(criteria);
        range.each(function (val, row, col) {
            if (criteria(val)) {
                var v = sumRange.get(row, col);
                if (numericPredicate(v)) {
                    sum += v || 0;
                }
            }
        });
        return sum;
    }).args(ARGS_SUMIF);
    defineFunction('averageif', function (range, criteria, sumRange) {
        var sum = 0, count = 0;
        criteria = parseCriteria(criteria);
        range.each(function (val, row, col) {
            if (criteria(val)) {
                var v = sumRange.get(row, col);
                if (numericPredicate(v)) {
                    sum += v || 0;
                    count++;
                }
            }
        });
        return count ? sum / count : new CalcError('DIV/0');
    }).args(ARGS_SUMIF);
    (function (def) {
        def('large', function (numbers, nth) {
            return numbers.sort(descending)[nth];
        });
        def('small', function (numbers, nth) {
            return numbers.sort(ascending)[nth];
        });
    }(function (name, handler) {
        defineFunction(name, function (matrix, nth) {
            var numbers = [];
            var error = matrix.each(function (val) {
                if (val instanceof CalcError) {
                    return val;
                }
                if (typeof val == 'number') {
                    numbers.push(val);
                }
            });
            if (error) {
                return error;
            }
            if (nth > numbers.length) {
                return new CalcError('NUM');
            }
            return handler(numbers, nth - 1);
        }).args([
            [
                'array',
                'matrix'
            ],
            [
                '*nth',
                'number++'
            ]
        ]);
    }));
    function _avg(numbers) {
        return numbers.reduce(function (sum, num) {
            return sum + num;
        }, 0) / numbers.length;
    }
    function _var_sp(numbers, divisor, avg) {
        if (avg == null) {
            avg = _avg(numbers);
        }
        return numbers.reduce(function (sum, num) {
            return sum + Math.pow(num - avg, 2);
        }, 0) / divisor;
    }
    function _stdev_sp(numbers, divisor) {
        return Math.sqrt(_var_sp(numbers, divisor));
    }
    defineFunction('stdev.s', function (numbers) {
        return _stdev_sp(numbers, numbers.length - 1);
    }).args([
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length >= 2',
                'NUM'
            ]
        ]
    ]);
    defineFunction('stdev.p', function (numbers) {
        return _stdev_sp(numbers, numbers.length);
    }).args([
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length >= 2',
                'NUM'
            ]
        ]
    ]);
    defineFunction('var.s', function (numbers) {
        return _var_sp(numbers, numbers.length - 1);
    }).args([
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length >= 2',
                'NUM'
            ]
        ]
    ]);
    defineFunction('var.p', function (numbers) {
        return _var_sp(numbers, numbers.length);
    }).args([
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length >= 2',
                'NUM'
            ]
        ]
    ]);
    defineFunction('median', function (numbers) {
        var n = numbers.length;
        numbers.sort(ascending);
        if (n % 2) {
            return numbers[n >> 1];
        }
        return (numbers[n >>= 1] + numbers[n - 1]) / 2;
    }).args([
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length > 0',
                'N/A'
            ]
        ]
    ]);
    defineFunction('mode.sngl', function (numbers) {
        numbers.sort(ascending);
        var prev = null, count = 0, max = 1, mode = null;
        for (var i = 0; i < numbers.length; ++i) {
            var n = numbers[i];
            if (n != prev) {
                count = 1;
                prev = n;
            } else {
                count++;
            }
            if (count > max) {
                max = count;
                mode = n;
            }
        }
        return mode == null ? new CalcError('N/A') : mode;
    }).args([[
            'numbers',
            [
                'collect',
                'number'
            ]
        ]]);
    defineFunction('mode.mult', function (numbers) {
        var seen = Object.create(null), max = 2, res = [];
        numbers.forEach(function (num) {
            var s = seen[num] || 0;
            seen[num] = ++s;
            if (s == max) {
                res.push(num);
            } else if (s > max) {
                max = s;
                res = [num];
            }
        });
        var m = new Matrix(this);
        res.forEach(function (num, i) {
            m.set(i, 0, num);
        });
        return m;
    }).args([[
            'numbers',
            [
                'collect',
                'number'
            ]
        ]]);
    defineFunction('geomean', function (numbers) {
        var n = numbers.length;
        var p = numbers.reduce(function (p, num) {
            if (num < 0) {
                throw new CalcError('NUM');
            }
            return p * num;
        }, 1);
        return Math.pow(p, 1 / n);
    }).args([
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length > 0',
                'NUM'
            ]
        ]
    ]);
    defineFunction('harmean', function (numbers) {
        var n = numbers.length;
        var s = numbers.reduce(function (s, num) {
            if (!num) {
                throw new CalcError('DIV/0');
            }
            return s + 1 / num;
        }, 0);
        return n / s;
    }).args([
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length > 0',
                'NUM'
            ]
        ]
    ]);
    defineFunction('trimmean', function (numbers, p) {
        var n = numbers.length;
        numbers.sort(ascending);
        var discard = Math.floor(n * p);
        if (discard % 2) {
            --discard;
        }
        discard /= 2;
        var sum = 0;
        for (var i = discard; i < n - discard; ++i) {
            sum += numbers[i];
        }
        return sum / (n - discard * 2);
    }).args([
        [
            'numbers',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'percent',
            [
                'and',
                'number',
                [
                    '[between)',
                    0,
                    1
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length > 0',
                'NUM'
            ]
        ]
    ]);
    defineFunction('frequency', function (data, bins) {
        data.sort(ascending);
        bins.sort(ascending);
        var prev = -Infinity;
        var i = 0;
        function count(max) {
            var n = 0;
            while (i < data.length && data[i] > prev && data[i] <= max) {
                ++n;
                ++i;
            }
            return n;
        }
        var m = new Matrix(this);
        bins.forEach(function (val, i) {
            var n = count(val);
            prev = val;
            m.set(i, 0, n);
        });
        m.set(m.height, 0, data.length - i);
        return m;
    }).args([
        [
            'data',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'bins',
            [
                'collect',
                'number',
                1
            ]
        ]
    ]);
    defineFunction('rank.eq', function (val, numbers, asc) {
        numbers.sort(asc ? ascending : descending);
        var pos = numbers.indexOf(val);
        return pos < 0 ? new CalcError('N/A') : pos + 1;
    }).args([
        [
            'value',
            'number'
        ],
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            'order',
            [
                'or',
                'logical',
                [
                    'null',
                    false
                ]
            ]
        ]
    ]);
    defineAlias('rank', 'rank.eq');
    defineFunction('rank.avg', function (val, numbers, asc) {
        numbers.sort(asc ? ascending : descending);
        var pos = numbers.indexOf(val);
        if (pos < 0) {
            return new CalcError('N/A');
        }
        for (var i = pos; numbers[i] == val; ++i) {
        }
        return (pos + i + 1) / 2;
    }).args([
        [
            'value',
            'number'
        ],
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            'order',
            [
                'or',
                'logical',
                [
                    'null',
                    false
                ]
            ]
        ]
    ]);
    defineFunction('kurt', function (numbers) {
        var n = numbers.length;
        var avg = _avg(numbers);
        var variance = _var_sp(numbers, n - 1, avg);
        var stddev = Math.sqrt(variance);
        var sum = numbers.reduce(function (sum, num) {
            return sum + Math.pow((num - avg) / stddev, 4);
        }, 0);
        return n * (n + 1) / ((n - 1) * (n - 2) * (n - 3)) * sum - 3 * Math.pow(n - 1, 2) / ((n - 2) * (n - 3));
    }).args([
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length >= 4',
                'NUM'
            ]
        ]
    ]);
    function _percentrank(numbers, x, exc) {
        var nlt = 0, ngt = 0, left = null, right = null, found = false;
        numbers.forEach(function (num) {
            if (num < x) {
                nlt++;
                left = left == null ? num : Math.max(left, num);
            } else if (num > x) {
                ngt++;
                right = right == null ? num : Math.min(right, num);
            } else {
                found = true;
            }
        });
        if (!nlt && !ngt) {
            return new CalcError('N/A');
        }
        if (found) {
            if (exc) {
                return (nlt + 1) / (numbers.length + 1);
            }
            return nlt / (nlt + ngt);
        }
        return ((right - x) * _percentrank(numbers, left, exc) + (x - left) * _percentrank(numbers, right, exc)) / (right - left);
    }
    var ARGS_PERCENTRANK = [
        [
            'array',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'x',
            'number'
        ],
        [
            'significance',
            [
                'or',
                [
                    'null',
                    3
                ],
                'integer++'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$array.length > 0',
                'NUM'
            ]
        ]
    ];
    defineFunction('percentrank.inc', function (numbers, x, significance) {
        var p = _percentrank(numbers, x, 0);
        p = p.toFixed(significance + 1);
        return parseFloat(p.substr(0, p.length - 1));
    }).args(ARGS_PERCENTRANK);
    defineFunction('percentrank.exc', function (numbers, x, significance) {
        var p = _percentrank(numbers, x, 1);
        p = p.toFixed(significance + 1);
        return parseFloat(p.substr(0, p.length - 1));
    }).args(ARGS_PERCENTRANK);
    defineAlias('percentrank', 'percentrank.inc');
    function _covariance(x, y, divisor) {
        var sum = 0;
        var ax = _avg(x);
        var ay = _avg(y);
        var n = x.length;
        for (var i = 0; i < n; ++i) {
            sum += (x[i] - ax) * (y[i] - ay);
        }
        return sum / divisor;
    }
    defineFunction('covariance.p', function (x, y) {
        return _covariance(x, y, x.length);
    }).args([
        [
            'array1',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'array2',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            '?',
            [
                'assert',
                '$array1.length == $array2.length',
                'N/A'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$array1.length > 0',
                'DIV/0'
            ]
        ]
    ]);
    defineFunction('covariance.s', function (x, y) {
        return _covariance(x, y, x.length - 1);
    }).args([
        [
            'array1',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'array2',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            '?',
            [
                'assert',
                '$array1.length == $array2.length',
                'N/A'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$array1.length > 1',
                'DIV/0'
            ]
        ]
    ]);
    defineAlias('covar', 'covariance.p');
    var _fact = util.memoize(function (n) {
        for (var i = 2, fact = 1; i <= n; ++i) {
            fact *= i;
        }
        return fact;
    });
    defineFunction('fact', _fact).args([[
            '*n',
            'integer+'
        ]]);
    defineFunction('factdouble', function (n) {
        for (var i = 2 + (n & 1), fact = 1; i <= n; i += 2) {
            fact *= i;
        }
        return fact;
    }).args([[
            '*n',
            'integer+'
        ]]);
    defineFunction('multinomial', function (numbers) {
        var div = 1, sum = 0;
        numbers.forEach(function (n) {
            if (n < 0) {
                throw new CalcError('NUM');
            }
            sum += n;
            div *= _fact(n);
        });
        return _fact(sum) / div;
    }).args([[
            'numbers',
            [
                'collect',
                'number'
            ]
        ]]);
    var _combinations = util.memoize(function (n, k) {
        for (var f1 = k + 1, f2 = 1, p1 = 1, p2 = 1; f2 <= n - k; ++f1, ++f2) {
            p1 *= f1;
            p2 *= f2;
        }
        return p1 / p2;
    });
    defineFunction('combin', _combinations).args([
        [
            '*n',
            'integer++'
        ],
        [
            '*k',
            [
                'and',
                'integer',
                [
                    '[between]',
                    0,
                    '$n'
                ]
            ]
        ]
    ]);
    defineFunction('combina', function (n, k) {
        return _combinations(n + k - 1, n - 1);
    }).args([
        [
            '*n',
            'integer++'
        ],
        [
            '*k',
            [
                'and',
                'integer',
                [
                    '[between]',
                    1,
                    '$n'
                ]
            ]
        ]
    ]);
    defineFunction('average', function (numbers) {
        var sum = numbers.reduce(function (sum, num) {
            return sum + num;
        }, 0);
        return sum / numbers.length;
    }).args([
        [
            'numbers',
            [
                'collect',
                'number!'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length > 0',
                'DIV/0'
            ]
        ]
    ]);
    defineFunction('averagea', function (values) {
        var sum = 0, count = 0;
        values.forEach(function (num) {
            if (typeof num != 'string') {
                sum += num;
            }
            ++count;
        });
        return count ? sum / count : new CalcError('DIV/0');
    }).args([[
            'values',
            [
                'collect',
                'anyvalue'
            ]
        ]]);
    function _percentile(numbers, rank) {
        numbers.sort(ascending);
        var n = numbers.length;
        var k = rank | 0, d = rank - k;
        if (k === 0) {
            return numbers[0];
        }
        if (k >= n) {
            return numbers[n - 1];
        }
        --k;
        return numbers[k] + d * (numbers[k + 1] - numbers[k]);
    }
    function _percentile_inc(numbers, p) {
        var rank = p * (numbers.length - 1) + 1;
        return _percentile(numbers, rank);
    }
    function _percentile_exc(numbers, p) {
        var rank = p * (numbers.length + 1);
        return _percentile(numbers, rank);
    }
    defineFunction('percentile.inc', _percentile_inc).args([
        [
            'numbers',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'p',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ]
    ]);
    defineFunction('percentile.exc', _percentile_exc).args([
        [
            'numbers',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'p',
            [
                'and',
                'number',
                [
                    '(between)',
                    0,
                    1
                ]
            ]
        ]
    ]);
    defineFunction('quartile.inc', function (numbers, quarter) {
        return _percentile_inc(numbers, quarter / 4);
    }).args([
        [
            'numbers',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'quarter',
            [
                'values',
                0,
                1,
                2,
                3,
                4
            ]
        ]
    ]);
    defineFunction('quartile.exc', function (numbers, quarter) {
        return _percentile_exc(numbers, quarter / 4);
    }).args([
        [
            'numbers',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'quarter',
            [
                'values',
                0,
                1,
                2,
                3,
                4
            ]
        ]
    ]);
    defineAlias('quartile', 'quartile.inc');
    defineAlias('percentile', 'percentile.inc');
    var AGGREGATE_FUNCS = [
        'AVERAGE',
        'COUNT',
        'COUNTA',
        'MAX',
        'MIN',
        'PRODUCT',
        'STDEV.S',
        'STDEV.P',
        'SUM',
        'VAR.S',
        'VAR.P',
        'MEDIAN',
        'MODE.SNGL',
        'LARGE',
        'SMALL',
        'PERCENTILE.INC',
        'QUARTILE.INC',
        'PERCENTILE.EXC',
        'QUARTILE.EXC'
    ];
    function fetchValuesForAggregate(self, args, options) {
        var values = [];
        var opt_ignore_hidden_rows = 1;
        var opt_ignore_errors = 2;
        var opt_use_aggregates = 4;
        (function fetchValues(args) {
            if (args instanceof Ref) {
                self.getRefCells(args, true).forEach(function (cell) {
                    var value = cell.value;
                    if (options & opt_ignore_hidden_rows && cell.hidden) {
                        return;
                    }
                    if (cell.formula) {
                        var str = cell.formula.print(cell.row, cell.col);
                        if (/^\s*(?:aggregate|subtotal)\s*\(/i.test(str)) {
                            if (!(options & opt_use_aggregates)) {
                                return;
                            }
                        }
                        if ('value' in cell.formula) {
                            value = cell.formula.value;
                        }
                    }
                    if (options & opt_ignore_errors && value instanceof CalcError) {
                        return;
                    }
                    if (typeof value == 'number' || value instanceof CalcError) {
                        values.push(value);
                    }
                });
            } else if (Array.isArray(args)) {
                for (var i = 0; i < args.length; ++i) {
                    fetchValues(args[i]);
                }
            } else if (args instanceof Matrix) {
                args.each(fetchValues);
            } else if (typeof args == 'number') {
                values.push(args);
            } else if (args instanceof CalcError && !(options & opt_ignore_errors)) {
                values.push(args);
            }
        }(args));
        return values;
    }
    defineFunction('aggregate', function (callback, funcId, options, args) {
        var self = this;
        self.resolveCells(args, function () {
            var values;
            if (funcId > 12) {
                values = fetchValuesForAggregate(self, args[0], options);
                var k = args[1];
                if (k instanceof CellRef) {
                    k = self.getRefData(k);
                }
                if (typeof k != 'number') {
                    return callback(new CalcError('VALUE'));
                }
            } else {
                values = fetchValuesForAggregate(self, args, options);
            }
            self.func(AGGREGATE_FUNCS[funcId - 1], callback, values);
        });
    }).argsAsync([
        [
            'funcId',
            [
                'values',
                1,
                2,
                3,
                4,
                5,
                6,
                7,
                8,
                9,
                10,
                11,
                12,
                13,
                14,
                15,
                16,
                17,
                18,
                19
            ]
        ],
        [
            'options',
            [
                'or',
                [
                    'null',
                    0
                ],
                [
                    'values',
                    0,
                    1,
                    2,
                    3,
                    4,
                    5,
                    6,
                    7
                ]
            ]
        ],
        [
            'args',
            'rest'
        ]
    ]);
    defineFunction('subtotal', function (callback, funcId) {
        var self = this;
        var ignoreHidden = funcId > 100;
        if (ignoreHidden) {
            funcId -= 100;
        }
        var args = [];
        for (var i = 2; i < arguments.length; ++i) {
            args.push(arguments[i]);
        }
        self.resolveCells(args, function () {
            var values = fetchValuesForAggregate(self, args, ignoreHidden ? 1 : 0);
            self.func(AGGREGATE_FUNCS[funcId - 1], callback, values);
        });
    }).argsAsync([
        [
            'funcId',
            [
                'values',
                1,
                2,
                3,
                4,
                5,
                6,
                7,
                8,
                9,
                10,
                11,
                101,
                102,
                103,
                104,
                105,
                106,
                107,
                108,
                109,
                110,
                111
            ]
        ],
        [
            '+',
            [
                'ref',
                [
                    'or',
                    'ref',
                    '#matrix'
                ]
            ]
        ]
    ]);
    defineFunction('avedev', function (numbers) {
        var avg = numbers.reduce(function (sum, num) {
            return sum + num;
        }, 0) / numbers.length;
        return numbers.reduce(function (sum, num) {
            return sum + Math.abs(num - avg);
        }, 0) / numbers.length;
    }).args([
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length >= 2',
                'NUM'
            ]
        ]
    ]);
    function _binom_dist(x, n, p, cumulative) {
        if (!cumulative) {
            return _combinations(n, x) * Math.pow(p, x) * Math.pow(1 - p, n - x);
        } else {
            var sum = 0;
            for (var j = 0; j <= x; ++j) {
                sum += _combinations(n, j) * Math.pow(p, j) * Math.pow(1 - p, n - j);
            }
            return sum;
        }
    }
    defineFunction('binom.dist', _binom_dist).args([
        [
            'successes',
            'integer+'
        ],
        [
            'trials',
            [
                'and',
                'integer',
                [
                    'assert',
                    '$trials >= $successes'
                ]
            ]
        ],
        [
            'probability',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'cumulative',
            'logical'
        ]
    ]);
    defineAlias('binomdist', 'binom.dist');
    defineFunction('binom.inv', function (n, p, alpha) {
        for (var x = 0; x <= n; ++x) {
            if (_binom_dist(x, n, p, true) >= alpha) {
                return x;
            }
        }
        return new CalcError('N/A');
    }).args([
        [
            'trials',
            'integer+'
        ],
        [
            'probability',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'alpha',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ]
    ]);
    defineAlias('critbinom', 'binom.inv');
    defineFunction('binom.dist.range', function (n, p, s, s2) {
        var sum = 0;
        for (var k = s; k <= s2; ++k) {
            sum += _combinations(n, k) * Math.pow(p, k) * Math.pow(1 - p, n - k);
        }
        return sum;
    }).args([
        [
            'trials',
            'integer+'
        ],
        [
            'probability',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'successes_min',
            [
                'and',
                'integer',
                [
                    '[between]',
                    0,
                    '$trials'
                ]
            ]
        ],
        [
            'successes_max',
            [
                'or',
                [
                    'and',
                    'integer',
                    [
                        '[between]',
                        '$successes_min',
                        '$trials'
                    ]
                ],
                [
                    'null',
                    '$successes_min'
                ]
            ]
        ]
    ]);
    defineFunction('negbinom.dist', function (x, k, p, cumulative) {
        if (cumulative) {
            var sum = 0;
            while (x >= 0) {
                sum += _combinations(x + k - 1, x) * Math.pow(p, k) * Math.pow(1 - p, x);
                x--;
            }
            return sum;
        }
        return _combinations(x + k - 1, x) * Math.pow(p, k) * Math.pow(1 - p, x);
    }).args([
        [
            'number_f',
            'integer+'
        ],
        [
            'number_s',
            'integer+'
        ],
        [
            'probability_s',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'cumulative',
            'logical'
        ]
    ]);
    defineAlias('negbinomdist', 'negbinom.dist');
    defineFunction('address', function (row, col, abs, a1, sheet) {
        var cell = new CellRef(row - 1, col - 1, abs - 1);
        if (sheet) {
            cell.setSheet(sheet, true);
        }
        return a1 ? cell.print(0, 0) : cell.print();
    }).args([
        [
            'row',
            'integer++'
        ],
        [
            'col',
            'integer++'
        ],
        [
            'abs',
            [
                'or',
                [
                    'null',
                    1
                ],
                [
                    'values',
                    1,
                    2,
                    3,
                    4
                ]
            ]
        ],
        [
            'a1',
            [
                'or',
                [
                    'null',
                    true
                ],
                'logical'
            ]
        ],
        [
            'sheet',
            [
                'or',
                'null',
                'string'
            ]
        ]
    ]);
    defineFunction('areas', function (ref) {
        var count = 0;
        (function loop(x) {
            if (x instanceof CellRef || x instanceof RangeRef) {
                count++;
            } else if (x instanceof UnionRef) {
                x.refs.forEach(loop);
            }
        }(ref));
        return count;
    }).args([[
            'ref',
            'ref'
        ]]);
    defineFunction('choose', function (index, args) {
        if (index > args.length) {
            return new CalcError('N/A');
        } else {
            return args[index - 1];
        }
    }).args([
        [
            '*index',
            'integer'
        ],
        [
            '+',
            [
                'value',
                'anything'
            ]
        ]
    ]);
    defineFunction('column', function (ref) {
        if (!ref) {
            return this.formula.col + 1;
        }
        if (ref instanceof CellRef) {
            return ref.col + 1;
        }
        return this.asMatrix(ref).mapCol(function (col) {
            return col + ref.topLeft.col + 1;
        });
    }).args([[
            'ref',
            [
                'or',
                'area',
                'null'
            ]
        ]]);
    defineFunction('columns', function (m) {
        return m instanceof Ref ? m.width() : m.width;
    }).args([[
            'ref',
            [
                'or',
                'area',
                '#matrix'
            ]
        ]]);
    defineFunction('formulatext', function (ref) {
        var cell = this.getRefCells(ref)[0];
        if (!cell.formula) {
            return new CalcError('N/A');
        }
        return cell.formula.print(cell.row, cell.col);
    }).args([[
            'ref',
            'ref'
        ]]);
    defineFunction('hlookup', function (value, m, row, approx) {
        var resultCol = null;
        m.eachCol(function (col) {
            var data = m.get(0, col);
            if (approx) {
                if (data > value) {
                    return true;
                }
                resultCol = col;
            } else if (data === value) {
                resultCol = col;
                return true;
            }
        });
        if (resultCol == null) {
            return new CalcError('N/A');
        }
        return m.get(row - 1, resultCol);
    }).args([
        [
            'value',
            'anyvalue'
        ],
        [
            'range',
            'matrix'
        ],
        [
            'row',
            'integer++'
        ],
        [
            'approx',
            [
                'or',
                'logical',
                [
                    'null',
                    true
                ]
            ]
        ]
    ]);
    defineFunction('index', function (callback, ref, row, col, areanum) {
        var self = this;
        if (ref instanceof UnionRef) {
            ref = ref.refs[areanum - 1];
        }
        if (!row && !col || !ref) {
            return callback(new CalcError('N/A'));
        }
        if (ref instanceof CellRef) {
            ref = ref.toRangeRef();
        }
        if (ref instanceof RangeRef) {
            if (row && col) {
                if (col > ref.width() || row > ref.height()) {
                    return callback(new CalcError('REF'));
                }
                var cell = ref.toCell(row - 1, col - 1);
                self.resolveCells([cell], function () {
                    callback(self.getRefData(cell));
                });
                return;
            }
            if (!row) {
                var colRange = ref.toColumn(col - 1);
                self.resolveCells([colRange], function () {
                    callback(self.asMatrix(colRange));
                });
                return;
            }
            if (!col) {
                var rowRange = ref.toRow(row - 1);
                self.resolveCells([rowRange], function () {
                    callback(self.asMatrix(rowRange));
                });
                return;
            }
        } else if (ref instanceof Matrix) {
            if (ref.width > 1 && ref.height > 1) {
                if (row && col) {
                    return callback(ref.get(row - 1, col - 1));
                }
                if (!row) {
                    return callback(ref.mapRow(function (row) {
                        return ref.get(row, col - 1);
                    }));
                }
                if (!col) {
                    return callback(ref.mapCol(function (col) {
                        return ref.get(row - 1, col);
                    }));
                }
            }
            if (ref.width == 1) {
                return callback(ref.get(row - 1, 0));
            }
            if (ref.height == 1) {
                return callback(ref.get(0, col - 1));
            }
        } else {
            callback(new CalcError('REF'));
        }
    }).argsAsync([
        [
            'range',
            [
                'or',
                'ref',
                'matrix'
            ]
        ],
        [
            'row',
            [
                'or',
                'integer+',
                'null'
            ]
        ],
        [
            'col',
            [
                'or',
                'integer+',
                'null'
            ]
        ],
        [
            'areanum',
            [
                'or',
                'integer++',
                [
                    'null',
                    1
                ]
            ]
        ]
    ]);
    defineFunction('indirect', function (thing) {
        try {
            var f = this.formula;
            var exp = calc.parseFormula(f.sheet, f.row, f.col, thing);
            if (!(exp.ast instanceof Ref)) {
                throw 1;
            }
            return exp.ast.absolute(f.row, f.col);
        } catch (ex) {
            return new CalcError('REF');
        }
    }).args([[
            'thing',
            'string'
        ]]);
    defineFunction('match', function (val, m, type) {
        var index = 1, cmp;
        if (type === 0) {
            cmp = parseCriteria(val);
        } else if (type === -1) {
            cmp = parseCriteria('<=' + val);
        } else if (type === 1) {
            cmp = parseCriteria('>=' + val);
        }
        if (m.each(function (el) {
                if (el != null && cmp(el)) {
                    if (type !== 0 && val != el) {
                        --index;
                    }
                    return true;
                }
                index++;
            }, true) && index > 0) {
            return index;
        } else {
            return new CalcError('N/A');
        }
    }).args([
        [
            'value',
            'anyvalue'
        ],
        [
            'range',
            'matrix'
        ],
        [
            'type',
            [
                'or',
                [
                    'values',
                    -1,
                    0,
                    1
                ],
                [
                    'null',
                    1
                ]
            ]
        ]
    ]);
    defineFunction('offset', function (ref, rows, cols, height, width) {
        var topLeft = (ref instanceof CellRef ? ref : ref.topLeft).clone();
        topLeft.row += rows;
        topLeft.col += cols;
        if (topLeft.row < 0 || topLeft.col < 0) {
            return new CalcError('VALUE');
        }
        if (height > 1 || width > 1) {
            return new RangeRef(topLeft, new CellRef(topLeft.row + height - 1, topLeft.col + width - 1)).setSheet(ref.sheet, ref.hasSheet());
        }
        return topLeft;
    }).args([
        [
            'ref',
            'area'
        ],
        [
            '*rows',
            'integer'
        ],
        [
            '*cols',
            'integer'
        ],
        [
            '*height',
            [
                'or',
                'integer++',
                [
                    'null',
                    '$ref.height()'
                ]
            ]
        ],
        [
            '*width',
            [
                'or',
                'integer++',
                [
                    'null',
                    '$ref.width()'
                ]
            ]
        ]
    ]);
    defineFunction('row', function (ref) {
        if (!ref) {
            return this.formula.row + 1;
        }
        if (ref instanceof CellRef) {
            return ref.row + 1;
        }
        return this.asMatrix(ref).mapRow(function (row) {
            return row + ref.topLeft.row + 1;
        });
    }).args([[
            'ref',
            [
                'or',
                'area',
                'null'
            ]
        ]]);
    defineFunction('rows', function (m) {
        return m instanceof Ref ? m.height() : m.height;
    }).args([[
            'ref',
            [
                'or',
                'area',
                '#matrix'
            ]
        ]]);
    defineFunction('vlookup', function (value, m, col, approx) {
        var resultRow = null;
        if (typeof value != 'number') {
            approx = false;
        }
        if (typeof value == 'string') {
            value = value.toLowerCase();
        }
        m.eachRow(function (row) {
            var data = m.get(row, 0);
            if (approx) {
                if (data > value) {
                    return true;
                }
                resultRow = row;
            } else {
                if (typeof data == 'string') {
                    data = data.toLowerCase();
                }
                if (data === value) {
                    resultRow = row;
                    return true;
                }
            }
        });
        if (resultRow == null) {
            return new CalcError('N/A');
        }
        return m.get(resultRow, col - 1);
    }).args([
        [
            'value',
            'anyvalue'
        ],
        [
            'range',
            'matrix'
        ],
        [
            'col',
            'integer++'
        ],
        [
            'approx',
            [
                'or',
                'logical',
                [
                    'null',
                    true
                ]
            ]
        ]
    ]);
    defineFunction('date', function (year, month, date) {
        return packDate(year, month - 1, date);
    }).args([
        [
            '*year',
            'integer'
        ],
        [
            '*month',
            'integer'
        ],
        [
            '*date',
            'integer'
        ]
    ]);
    defineFunction('day', function (date) {
        return unpackDate(date).date;
    }).args([[
            '*date',
            'date'
        ]]);
    defineFunction('month', function (date) {
        return unpackDate(date).month + 1;
    }).args([[
            '*date',
            'date'
        ]]);
    defineFunction('year', function (date) {
        return unpackDate(date).year;
    }).args([[
            '*date',
            'date'
        ]]);
    defineFunction('weekday', function (date) {
        return unpackDate(date).day + 1;
    }).args([[
            '*date',
            'date'
        ]]);
    defineFunction('weeknum', function (date, type) {
        var fw = packDate(unpackDate(date).year, 0, 1);
        var sy = unpackDate(fw);
        var diff;
        if (type == 21) {
            diff = 3 - (sy.day + 6) % 7;
            if (diff < 0) {
                diff += 7;
            }
            fw += diff;
            sy.date += diff;
            sy.day = 4;
            type = 1;
        } else {
            if (type == 1) {
                type = 0;
            } else if (type == 2) {
                type = 1;
            } else {
                type = (type - 10) % 7;
            }
        }
        diff = sy.day - type;
        if (diff < 0) {
            diff += 7;
        }
        fw -= diff;
        return Math.ceil((date + 1 - fw) / 7);
    }).args([
        [
            '*date',
            'date'
        ],
        [
            '*type',
            [
                'or',
                [
                    'null',
                    1
                ],
                [
                    'values',
                    1,
                    2,
                    11,
                    12,
                    13,
                    14,
                    15,
                    16,
                    17,
                    21
                ]
            ]
        ]
    ]);
    function weeksInYear(year) {
        var d = unpackDate(packDate(year, 0, 1));
        if (d.day == 4 || d.day == 3 && runtime.isLeapYear(year)) {
            return 53;
        }
        return 52;
    }
    defineFunction('isoweeknum', function isoweeknum(date) {
        var d = unpackDate(date);
        var dow = d.day || 7;
        var wk = Math.floor((d.ord - dow + 10) / 7);
        if (wk < 1) {
            return weeksInYear(d.year - 1);
        } else if (wk == 53 && wk > weeksInYear(d.year)) {
            return 1;
        }
        return wk;
    }).args([[
            '*date',
            'date'
        ]]);
    defineFunction('now', function () {
        return runtime.dateToSerial(new Date());
    }).args([]);
    defineFunction('today', function () {
        return runtime.dateToSerial(new Date()) | 0;
    }).args([]);
    defineFunction('time', function (hh, mm, ss) {
        return runtime.packTime(hh, mm, ss, 0);
    }).args([
        [
            '*hours',
            'integer'
        ],
        [
            '*minutes',
            'integer'
        ],
        [
            '*seconds',
            'integer'
        ]
    ]);
    defineFunction('hour', function (time) {
        return runtime.unpackTime(time).hours;
    }).args([[
            '*time',
            'datetime'
        ]]);
    defineFunction('minute', function (time) {
        return runtime.unpackTime(time).minutes;
    }).args([[
            '*time',
            'datetime'
        ]]);
    defineFunction('second', function (time) {
        return runtime.unpackTime(time).seconds;
    }).args([[
            '*time',
            'datetime'
        ]]);
    defineFunction('edate', function (base, months) {
        var d = unpackDate(base);
        var m = d.month + months;
        var y = d.year + Math.floor(m / 12);
        m %= 12;
        if (m < 0) {
            m += 12;
        }
        d = Math.min(d.date, daysInMonth(y, m));
        return packDate(y, m, d);
    }).args([
        [
            '*start_date',
            'date'
        ],
        [
            '*months',
            'integer'
        ]
    ]);
    defineFunction('eomonth', function (base, months) {
        var d = unpackDate(base);
        var m = d.month + months;
        var y = d.year + Math.floor(m / 12);
        m %= 12;
        if (m < 0) {
            m += 12;
        }
        d = daysInMonth(y, m);
        return packDate(y, m, d);
    }).args([
        [
            '*start_date',
            'date'
        ],
        [
            '*months',
            'integer'
        ]
    ]);
    defineFunction('workday', function (date, n, holidays) {
        var inc = n > 0 ? 1 : -1;
        n = Math.abs(n);
        var dow = unpackDate(date).day;
        while (n > 0) {
            date += inc;
            dow = (dow + inc) % 7;
            if (dow > 0 && dow < 6 && holidays.indexOf(date) < 0) {
                --n;
            }
        }
        return date;
    }).args([
        [
            'start_date',
            'date'
        ],
        [
            'days',
            'integer'
        ],
        [
            'holidays',
            [
                'collect',
                'date'
            ]
        ]
    ]);
    defineFunction('networkdays', function (date, end, holidays) {
        if (date > end) {
            var tmp = date;
            date = end;
            end = tmp;
        }
        var count = 0;
        var dow = unpackDate(date).day;
        while (date <= end) {
            if (dow > 0 && dow < 6 && holidays.indexOf(date) < 0) {
                count++;
            }
            date++;
            dow = (dow + 1) % 7;
        }
        return count;
    }).args([
        [
            'start_date',
            'date'
        ],
        [
            'end_date',
            'date'
        ],
        [
            'holidays',
            [
                'collect',
                'date'
            ]
        ]
    ]);
    defineFunction('days', function (start, end) {
        return end - start;
    }).args([
        [
            '*start_date',
            'date'
        ],
        [
            '*end_date',
            'date'
        ]
    ]);
    function _days_360(start, end, method) {
        var d1 = unpackDate(start);
        var d2 = unpackDate(end);
        if (method) {
            if (d1.date == 31) {
                d1.date = 30;
            }
            if (d2.date == 31) {
                d2.date = 30;
            }
        } else {
            if (d1.month == 1 && d2.month == 1 && d1.date == daysInMonth(d1.year, 1) && d2.date == daysInMonth(d2.year, 1)) {
                d2.date = 30;
            }
            if (d1.date == daysInMonth(d1.year, d1.month)) {
                d1.date = 30;
                if (d2.date == 31) {
                    d2.date = 30;
                }
            } else {
                if (d1.date == 30 && d2.date == 31) {
                    d2.date = 30;
                }
            }
        }
        return 360 * (d2.year - d1.year) + 30 * (d2.month - d1.month) + (d2.date - d1.date);
    }
    runtime._days_360 = _days_360;
    defineFunction('days360', _days_360).args([
        [
            '*start_date',
            'date'
        ],
        [
            '*end_date',
            'date'
        ],
        [
            '*method',
            [
                'or',
                'logical',
                [
                    'null',
                    false
                ]
            ]
        ]
    ]);
    defineFunction('yearfrac', function (start, end, method) {
        switch (method) {
        case 0:
            return _days_360(start, end, false) / 360;
        case 1:
            return (end - start) / daysInYear(unpackDate(start).year);
        case 2:
            return (end - start) / 360;
        case 3:
            return (end - start) / 365;
        case 4:
            return _days_360(start, end, true) / 360;
        }
    }).args([
        [
            '*start_date',
            'date'
        ],
        [
            '*end_date',
            'date'
        ],
        [
            '*method',
            [
                'or',
                [
                    'null',
                    0
                ],
                [
                    'values',
                    0,
                    1,
                    2,
                    3,
                    4
                ]
            ]
        ]
    ]);
    defineFunction('datevalue', function (text) {
        var date = runtime.parseDate(text);
        if (date) {
            return runtime.dateToSerial(date);
        }
        return new CalcError('VALUE');
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('timevalue', function (text) {
        var m = text.toLowerCase().match(/(\d+):(\d+)(:(\d+)(\.(\d+))?)?\s*(am?|pm?)?/);
        if (m) {
            var hh = parseFloat(m[1]);
            var mm = parseFloat(m[2]);
            var ss = m[3] ? parseFloat(m[4]) : 0;
            var ampm = m[7];
            if (ampm && (hh > 12 || hh < 1)) {
                return new CalcError('VALUE');
            }
            if (/^p/.test(ampm)) {
                hh += 12;
            }
            return runtime.packTime(hh, mm, ss, 0);
        }
        return new CalcError('VALUE');
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('mdeterm', function (m) {
        var error = m.each(function (val) {
            if (typeof val != 'number') {
                return new CalcError('VALUE');
            }
        }, true);
        return error || m.determinant();
    }).args([[
            'm',
            [
                'and',
                'matrix',
                [
                    'assert',
                    '$m.width == $m.height'
                ]
            ]
        ]]);
    defineFunction('transpose', function (m) {
        return m.transpose();
    }).args([[
            'range',
            'matrix'
        ]]);
    defineFunction('mmult', function (a, b) {
        return a.multiply(b);
    }).args([
        [
            'a',
            'matrix'
        ],
        [
            'b',
            [
                'and',
                'matrix',
                [
                    'assert',
                    '$b.height == $a.width'
                ]
            ]
        ]
    ]);
    defineFunction('munit', function (n) {
        return new Matrix(this).unit(n);
    }).args([[
            'n',
            'integer+'
        ]]);
    defineFunction('minverse', function (m) {
        var error = m.each(function (val) {
            if (typeof val != 'number') {
                return new CalcError('VALUE');
            }
        }, true);
        return error || m.inverse() || new CalcError('VALUE');
    }).args([[
            'm',
            [
                'and',
                'matrix',
                [
                    'assert',
                    '$m.width == $m.height'
                ]
            ]
        ]]);
    defineFunction('rand', function () {
        return Math.random();
    }).args([]);
    defineFunction('randbetween', function (min, max) {
        return min + Math.floor((max - min + 1) * Math.random());
    }).args([
        [
            'min',
            'integer'
        ],
        [
            'max',
            [
                'and',
                'integer',
                [
                    'assert',
                    '$max >= $min'
                ]
            ]
        ]
    ]);
    defineFunction('true', function () {
        return true;
    }).args([]);
    defineFunction('false', function () {
        return true;
    }).args([]);
    defineFunction('roman', function (num) {
        return util.arabicToRoman(num).toUpperCase();
    }).args([[
            '*number',
            'integer'
        ]]);
    defineFunction('arabic', function (rom) {
        var num = util.romanToArabic(rom);
        return num == null ? new CalcError('VALUE') : num;
    }).args([[
            '*roman',
            'string'
        ]]);
    defineFunction('base', function (number, radix, minLen) {
        var str = number.toString(radix).toUpperCase();
        while (str.length < minLen) {
            str = '0' + str;
        }
        return str;
    }).args([
        [
            '*number',
            'integer'
        ],
        [
            '*radix',
            [
                'and',
                'integer',
                [
                    '[between]',
                    2,
                    36
                ]
            ]
        ],
        [
            '*minLen',
            [
                'or',
                'integer+',
                [
                    'null',
                    0
                ]
            ]
        ]
    ]);
    defineFunction('decimal', function (text, radix) {
        text = text.toUpperCase();
        var val = 0;
        for (var i = 0; i < text.length; ++i) {
            var d = text.charCodeAt(i);
            if (d >= 48 && d <= 57) {
                d -= 48;
            } else if (d >= 65 && d < 55 + radix) {
                d -= 55;
            } else {
                return new CalcError('VALUE');
            }
            val = val * radix + d;
        }
        return val;
    }).args([
        [
            '*text',
            'string'
        ],
        [
            '*radix',
            [
                'and',
                'integer',
                [
                    '[between]',
                    2,
                    36
                ]
            ]
        ]
    ]);
    defineFunction('char', function (code) {
        return String.fromCharCode(code);
    }).args([[
            '*code',
            'integer+'
        ]]);
    var RX_NON_PRINTABLE = /[\0-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
    defineFunction('clean', function (text) {
        return text.replace(RX_NON_PRINTABLE, '');
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('code', function (text) {
        return text.charAt(0);
    }).args([[
            '*text',
            'string'
        ]]);
    defineAlias('unichar', 'char');
    defineAlias('unicode', 'code');
    defineFunction('concatenate', function (args) {
        var out = '';
        for (var i = 0; i < args.length; ++i) {
            out += args[i];
        }
        return out;
    }).args([[
            '+',
            [
                '*text',
                'string'
            ]
        ]]);
    defineFunction('dollar', function (number, decimals) {
        var format = '$#,##0DECIMALS;($#,##0DECIMALS)';
        var dec = '';
        var denomitator = 1;
        while (decimals-- > 0) {
            dec += '0';
        }
        while (++decimals < 0) {
            denomitator *= 10;
        }
        if (dec !== '') {
            dec = '.' + dec;
        } else if (denomitator !== 1) {
            number = Math.round(number / denomitator) * denomitator;
        }
        format = format.replace(/DECIMALS/g, dec);
        return spreadsheet.formatting.text(number, format);
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*decimals',
            [
                'or',
                'integer',
                [
                    'null',
                    2
                ]
            ]
        ]
    ]);
    defineFunction('exact', function (a, b) {
        return a === b;
    }).args([
        [
            '*text1',
            'string'
        ],
        [
            '*text2',
            'string'
        ]
    ]);
    defineFunction('find', function (substring, string, start) {
        var pos = string.indexOf(substring, start - 1);
        return pos < 0 ? new CalcError('VALUE') : pos + 1;
    }).args([
        [
            '*substring',
            'string'
        ],
        [
            '*string',
            'string'
        ],
        [
            '*start',
            [
                'or',
                'integer++',
                [
                    'null',
                    1
                ]
            ]
        ]
    ]);
    defineFunction('fixed', function (number, decimals, noCommas) {
        var scale = Math.pow(10, decimals);
        number = Math.round(number * scale) / scale;
        var format = noCommas ? '0' : '#,##0';
        if (decimals > 0) {
            format += '.';
            while (decimals-- > 0) {
                format += '0';
            }
        }
        return spreadsheet.formatting.text(number, format);
    }).args([
        [
            '*number',
            'number'
        ],
        [
            '*decimals',
            [
                'or',
                'integer',
                [
                    'null',
                    2
                ]
            ]
        ],
        [
            '*noCommas',
            [
                'or',
                'boolean',
                [
                    'null',
                    false
                ]
            ]
        ]
    ]);
    defineFunction('left', function (text, length) {
        return text.substr(0, length);
    }).args([
        [
            '*text',
            'string'
        ],
        [
            '*length',
            [
                'or',
                'integer+',
                [
                    'null',
                    1
                ]
            ]
        ]
    ]);
    defineFunction('right', function (text, length) {
        return text.substr(-length);
    }).args([
        [
            '*text',
            'string'
        ],
        [
            '*length',
            [
                'or',
                'integer+',
                [
                    'null',
                    1
                ]
            ]
        ]
    ]);
    defineFunction('len', function (text) {
        return text.length;
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('lower', function (text) {
        return text.toLowerCase();
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('upper', function (text) {
        return text.toUpperCase();
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('ltrim', function (text) {
        return text.replace(/^\s+/, '');
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('rtrim', function (text) {
        return text.replace(/\s+$/, '');
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('trim', function (text) {
        return text.replace(/^\s+|\s+$/, '');
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('mid', function (text, start, length) {
        return text.substr(start - 1, length);
    }).args([
        [
            '*text',
            'string'
        ],
        [
            '*start',
            'integer++'
        ],
        [
            '*length',
            'integer+'
        ]
    ]);
    defineFunction('proper', function (text) {
        return text.toLowerCase().replace(/\b./g, function (s) {
            return s.toUpperCase();
        });
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('replace', function (text, start, length, newText) {
        return text.substr(0, --start) + newText + text.substr(start + length);
    }).args([
        [
            '*text',
            'string'
        ],
        [
            '*start',
            'integer++'
        ],
        [
            '*length',
            'integer+'
        ],
        [
            '*newText',
            'string'
        ]
    ]);
    defineFunction('rept', function (text, number) {
        var out = '';
        while (number-- > 0) {
            out += text;
        }
        return out;
    }).args([
        [
            '*text',
            'string'
        ],
        [
            '*number',
            'integer+'
        ]
    ]);
    defineFunction('search', function (substring, string, start) {
        var pos = string.toLowerCase().indexOf(substring.toLowerCase(), start - 1);
        return pos < 0 ? new CalcError('VALUE') : pos + 1;
    }).args([
        [
            '*substring',
            'string'
        ],
        [
            '*string',
            'string'
        ],
        [
            '*start',
            [
                'or',
                'integer++',
                [
                    'null',
                    1
                ]
            ]
        ]
    ]);
    defineFunction('substitute', function (text, oldText, newText, nth) {
        if (oldText === newText) {
            return text;
        }
        var pos = -1;
        function replace() {
            text = text.substring(0, pos) + newText + text.substring(pos + oldText.length);
        }
        while ((pos = text.indexOf(oldText, pos + 1)) >= 0) {
            if (nth == null) {
                replace();
            } else if (--nth === 0) {
                replace();
                break;
            }
        }
        return text;
    }).args([
        [
            '*text',
            'string'
        ],
        [
            '*oldText',
            'string'
        ],
        [
            '*newText',
            'string'
        ],
        [
            '*nth',
            [
                'or',
                'integer++',
                'null'
            ]
        ]
    ]);
    defineFunction('t', function (value) {
        return typeof value == 'string' ? value : '';
    }).args([[
            '*value',
            'anyvalue'
        ]]);
    defineFunction('text', function (value, format) {
        return spreadsheet.formatting.text(value, format);
    }).args([
        [
            '*value',
            'anyvalue'
        ],
        [
            '*format',
            'string'
        ]
    ]);
    defineFunction('value', function (value) {
        if (typeof value == 'number') {
            return value;
        }
        if (typeof value == 'boolean') {
            return +value;
        }
        value = (value + '').replace(/[$€,]/g, '');
        value = parseFloat(value);
        return isNaN(value) ? new CalcError('VALUE') : value;
    }).args([[
            '*value',
            'anyvalue'
        ]]);
    function Hyperlink(link, text) {
        this.link = link;
        this.text = text;
    }
    Hyperlink.prototype.toString = function () {
        return this.text;
    };
    defineFunction('hyperlink', function (link, text) {
        return new Hyperlink(link, text);
    }).args([
        [
            '*link',
            'string'
        ],
        [
            '*text',
            [
                'or',
                'string',
                [
                    'null',
                    '$link'
                ]
            ]
        ]
    ]);
    defineFunction('iferror', function (value, valueIfError) {
        return value instanceof CalcError ? valueIfError : value;
    }).args([
        [
            '*value',
            'forced!'
        ],
        [
            '*value_if_error',
            'anyvalue!'
        ]
    ]);
    var parseCriteria = function () {
        var RXCACHE = Object.create(null);
        function makeComparator(cmp, x) {
            if (typeof x == 'string') {
                var num = parseFloat(x);
                if (!isNaN(num) && num == x) {
                    x = num;
                }
            }
            return function (a) {
                var b = x;
                if (typeof a == 'string' && typeof b == 'string') {
                    a = a.toLowerCase();
                    b = b.toLowerCase();
                }
                return cmp(a, b);
            };
        }
        function lc(a) {
            var num, str;
            if (typeof a == 'string') {
                a = a.toLowerCase();
            }
            if (/^[0-9.]+%$/.test(a)) {
                str = a.substr(0, a.length - 1);
                num = parseFloat(str);
                if (!isNaN(num) && num == str) {
                    a = num / 100;
                }
            } else if (/^[0-9.]+$/.test(a)) {
                num = parseFloat(a);
                if (!isNaN(num) && num == a) {
                    a = num;
                }
            }
            return a;
        }
        function compLT(a, b) {
            return lc(a) < lc(b);
        }
        function compLTE(a, b) {
            return lc(a) <= lc(b);
        }
        function compGT(a, b) {
            return lc(a) > lc(b);
        }
        function compGTE(a, b) {
            return lc(a) >= lc(b);
        }
        function compNE(a, b) {
            return !compEQ(a, b);
        }
        function compEQ(a, b) {
            if (b instanceof RegExp) {
                return b.test(a);
            }
            if (typeof a == 'string' || typeof b == 'string') {
                a = String(a);
                b = String(b);
            }
            return lc(a) == lc(b);
        }
        return function (cmp) {
            if (typeof cmp == 'function') {
                return cmp;
            }
            var m;
            if (m = /^=(.*)$/.exec(cmp)) {
                return makeComparator(compEQ, m[1]);
            }
            if (m = /^<>(.*)$/.exec(cmp)) {
                return makeComparator(compNE, m[1]);
            }
            if (m = /^<=(.*)$/.exec(cmp)) {
                return makeComparator(compLTE, m[1]);
            }
            if (m = /^<(.*)$/.exec(cmp)) {
                return makeComparator(compLT, m[1]);
            }
            if (m = /^>=(.*)$/.exec(cmp)) {
                return makeComparator(compGTE, m[1]);
            }
            if (m = /^>(.*)$/.exec(cmp)) {
                return makeComparator(compGT, m[1]);
            }
            if (/[?*]/.exec(cmp)) {
                var rx = RXCACHE[cmp];
                if (!rx) {
                    rx = cmp.replace(/(~\?|~\*|[\]({\+\.\|\^\$\\})\[]|[?*])/g, function (s) {
                        switch (s) {
                        case '~?':
                            return '\\?';
                        case '~*':
                            return '\\*';
                        case '?':
                            return '.';
                        case '*':
                            return '.*';
                        default:
                            return '\\' + s;
                        }
                    });
                    rx = RXCACHE[cmp] = new RegExp('^' + rx + '$', 'i');
                }
                return makeComparator(compEQ, rx);
            }
            return makeComparator(compEQ, cmp);
        };
    }();
    function numericPredicate(val) {
        return typeof val == 'number' || typeof val == 'boolean' || val == null || val === '';
    }
    function ascending(a, b) {
        return a === b ? 0 : a < b ? -1 : 1;
    }
    function descending(a, b) {
        return a === b ? 0 : a < b ? 1 : -1;
    }
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/runtime.functions.2', ['spreadsheet/runtime'], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var spreadsheet = kendo.spreadsheet;
    var calc = spreadsheet.calc;
    var runtime = calc.runtime;
    var defineFunction = runtime.defineFunction;
    var CalcError = runtime.CalcError;
    var packDate = runtime.packDate;
    var unpackDate = runtime.unpackDate;
    var isLeapYear = runtime.isLeapYear;
    var daysInMonth = runtime.daysInMonth;
    var _days_360 = runtime._days_360;
    defineFunction('ERF', function (ll, ul) {
        if (ul == null) {
            return ERF(ll);
        }
        return ERF(ul) - ERF(ll);
    }).args([
        [
            'lower_limit',
            'number'
        ],
        [
            'upper_limit',
            [
                'or',
                'number',
                'null'
            ]
        ]
    ]);
    defineFunction('ERFC', ERFC).args([[
            'x',
            'number'
        ]]);
    defineFunction('GAMMALN', GAMMALN).args([[
            'x',
            'number++'
        ]]);
    defineFunction('GAMMA', GAMMA).args([[
            'x',
            'number'
        ]]);
    defineFunction('GAMMA.DIST', GAMMA_DIST).args([
        [
            'x',
            'number+'
        ],
        [
            'alpha',
            'number++'
        ],
        [
            'beta',
            'number++'
        ],
        [
            'cumulative',
            'logical'
        ]
    ]);
    defineFunction('GAMMA.INV', GAMMA_INV).args([
        [
            'p',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'alpha',
            'number++'
        ],
        [
            'beta',
            'number++'
        ]
    ]);
    defineFunction('NORM.S.DIST', NORM_S_DIST).args([
        [
            'z',
            'number'
        ],
        [
            'cumulative',
            'logical'
        ]
    ]);
    defineFunction('NORM.S.INV', NORM_S_INV).args([[
            'p',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ]]);
    defineFunction('NORM.DIST', NORM_DIST).args([
        [
            'x',
            'number'
        ],
        [
            'mean',
            'number'
        ],
        [
            'stddev',
            'number++'
        ],
        [
            'cumulative',
            'logical'
        ]
    ]);
    defineFunction('NORM.INV', NORM_INV).args([
        [
            'p',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'mean',
            'number'
        ],
        [
            'stddev',
            'number++'
        ]
    ]);
    defineFunction('BETADIST', BETADIST).args([
        [
            'x',
            'number'
        ],
        [
            'alpha',
            'number++'
        ],
        [
            'beta',
            'number++'
        ],
        [
            'A',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'B',
            [
                'or',
                'number',
                [
                    'null',
                    1
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$x >= $A',
                'NUM'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$x <= $B',
                'NUM'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$A < $B',
                'NUM'
            ]
        ]
    ]);
    defineFunction('BETA.DIST', BETA_DIST).args([
        [
            'x',
            'number'
        ],
        [
            'alpha',
            'number++'
        ],
        [
            'beta',
            'number++'
        ],
        [
            'cumulative',
            'logical'
        ],
        [
            'A',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'B',
            [
                'or',
                'number',
                [
                    'null',
                    1
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$x >= $A',
                'NUM'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$x <= $B',
                'NUM'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$A < $B',
                'NUM'
            ]
        ]
    ]);
    defineFunction('BETA.INV', BETA_INV).args([
        [
            'p',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'alpha',
            'number++'
        ],
        [
            'beta',
            'number++'
        ],
        [
            'A',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'B',
            [
                'or',
                'number',
                [
                    'null',
                    1
                ]
            ]
        ]
    ]);
    defineFunction('CHISQ.DIST', chisq_left).args([
        [
            'x',
            'number+'
        ],
        [
            'deg_freedom',
            'integer++'
        ],
        [
            'cumulative',
            'logical'
        ]
    ]);
    defineFunction('CHISQ.DIST.RT', chisq_right).args([
        [
            'x',
            'number+'
        ],
        [
            'deg_freedom',
            'integer++'
        ]
    ]);
    defineFunction('CHISQ.INV', chisq_left_inv).args([
        [
            'p',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'deg_freedom',
            'integer++'
        ]
    ]);
    defineFunction('CHISQ.INV.RT', chisq_right_inv).args([
        [
            'p',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'deg_freedom',
            'integer++'
        ]
    ]);
    defineFunction('CHISQ.TEST', function (ac, ex) {
        return chisq_test(ac.data, ex.data);
    }).args([
        [
            'actual_range',
            'matrix'
        ],
        [
            'expected_range',
            'matrix'
        ],
        [
            '?',
            [
                'assert',
                '$actual_range.width == $expected_range.width'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$actual_range.height == $expected_range.height'
            ]
        ]
    ]);
    defineFunction('EXPON.DIST', expon).args([
        [
            'x',
            'number+'
        ],
        [
            'lambda',
            'number++'
        ],
        [
            'cumulative',
            'logical'
        ]
    ]);
    defineFunction('POISSON.DIST', poisson).args([
        [
            'x',
            'integer+'
        ],
        [
            'mean',
            'number+'
        ],
        [
            'cumulative',
            'logical'
        ]
    ]);
    defineFunction('F.DIST', Fdist).args([
        [
            'x',
            'number+'
        ],
        [
            'deg_freedom1',
            'integer++'
        ],
        [
            'deg_freedom2',
            'integer++'
        ],
        [
            'cumulative',
            'logical'
        ]
    ]);
    defineFunction('F.DIST.RT', Fdist_right).args([
        [
            'x',
            'number+'
        ],
        [
            'deg_freedom1',
            'integer++'
        ],
        [
            'deg_freedom2',
            'integer++'
        ]
    ]);
    defineFunction('F.INV', Finv).args([
        [
            'p',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'deg_freedom1',
            'integer++'
        ],
        [
            'deg_freedom2',
            'integer++'
        ]
    ]);
    defineFunction('F.INV.RT', Finv_right).args([
        [
            'p',
            [
                'and',
                'number',
                [
                    '[between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'deg_freedom1',
            'integer++'
        ],
        [
            'deg_freedom2',
            'integer++'
        ]
    ]);
    defineFunction('F.TEST', Ftest).args([
        [
            'array1',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'array2',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            '?',
            [
                'assert',
                '$array1.length >= 2',
                'DIV/0'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$array2.length >= 2',
                'DIV/0'
            ]
        ]
    ]);
    defineFunction('FISHER', fisher).args([[
            'x',
            [
                'and',
                'number',
                [
                    '(between)',
                    -1,
                    1
                ]
            ]
        ]]);
    defineFunction('FISHERINV', fisherinv).args([[
            'y',
            'number'
        ]]);
    defineFunction('T.DIST', Tdist).args([
        [
            'x',
            'number'
        ],
        [
            'deg_freedom',
            'integer++'
        ],
        [
            'cumulative',
            'logical'
        ]
    ]);
    defineFunction('T.DIST.RT', Tdist_right).args([
        [
            'x',
            'number'
        ],
        [
            'deg_freedom',
            'integer++'
        ]
    ]);
    defineFunction('T.DIST.2T', Tdist_2tail).args([
        [
            'x',
            'number+'
        ],
        [
            'deg_freedom',
            'integer++'
        ]
    ]);
    defineFunction('T.INV', Tdist_inv).args([
        [
            'p',
            [
                'and',
                'number',
                [
                    '(between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'deg_freedom',
            'integer++'
        ]
    ]);
    defineFunction('T.INV.2T', Tdist_2tail_inv).args([
        [
            'p',
            [
                'and',
                'number',
                [
                    '(between]',
                    0,
                    1
                ]
            ]
        ],
        [
            'deg_freedom',
            'integer++'
        ]
    ]);
    defineFunction('T.TEST', Tdist_test).args([
        [
            'array1',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'array2',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'tails',
            [
                'and',
                'integer',
                [
                    'values',
                    1,
                    2
                ]
            ]
        ],
        [
            'type',
            [
                'and',
                'integer',
                [
                    'values',
                    1,
                    2,
                    3
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$type != 1 || $array1.length == $array2.length',
                'N/A'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$array1.length >= 2',
                'DIV/0'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$array2.length >= 2',
                'DIV/0'
            ]
        ]
    ]);
    defineFunction('CONFIDENCE.T', confidence_t).args([
        [
            'alpha',
            [
                'and',
                'number',
                [
                    '(between)',
                    0,
                    1
                ]
            ]
        ],
        [
            'standard_dev',
            'number++'
        ],
        [
            'size',
            [
                'and',
                'integer++',
                [
                    'assert',
                    '$size != 1',
                    'DIV/0'
                ]
            ]
        ]
    ]);
    defineFunction('CONFIDENCE.NORM', confidence_norm).args([
        [
            'alpha',
            [
                'and',
                'number',
                [
                    '(between)',
                    0,
                    1
                ]
            ]
        ],
        [
            'standard_dev',
            'number++'
        ],
        [
            'size',
            [
                'and',
                'integer++'
            ]
        ]
    ]);
    defineFunction('GAUSS', gauss).args([[
            'z',
            'number'
        ]]);
    defineFunction('PHI', phi).args([[
            'x',
            'number'
        ]]);
    defineFunction('LOGNORM.DIST', lognorm_dist).args([
        [
            'x',
            'number++'
        ],
        [
            'mean',
            'number'
        ],
        [
            'standard_dev',
            'number++'
        ],
        [
            'cumulative',
            'logical'
        ]
    ]);
    defineFunction('LOGNORM.INV', lognorm_inv).args([
        [
            'probability',
            [
                'and',
                'number',
                [
                    '(between)',
                    0,
                    1
                ]
            ]
        ],
        [
            'mean',
            'number'
        ],
        [
            'standard_dev',
            'number++'
        ]
    ]);
    defineFunction('PROB', prob).args([
        [
            'x_range',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'prob_range',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'lower_limit',
            'number'
        ],
        [
            'upper_limit',
            [
                'or',
                'number',
                [
                    'null',
                    '$lower_limit'
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$prob_range.length == $x_range.length',
                'N/A'
            ]
        ]
    ]);
    defineFunction('SLOPE', slope).args([
        [
            'known_y',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'known_x',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            '?',
            [
                'assert',
                '$known_x.length == $known_y.length',
                'N/A'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$known_x.length > 0 && $known_y.length > 0',
                'N/A'
            ]
        ]
    ]);
    defineFunction('INTERCEPT', intercept).args([
        [
            'known_y',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'known_x',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            '?',
            [
                'assert',
                '$known_x.length == $known_y.length',
                'N/A'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$known_x.length > 0 && $known_y.length > 0',
                'N/A'
            ]
        ]
    ]);
    defineFunction('PEARSON', pearson).args([
        [
            'array1',
            [
                'collect!',
                'anything',
                1
            ]
        ],
        [
            'array2',
            [
                'collect!',
                'anything',
                1
            ]
        ],
        [
            '?',
            [
                'assert',
                '$array2.length == $array1.length',
                'N/A'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$array2.length > 0 && $array1.length > 0',
                'N/A'
            ]
        ]
    ]);
    defineFunction('RSQ', rsq).args([
        [
            'known_y',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'known_x',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            '?',
            [
                'assert',
                '$known_x.length == $known_y.length',
                'N/A'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$known_x.length > 0 && $known_y.length > 0',
                'N/A'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$known_x.length != 1 && $known_y.length != 1',
                'N/A'
            ]
        ]
    ]);
    defineFunction('STEYX', steyx).args([
        [
            'known_y',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'known_x',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            '?',
            [
                'assert',
                '$known_x.length == $known_y.length',
                'N/A'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$known_x.length >= 3 && $known_y.length >= 3',
                'DIV/0'
            ]
        ]
    ]);
    defineFunction('FORECAST', forecast).args([
        [
            'x',
            'number'
        ],
        [
            'known_y',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'known_x',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            '?',
            [
                'assert',
                '$known_x.length == $known_y.length',
                'N/A'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$known_x.length > 0 && $known_y.length > 0',
                'N/A'
            ]
        ]
    ]);
    defineFunction('LINEST', linest).args([
        [
            'known_y',
            'matrix'
        ],
        [
            'known_x',
            [
                'or',
                'matrix',
                'null'
            ]
        ],
        [
            'const',
            [
                'or',
                'logical',
                [
                    'null',
                    true
                ]
            ]
        ],
        [
            'stats',
            [
                'or',
                'logical',
                [
                    'null',
                    false
                ]
            ]
        ]
    ]);
    defineFunction('LOGEST', logest).args([
        [
            'known_y',
            'matrix'
        ],
        [
            'known_x',
            [
                'or',
                'matrix',
                'null'
            ]
        ],
        [
            'const',
            [
                'or',
                'logical',
                [
                    'null',
                    true
                ]
            ]
        ],
        [
            'stats',
            [
                'or',
                'logical',
                [
                    'null',
                    false
                ]
            ]
        ]
    ]);
    defineFunction('TREND', trend).args([
        [
            'known_y',
            'matrix'
        ],
        [
            'known_x',
            [
                'or',
                'matrix',
                'null'
            ]
        ],
        [
            'new_x',
            [
                'or',
                'matrix',
                'null'
            ]
        ],
        [
            'const',
            [
                'or',
                'logical',
                [
                    'null',
                    true
                ]
            ]
        ]
    ]);
    defineFunction('GROWTH', growth).args([
        [
            'known_y',
            'matrix'
        ],
        [
            'known_x',
            [
                'or',
                'matrix',
                'null'
            ]
        ],
        [
            'new_x',
            [
                'or',
                'matrix',
                'null'
            ]
        ],
        [
            'const',
            [
                'or',
                'logical',
                [
                    'null',
                    true
                ]
            ]
        ]
    ]);
    defineFunction('FV', FV).args([
        [
            'rate',
            'number'
        ],
        [
            'nper',
            'number'
        ],
        [
            'pmt',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'pv',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'type',
            [
                'or',
                [
                    'values',
                    0,
                    1
                ],
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$pmt || $pv'
            ]
        ]
    ]);
    defineFunction('PV', PV).args([
        [
            'rate',
            'number'
        ],
        [
            'nper',
            'number'
        ],
        [
            'pmt',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'fv',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'type',
            [
                'or',
                [
                    'values',
                    0,
                    1
                ],
                [
                    'null',
                    0
                ]
            ]
        ]
    ]);
    defineFunction('PMT', PMT).args([
        [
            'rate',
            'number'
        ],
        [
            'nper',
            'number'
        ],
        [
            'pmt',
            'number'
        ],
        [
            'fv',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'type',
            [
                'or',
                [
                    'values',
                    0,
                    1
                ],
                [
                    'null',
                    0
                ]
            ]
        ]
    ]);
    defineFunction('NPER', NPER).args([
        [
            'rate',
            'number'
        ],
        [
            'pmt',
            'number'
        ],
        [
            'pv',
            'number'
        ],
        [
            'fv',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'type',
            [
                'or',
                [
                    'values',
                    0,
                    1
                ],
                [
                    'null',
                    0
                ]
            ]
        ]
    ]);
    defineFunction('RATE', RATE).args([
        [
            'nper',
            'number'
        ],
        [
            'pmt',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'pv',
            'number'
        ],
        [
            'fv',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'type',
            [
                'or',
                [
                    'values',
                    0,
                    1
                ],
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'guess',
            [
                'or',
                'number++',
                [
                    'null',
                    0.01
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$pmt || $fv'
            ]
        ]
    ]);
    defineFunction('IPMT', IPMT).args([
        [
            'rate',
            'number'
        ],
        [
            'per',
            'number++'
        ],
        [
            'nper',
            'number++'
        ],
        [
            'pv',
            'number'
        ],
        [
            'fv',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'type',
            [
                'or',
                [
                    'values',
                    0,
                    1
                ],
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$per >= 1 && $per <= $nper'
            ]
        ]
    ]);
    defineFunction('PPMT', PPMT).args([
        [
            'rate',
            'number'
        ],
        [
            'per',
            'number++'
        ],
        [
            'nper',
            'number++'
        ],
        [
            'pv',
            'number'
        ],
        [
            'fv',
            [
                'or',
                'number',
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            'type',
            [
                'or',
                [
                    'values',
                    0,
                    1
                ],
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$per >= 1 && $per <= $nper'
            ]
        ]
    ]);
    defineFunction('CUMPRINC', CUMPRINC).args([
        [
            'rate',
            'number++'
        ],
        [
            'nper',
            'number++'
        ],
        [
            'pv',
            'number++'
        ],
        [
            'start_period',
            'number++'
        ],
        [
            'end_period',
            'number++'
        ],
        [
            'type',
            [
                'or',
                [
                    'values',
                    0,
                    1
                ],
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$end_period >= $start_period',
                'NUM'
            ]
        ]
    ]);
    defineFunction('CUMIPMT', CUMIPMT).args([
        [
            'rate',
            'number++'
        ],
        [
            'nper',
            'number++'
        ],
        [
            'pv',
            'number++'
        ],
        [
            'start_period',
            'number++'
        ],
        [
            'end_period',
            'number++'
        ],
        [
            'type',
            [
                'or',
                [
                    'values',
                    0,
                    1
                ],
                [
                    'null',
                    0
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$end_period >= $start_period',
                'NUM'
            ]
        ]
    ]);
    defineFunction('NPV', NPV).args([
        [
            'rate',
            'number'
        ],
        [
            'values',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$values.length > 0',
                'N/A'
            ]
        ]
    ]);
    defineFunction('IRR', IRR).args([
        [
            'values',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'guess',
            [
                'or',
                'number',
                [
                    'null',
                    0.1
                ]
            ]
        ]
    ]);
    defineFunction('EFFECT', EFFECT).args([
        [
            'nominal_rate',
            'number++'
        ],
        [
            'npery',
            'integer++'
        ]
    ]);
    defineFunction('NOMINAL', NOMINAL).args([
        [
            'effect_rate',
            'number++'
        ],
        [
            'npery',
            'integer++'
        ]
    ]);
    defineFunction('XNPV', XNPV).args([
        [
            'rate',
            'number'
        ],
        [
            'values',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'dates',
            [
                'collect',
                'date',
                1
            ]
        ],
        [
            '?',
            [
                'assert',
                '$values.length == $dates.length',
                'NUM'
            ]
        ]
    ]);
    defineFunction('XIRR', XIRR).args([
        [
            'values',
            [
                'collect',
                'number',
                1
            ]
        ],
        [
            'dates',
            [
                'collect',
                'date',
                1
            ]
        ],
        [
            'guess',
            [
                'or',
                'number',
                [
                    'null',
                    0.1
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$values.length == $dates.length',
                'NUM'
            ]
        ]
    ]);
    defineFunction('ISPMT', ISPMT).args([
        [
            'rate',
            'number'
        ],
        [
            'per',
            'number++'
        ],
        [
            'nper',
            'number++'
        ],
        [
            'pv',
            'number'
        ],
        [
            '?',
            [
                'assert',
                '$per >= 1 && $per <= $nper'
            ]
        ]
    ]);
    defineFunction('DB', DB).args([
        [
            'cost',
            'number'
        ],
        [
            'salvage',
            'number'
        ],
        [
            'life',
            'number++'
        ],
        [
            'period',
            'number++'
        ],
        [
            'month',
            [
                'or',
                'number',
                [
                    'null',
                    12
                ]
            ]
        ]
    ]);
    defineFunction('DDB', DDB).args([
        [
            'cost',
            'number'
        ],
        [
            'salvage',
            'number'
        ],
        [
            'life',
            'number++'
        ],
        [
            'period',
            'number++'
        ],
        [
            'factor',
            [
                'or',
                'number',
                [
                    'null',
                    2
                ]
            ]
        ]
    ]);
    defineFunction('SLN', SLN).args([
        [
            'cost',
            'number'
        ],
        [
            'salvage',
            'number'
        ],
        [
            'life',
            'number++'
        ]
    ]);
    defineFunction('SYD', SYD).args([
        [
            'cost',
            'number'
        ],
        [
            'salvage',
            'number'
        ],
        [
            'life',
            'number++'
        ],
        [
            'per',
            'number++'
        ]
    ]);
    defineFunction('VDB', VDB).args([
        [
            'cost',
            'number+'
        ],
        [
            'salvage',
            'number+'
        ],
        [
            'life',
            'number++'
        ],
        [
            'start_period',
            'number+'
        ],
        [
            'end_period',
            'number+'
        ],
        [
            'factor',
            [
                'or',
                'number+',
                [
                    'null',
                    2
                ]
            ]
        ],
        [
            'no_switch',
            [
                'or',
                'logical',
                [
                    'null',
                    false
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$end_period >= $start_period',
                'NUM'
            ]
        ]
    ]);
    var COUPS_ARGS = [
        [
            'settlement',
            'date'
        ],
        [
            'maturity',
            'date'
        ],
        [
            'frequency',
            [
                'and',
                'integer',
                [
                    'values',
                    1,
                    2,
                    4
                ]
            ]
        ],
        [
            'basis',
            [
                'or',
                [
                    'null',
                    0
                ],
                [
                    'and',
                    'integer',
                    [
                        'values',
                        0,
                        1,
                        2,
                        3,
                        4
                    ]
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$settlement < $maturity',
                'NUM'
            ]
        ]
    ];
    defineFunction('COUPDAYBS', COUPDAYBS).args(COUPS_ARGS);
    defineFunction('COUPDAYS', COUPDAYS).args(COUPS_ARGS);
    defineFunction('COUPDAYSNC', COUPDAYSNC).args(COUPS_ARGS);
    defineFunction('COUPPCD', COUPPCD).args(COUPS_ARGS);
    defineFunction('COUPNCD', COUPNCD).args(COUPS_ARGS);
    defineFunction('COUPNUM', COUPNUM).args(COUPS_ARGS);
    defineFunction('ACCRINTM', ACCRINTM).args([
        [
            'issue',
            'date'
        ],
        [
            'settlement',
            'date'
        ],
        [
            'rate',
            'number++'
        ],
        [
            'par',
            [
                'or',
                [
                    'null',
                    1000
                ],
                'number++'
            ]
        ],
        [
            'basis',
            [
                'or',
                [
                    'null',
                    0
                ],
                [
                    'and',
                    'integer',
                    [
                        'values',
                        0,
                        1,
                        2,
                        3,
                        4
                    ]
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$issue < $settlement',
                'NUM'
            ]
        ]
    ]);
    defineFunction('ACCRINT', ACCRINT).args([
        [
            'issue',
            'date'
        ],
        [
            'first_interest',
            'date'
        ],
        [
            'settlement',
            'date'
        ],
        [
            'rate',
            'number++'
        ],
        [
            'par',
            [
                'or',
                [
                    'null',
                    1000
                ],
                'number++'
            ]
        ],
        [
            'frequency',
            [
                'and',
                'integer',
                [
                    'values',
                    1,
                    2,
                    4
                ]
            ]
        ],
        [
            'basis',
            [
                'or',
                [
                    'null',
                    0
                ],
                [
                    'and',
                    'integer',
                    [
                        'values',
                        0,
                        1,
                        2,
                        3,
                        4
                    ]
                ]
            ]
        ],
        [
            'calc_method',
            [
                'or',
                'logical',
                [
                    'null',
                    true
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$issue < $settlement',
                'NUM'
            ]
        ]
    ]);
    defineFunction('DISC', DISC).args([
        [
            'settlement',
            'date'
        ],
        [
            'maturity',
            'date'
        ],
        [
            'pr',
            'number++'
        ],
        [
            'redemption',
            'number++'
        ],
        [
            'basis',
            [
                'or',
                [
                    'null',
                    0
                ],
                [
                    'and',
                    'integer',
                    [
                        'values',
                        0,
                        1,
                        2,
                        3,
                        4
                    ]
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$settlement < $maturity',
                'NUM'
            ]
        ]
    ]);
    defineFunction('INTRATE', INTRATE).args([
        [
            'settlement',
            'date'
        ],
        [
            'maturity',
            'date'
        ],
        [
            'investment',
            'number++'
        ],
        [
            'redemption',
            'number++'
        ],
        [
            'basis',
            [
                'or',
                [
                    'null',
                    0
                ],
                [
                    'and',
                    'integer',
                    [
                        'values',
                        0,
                        1,
                        2,
                        3,
                        4
                    ]
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$settlement < $maturity',
                'NUM'
            ]
        ]
    ]);
    defineFunction('RECEIVED', RECEIVED).args([
        [
            'settlement',
            'date'
        ],
        [
            'maturity',
            'date'
        ],
        [
            'investment',
            'number++'
        ],
        [
            'discount',
            'number++'
        ],
        [
            'basis',
            [
                'or',
                [
                    'null',
                    0
                ],
                [
                    'and',
                    'integer',
                    [
                        'values',
                        0,
                        1,
                        2,
                        3,
                        4
                    ]
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$settlement < $maturity',
                'NUM'
            ]
        ]
    ]);
    defineFunction('PRICE', PRICE).args([
        [
            'settlement',
            'date'
        ],
        [
            'maturity',
            'date'
        ],
        [
            'rate',
            'number++'
        ],
        [
            'yld',
            'number++'
        ],
        [
            'redemption',
            'number++'
        ],
        [
            'frequency',
            [
                'and',
                'integer',
                [
                    'values',
                    1,
                    2,
                    4
                ]
            ]
        ],
        [
            'basis',
            [
                'or',
                [
                    'null',
                    0
                ],
                [
                    'and',
                    'integer',
                    [
                        'values',
                        0,
                        1,
                        2,
                        3,
                        4
                    ]
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$settlement < $maturity',
                'NUM'
            ]
        ]
    ]);
    defineFunction('PRICEDISC', PRICEDISC).args([
        [
            'settlement',
            'date'
        ],
        [
            'maturity',
            'date'
        ],
        [
            'discount',
            'number++'
        ],
        [
            'redemption',
            'number++'
        ],
        [
            'basis',
            [
                'or',
                [
                    'null',
                    0
                ],
                [
                    'and',
                    'integer',
                    [
                        'values',
                        0,
                        1,
                        2,
                        3,
                        4
                    ]
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$settlement < $maturity',
                'NUM'
            ]
        ]
    ]);
    var MAX_IT = 300, EPS = 2.2204e-16, FP_MIN = 1e-30, f_abs = Math.abs;
    function ERF(x) {
        if (f_abs(x) >= 3.3) {
            return 1 - ERFC(x);
        }
        var S = x > 0 ? 1 : -1;
        if (S == -1) {
            x = -x;
        }
        var m = 0, an = 1;
        for (var n = 1; n < 100; n++) {
            m += an;
            an *= 2 * x * x / (2 * n + 1);
        }
        return S * 2 / Math.sqrt(Math.PI) * x * Math.exp(-x * x) * m;
    }
    function ERFC(x) {
        if (f_abs(x) < 3.3) {
            return 1 - ERF(x);
        }
        var s = 1;
        if (x < 0) {
            s = -1;
            x = -x;
        }
        var frac = x;
        for (var n = 8; n >= 1; n -= 0.5) {
            frac = x + n / frac;
        }
        frac = 1 / (x + frac);
        return s == 1 ? Math.exp(-x * x) / Math.sqrt(Math.PI) * frac : 2 - Math.exp(-x * x) / Math.sqrt(Math.PI) * frac;
    }
    function GAMMALN(x) {
        var cof = [
            1.000000000190015,
            76.18009172947146,
            -86.50532032941678,
            24.01409824083091,
            -1.231739572450155,
            0.001208650973866179,
            -0.000005395239384953
        ];
        var y = x, tmp = x + 5.5, ser = cof[0];
        tmp -= (x + 0.5) * Math.log(tmp);
        for (var j = 1; j <= 6; j++) {
            y += 1;
            ser += cof[j] / y;
        }
        return -tmp + Math.log(Math.sqrt(2 * Math.PI) * ser / x);
    }
    function GAMMA(x) {
        if (x > 0) {
            return Math.exp(GAMMALN(x));
        }
        var pi = Math.PI, y = -x;
        return -pi / (y * GAMMA(y) * Math.sin(pi * y));
    }
    function BETALN(a, b) {
        return GAMMALN(a) + GAMMALN(b) - GAMMALN(a + b);
    }
    function BETA(a, b) {
        return Math.exp(BETALN(a, b));
    }
    function gamma_inc(a, x) {
        return x < a + 1 ? g_series(a, x) : 1 - g_contfrac(a, x);
    }
    function g_series(a, x) {
        var sum = 1 / a, frac = sum, ap = a;
        var gln = GAMMALN(a), n;
        for (n = 1; n <= MAX_IT; n++) {
            ap++;
            frac *= x / ap;
            sum += frac;
            if (f_abs(frac) < f_abs(sum) * EPS) {
                break;
            }
        }
        return sum * Math.exp(-x + a * Math.log(x) - gln);
    }
    function g_contfrac(a, x) {
        var f = FP_MIN, c = f, d = 0, aj = 1, bj = x + 1 - a;
        var gln = GAMMALN(a);
        for (var i = 1; i <= MAX_IT; i++) {
            d = bj + aj * d;
            if (f_abs(d) < FP_MIN) {
                d = FP_MIN;
            }
            c = bj + aj / c;
            if (f_abs(c) < FP_MIN) {
                c = FP_MIN;
            }
            d = 1 / d;
            var delta = c * d;
            f *= delta;
            if (f_abs(delta - 1) < EPS) {
                break;
            }
            bj += 2;
            aj = -i * (i - a);
        }
        return f * Math.exp(-x - gln + a * Math.log(x));
    }
    function GAMMA_DIST(x, a, b, cumulative) {
        if (!cumulative) {
            return Math.pow(x / b, a - 1) * Math.exp(-x / b) / (b * GAMMA(a));
        }
        return gamma_inc(a, x / b);
    }
    function GAMMA_INV(p, a, b) {
        if (p === 0) {
            return 0;
        }
        if (p == 1) {
            return Infinity;
        }
        var m = 0, M = 10, x = 0, ab = a * b;
        if (ab > 1) {
            M *= ab;
        }
        for (var i = 0; i < MAX_IT; i++) {
            x = 0.5 * (m + M);
            var q = GAMMA_DIST(x, a, b, true);
            if (f_abs(p - q) < 1e-16) {
                break;
            }
            if (q > p) {
                M = x;
            } else {
                m = x;
            }
        }
        return x;
    }
    function NORM_S_DIST(x, cumulative) {
        if (!cumulative) {
            return Math.exp(-x * x / 2) / Math.sqrt(2 * Math.PI);
        }
        return 0.5 + 0.5 * ERF(x / Math.sqrt(2));
    }
    function NORM_S_INV(p) {
        var a = [
                -39.69683028665376,
                220.9460984245205,
                -275.9285104469687,
                138.357751867269,
                -30.66479806614716,
                2.506628277459239
            ], b = [
                -54.47609879822406,
                161.5858368580409,
                -155.6989798598866,
                66.80131188771972,
                -13.28068155288572
            ], c = [
                -0.007784894002430293,
                -0.3223964580411365,
                -2.400758277161838,
                -2.549732539343734,
                4.374664141464968,
                2.938163982698783
            ], d = [
                0.007784695709041462,
                0.3224671290700398,
                2.445134137142996,
                3.754408661907416
            ];
        var plow = 0.02425, phigh = 1 - plow;
        var q, r;
        if (p < plow) {
            q = Math.sqrt(-2 * Math.log(p));
            return (((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1);
        }
        if (phigh < p) {
            q = Math.sqrt(-2 * Math.log(1 - p));
            return -(((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1);
        }
        q = p - 0.5;
        r = q * q;
        return (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * q / (((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1);
    }
    function NORM_DIST(x, m, s, cumulative) {
        if (!cumulative) {
            return Math.exp(-(x - m) * (x - m) / (2 * s * s)) / (s * Math.sqrt(2 * Math.PI));
        }
        return NORM_S_DIST((x - m) / s, true);
    }
    function NORM_INV(p, m, s) {
        return m + s * NORM_S_INV(p);
    }
    function betastd_pdf(x, a, b) {
        return Math.exp((a - 1) * Math.log(x) + (b - 1) * Math.log(1 - x) - BETALN(a, b));
    }
    function betastd_cdf(x, a, b) {
        var k = Math.exp(a * Math.log(x) + b * Math.log(1 - x) - BETALN(a, b));
        return x < (a + 1) / (a + b + 2) ? k * beta_lentz(a, b, x) / a : 1 - k * beta_lentz(b, a, 1 - x) / b;
    }
    function beta_lentz(a, b, x) {
        var m, m2;
        var aa, c, d, del, h, qab, qam, qap;
        qab = a + b;
        qap = a + 1;
        qam = a - 1;
        c = 1;
        d = 1 - qab * x / qap;
        if (f_abs(d) < FP_MIN) {
            d = FP_MIN;
        }
        d = 1 / d;
        h = d;
        for (m = 1; m <= MAX_IT; m++) {
            m2 = 2 * m;
            aa = m * (b - m) * x / ((qam + m2) * (a + m2));
            d = 1 + aa * d;
            if (f_abs(d) < FP_MIN) {
                d = FP_MIN;
            }
            c = 1 + aa / c;
            if (f_abs(c) < FP_MIN) {
                c = FP_MIN;
            }
            d = 1 / d;
            h *= d * c;
            aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
            d = 1 + aa * d;
            if (f_abs(d) < FP_MIN) {
                d = FP_MIN;
            }
            c = 1 + aa / c;
            if (f_abs(c) < FP_MIN) {
                c = FP_MIN;
            }
            d = 1 / d;
            del = d * c;
            h *= del;
            if (f_abs(del - 1) < EPS) {
                break;
            }
        }
        return h;
    }
    function betastd_inv(p, a, b) {
        var m = 0, M = 1, x = 0;
        for (var i = 0; i < MAX_IT; i++) {
            x = 0.5 * (m + M);
            var q = betastd_cdf(x, a, b);
            if (f_abs(p - q) < EPS) {
                break;
            }
            if (q > p) {
                M = x;
            } else {
                m = x;
            }
        }
        return x;
    }
    function BETADIST(x, a, b, m, M) {
        return betastd_cdf((x - m) / (M - m), a, b);
    }
    function BETA_DIST(x, a, b, cdf, m, M) {
        if (cdf) {
            return betastd_cdf((x - m) / (M - m), a, b);
        }
        return betastd_pdf((x - m) / (M - m), a, b) / (M - m);
    }
    function BETA_INV(p, a, b, m, M) {
        return m + (M - m) * betastd_inv(p, a, b);
    }
    function chisq_left(x, n, cds) {
        return GAMMA_DIST(x, n / 2, 2, cds);
    }
    function chisq_right(x, n) {
        return 1 - chisq_left(x, n, true);
    }
    function chisq_left_inv(p, n) {
        return GAMMA_INV(p, n / 2, 2);
    }
    function chisq_right_inv(p, n) {
        return chisq_left_inv(1 - p, n);
    }
    function chisq_test(obsv, expect) {
        var rows = obsv.length, cols = obsv[0].length;
        var x = 0, i, j;
        for (i = 0; i < rows; i++) {
            for (j = 0; j < cols; j++) {
                var eij = expect[i][j];
                var delta = obsv[i][j] - eij;
                delta *= delta;
                x += delta / eij;
            }
        }
        var n = (rows - 1) * (cols - 1);
        return chisq_right(x, n);
    }
    function expon(x, r, cdf) {
        if (cdf) {
            return 1 - Math.exp(-r * x);
        }
        return r * Math.exp(-r * x);
    }
    function poisson(k, m, cdf) {
        if (cdf) {
            return 1 - chisq_left(2 * m, 2 * (k + 1), true);
        }
        var lnf = 0;
        for (var i = 2; i <= k; i++) {
            lnf += Math.log(i);
        }
        return Math.exp(k * Math.log(m) - m - lnf);
    }
    function Fdist(x, n, d, cdf) {
        if (cdf) {
            return betastd_cdf(n * x / (d + n * x), n / 2, d / 2);
        }
        var u = n / d;
        n /= 2;
        d /= 2;
        return u / BETA(n, d) * Math.pow(u * x, n - 1) / Math.pow(1 + u * x, n + d);
    }
    function Fdist_right(x, n, d) {
        return 1 - Fdist(x, n, d, true);
    }
    function Finv_right(p, n, d) {
        return d / n * (1 / BETA_INV(p, d / 2, n / 2, 0, 1) - 1);
    }
    function Finv(p, n, d) {
        return d / n * (1 / BETA_INV(1 - p, d / 2, n / 2, 0, 1) - 1);
    }
    function _mean(arr) {
        var me = 0, n = arr.length;
        for (var i = 0; i < n; i++) {
            me += arr[i];
        }
        return me / n;
    }
    function _var_sq(arr, m) {
        var v = 0, n = arr.length;
        for (var i = 0; i < n; i++) {
            var delta = arr[i] - m;
            v += delta * delta;
        }
        return v / (n - 1);
    }
    function Ftest(arr1, arr2) {
        var n1 = arr1.length - 1, n2 = arr2.length - 1;
        var va1 = _var_sq(arr1, _mean(arr1)), va2 = _var_sq(arr2, _mean(arr2));
        if (!va1 || !va2) {
            throw new CalcError('DIV/0');
        }
        return 2 * Fdist(va1 / va2, n1, n2, true);
    }
    function fisher(x) {
        return 0.5 * Math.log((1 + x) / (1 - x));
    }
    function fisherinv(x) {
        var e2 = Math.exp(2 * x);
        return (e2 - 1) / (e2 + 1);
    }
    function Tdist(x, n, cdf) {
        if (cdf) {
            return 1 - 0.5 * betastd_cdf(n / (x * x + n), n / 2, 0.5);
        }
        return 1 / (Math.sqrt(n) * BETA(0.5, n / 2)) * Math.pow(1 + x * x / n, -(n + 1) / 2);
    }
    function Tdist_right(x, n) {
        return 1 - Tdist(x, n, true);
    }
    function Tdist_2tail(x, n) {
        if (x < 0) {
            x = -x;
        }
        return 2 * Tdist_right(x, n);
    }
    function Tdist_inv(p, n) {
        var x = betastd_inv(2 * Math.min(p, 1 - p), n / 2, 0.5);
        x = Math.sqrt(n * (1 - x) / x);
        return p > 0.5 ? x : -x;
    }
    function Tdist_2tail_inv(p, n) {
        return Tdist_inv(1 - p / 2, n);
    }
    function Tdist_test(gr1, gr2, tail, type) {
        var n1 = gr1.length, n2 = gr2.length;
        var t_st, df;
        if (type == 1) {
            var d = 0, d2 = 0;
            for (var i = 0; i < n1; i++) {
                var delta = gr1[i] - gr2[i];
                d += delta;
                d2 += delta * delta;
            }
            var md = d / n1;
            t_st = md / Math.sqrt((d2 - d * md) / (n1 * (n1 - 1)));
            return tail == 1 ? Tdist_right(t_st, n1 - 1) : Tdist_2tail(t_st, n1 - 1);
        }
        var m1 = _mean(gr1), m2 = _mean(gr2), v1 = _var_sq(gr1, m1), v2 = _var_sq(gr2, m2);
        if (type == 3) {
            var u1 = v1 / n1, u2 = v2 / n2, u = u1 + u2;
            var q1 = u1 / u, q2 = u2 / u;
            df = 1 / (q1 * q1 / (n1 - 1) + q2 * q2 / (n2 - 1));
            t_st = f_abs(m1 - m2) / Math.sqrt(u);
            return tail == 1 ? Tdist_right(t_st, df) : Tdist_2tail(t_st, df);
        } else {
            df = n1 + n2 - 2;
            t_st = f_abs(m1 - m2) * Math.sqrt(df * n1 * n2 / ((n1 + n2) * ((n1 - 1) * v1 + (n2 - 1) * v2)));
            return tail == 1 ? Tdist_right(t_st, df) : Tdist_2tail(t_st, df);
        }
    }
    function confidence_t(alpha, stddev, size) {
        return -Tdist_inv(alpha / 2, size - 1) * stddev / Math.sqrt(size);
    }
    function confidence_norm(alpha, stddev, size) {
        return -NORM_S_INV(alpha / 2) * stddev / Math.sqrt(size);
    }
    function gauss(z) {
        return NORM_S_DIST(z, true) - 0.5;
    }
    function phi(x) {
        return NORM_S_DIST(x);
    }
    function lognorm_dist(x, m, s, cumulative) {
        if (cumulative) {
            return 0.5 + 0.5 * ERF((Math.log(x) - m) / (s * Math.sqrt(2)));
        }
        var t = Math.log(x) - m;
        return Math.exp(-t * t / (2 * s * s)) / (x * s * Math.sqrt(2 * Math.PI));
    }
    function lognorm_inv(p, m, s) {
        return Math.exp(NORM_INV(p, m, s));
    }
    function prob(x_, p_, lw, up) {
        var n = x_.length;
        var s = 0, i;
        for (i = 0; i < n; i++) {
            if (p_[i] <= 0 || p_[i] > 1) {
                throw new CalcError('NUM');
            }
            s += p_[i];
        }
        if (s != 1) {
            throw new CalcError('NUM');
        }
        var res = 0;
        for (i = 0; i < n; i++) {
            var x = x_[i];
            if (x >= lw && x <= up) {
                res += p_[i];
            }
        }
        return res;
    }
    function slope(y_, x_) {
        var mx = _mean(x_), my = _mean(y_), b1 = 0, b2 = 0;
        for (var i = 0, n = y_.length; i < n; i++) {
            var t = x_[i] - mx;
            b1 += t * (y_[i] - my);
            b2 += t * t;
        }
        return b1 / b2;
    }
    function intercept(y_, x_) {
        var mx = _mean(x_), my = _mean(y_);
        var b1 = 0, b2 = 0;
        for (var i = 0, n = y_.length; i < n; i++) {
            var t = x_[i] - mx;
            b1 += t * (y_[i] - my);
            b2 += t * t;
        }
        return my - b1 * mx / b2;
    }
    function pearson(x_, y_) {
        whipNumberArrays(x_, y_);
        var mx = _mean(x_), my = _mean(y_);
        var s1 = 0, s2 = 0, s3 = 0;
        for (var i = 0, n = x_.length; i < n; i++) {
            var t1 = x_[i] - mx, t2 = y_[i] - my;
            s1 += t1 * t2;
            s2 += t1 * t1;
            s3 += t2 * t2;
        }
        return s1 / Math.sqrt(s2 * s3);
    }
    function rsq(x_, y_) {
        var r = pearson(x_, y_);
        return r * r;
    }
    function steyx(y_, x_) {
        var n = x_.length;
        var mx = _mean(x_), my = _mean(y_);
        var s1 = 0, s2 = 0, s3 = 0;
        for (var i = 0; i < n; i++) {
            var t1 = x_[i] - mx, t2 = y_[i] - my;
            s1 += t2 * t2;
            s2 += t1 * t2;
            s3 += t1 * t1;
        }
        return Math.sqrt((s1 - s2 * s2 / s3) / (n - 2));
    }
    function forecast(x, y_, x_) {
        var mx = _mean(x_), my = _mean(y_);
        var s1 = 0, s2 = 0;
        for (var i = 0, n = x_.length; i < n; i++) {
            var t1 = x_[i] - mx, t2 = y_[i] - my;
            s1 += t1 * t2;
            s2 += t1 * t1;
        }
        if (s2 === 0) {
            throw new CalcError('N/A');
        }
        var b = s1 / s2, a = my - b * mx;
        return a + b * x;
    }
    function _mat_mean(Mat) {
        var n = Mat.height, sum = 0;
        for (var i = 0; i < n; i++) {
            sum += Mat.data[i][0];
        }
        return sum / n;
    }
    function _mat_devsq(Mat, mean) {
        var n = Mat.height, sq = 0;
        for (var i = 0; i < n; i++) {
            var x = Mat.data[i][0] - mean;
            sq += x * x;
        }
        return sq;
    }
    function linest(Y, X, konst, stats) {
        var i = 0;
        if (!X) {
            X = Y.map(function () {
                return ++i;
            });
        }
        if (konst) {
            X = X.clone();
            X.eachRow(function (row) {
                X.data[row].unshift(1);
            });
            ++X.width;
        }
        var Xt = X.transpose();
        var B = Xt.multiply(X).inverse().multiply(Xt).multiply(Y);
        var line_1 = [];
        for (i = B.height - 1; i >= 0; i--) {
            line_1.push(B.data[i][0]);
        }
        if (!konst) {
            line_1.push(0);
        }
        if (!stats) {
            return this.asMatrix([line_1]);
        }
        var Y1 = X.multiply(B);
        var y_y1 = Y.adds(Y1, true);
        var mp = !konst ? 0 : _mat_mean(Y1);
        var SSreg = _mat_devsq(Y1, mp);
        var me = !konst ? 0 : _mat_mean(y_y1);
        var SSresid = _mat_devsq(y_y1, me);
        var line_5 = [];
        line_5.push(SSreg, SSresid);
        var R2 = SSreg / (SSreg + SSresid);
        var degfre = Y.height - X.width;
        var err_est = Math.sqrt(SSresid / degfre);
        var line_3 = [];
        line_3.push(R2, err_est);
        var F_sta = !konst ? R2 / X.width / ((1 - R2) / degfre) : SSreg / (X.width - 1) / (SSresid / degfre);
        var line_4 = [];
        line_4.push(F_sta, degfre);
        var SCP = Xt.multiply(X).inverse();
        var line_2 = [];
        for (i = SCP.height - 1; i >= 0; i--) {
            line_2.push(Math.sqrt(SCP.data[i][i] * SSresid / degfre));
        }
        return this.asMatrix([
            line_1,
            line_2,
            line_3,
            line_4,
            line_5
        ]);
    }
    function logest(Y, X, konst, stats) {
        return linest.call(this, Y.map(Math.log), X, konst, stats).map(Math.exp);
    }
    function trend(Y, X, W, konst) {
        var i = 0;
        if (!X) {
            X = Y.map(function () {
                return ++i;
            });
        }
        if (konst) {
            X = X.clone();
            X.eachRow(function (row) {
                X.data[row].unshift(1);
            });
            ++X.width;
        }
        var Xt = X.transpose();
        var B = Xt.multiply(X).inverse().multiply(Xt).multiply(Y);
        if (!W) {
            W = X;
        } else {
            if (konst) {
                W = W.clone();
                W.eachRow(function (row) {
                    W.data[row].unshift(1);
                });
                ++W.width;
            }
        }
        return W.multiply(B);
    }
    function growth(Y, X, new_X, konst) {
        return trend.call(this, Y.map(Math.log), X, new_X, konst).map(Math.exp);
    }
    function root_newton(func, guess, max_it, eps) {
        var MAX_IT = max_it || 20, EPS = eps || 1e-7;
        var root = guess;
        for (var j = 1; j <= MAX_IT; j++) {
            var f_d = func(root), f = f_d[0], df = f_d[1];
            var dx = f / df;
            root -= dx;
            if (Math.abs(dx) < EPS) {
                return root;
            }
        }
        return new CalcError('NUM');
    }
    function FV(rate, nper, pmt, pv, type) {
        var h1 = Math.pow(1 + rate, nper);
        var h2 = rate ? (h1 - 1) / rate : nper;
        return -(pv * h1 + pmt * h2 * (1 + rate * type));
    }
    function PV(rate, nper, pmt, fv, type) {
        if (!rate) {
            return -fv - pmt * nper;
        }
        var h1 = Math.pow(1 + rate, nper);
        return -(fv + pmt * (h1 - 1) / rate * (1 + rate * type)) / h1;
    }
    function PMT(rate, nper, pv, fv, type) {
        if (!rate) {
            return -(fv + pv) / nper;
        }
        var h1 = Math.pow(1 + rate, nper);
        return -rate * (fv + pv * h1) / ((1 + rate * type) * (h1 - 1));
    }
    function NPER(rate, pmt, pv, fv, type) {
        if (!rate) {
            return -(fv + pv) / pmt;
        }
        var h1 = pmt * (1 + rate * type);
        return Math.log((h1 - fv * rate) / (h1 + pv * rate)) / Math.log(1 + rate);
    }
    function RATE(nper, pmt, pv, fv, type, guess) {
        function xfd(x) {
            var h2 = Math.pow(1 + x, nper - 1), h1 = h2 * (1 + x);
            return [
                pv * h1 + pmt * (1 / x + type) * (h1 - 1) + fv,
                nper * pv * h2 + pmt * (-(h1 - 1) / (x * x) + (1 / x + type) * nper * h2)
            ];
        }
        return root_newton(xfd, guess);
    }
    function IPMT(rate, per, nper, pv, fv, type) {
        if (type == 1 && per == 1) {
            return 0;
        }
        var pmt = PMT(rate, nper, pv, fv, type);
        var ipmt = FV(rate, per - 1, pmt, pv, type) * rate;
        return type ? ipmt / (1 + rate) : ipmt;
    }
    function PPMT(rate, per, nper, pv, fv, type) {
        var pmt = PMT(rate, nper, pv, fv, type);
        return pmt - IPMT(rate, per, nper, pv, fv, type);
    }
    function CUMPRINC(rate, nper, pv, start, end, type) {
        if (type == 1) {
            start--;
            end--;
        }
        var tn = Math.pow(1 + rate, nper), ts = Math.pow(1 + rate, start - 1), te = Math.pow(1 + rate, end);
        var monthlyPayment = rate * pv * tn / (tn - 1);
        var remainingBalanceAtStart = ts * pv - (ts - 1) / rate * monthlyPayment;
        var remainingBalanceAtEnd = te * pv - (te - 1) / rate * monthlyPayment;
        return remainingBalanceAtEnd - remainingBalanceAtStart;
    }
    function CUMIPMT(rate, nper, pv, start, end, type) {
        var cip = 0;
        for (var i = start; i <= end; i++) {
            cip += IPMT(rate, i, nper, pv, 0, type);
        }
        return cip;
    }
    function NPV(rate, flows) {
        var npv = 0;
        for (var i = 0, n = flows.length; i < n; i++) {
            npv += flows[i] * Math.pow(1 + rate, -i - 1);
        }
        return npv;
    }
    function IRR(flows, guess) {
        function xfd(x) {
            var npv = 0, npv1 = 0;
            for (var j = 0, n = flows.length; j < n; j++) {
                npv += flows[j] * Math.pow(1 + x, -j - 1);
                npv1 += -j * flows[j] * Math.pow(1 + x, -j - 2);
            }
            return [
                npv,
                npv1
            ];
        }
        return root_newton(xfd, guess);
    }
    function EFFECT(nominal_rate, npery) {
        return Math.pow(1 + nominal_rate / npery, npery) - 1;
    }
    function NOMINAL(effect_rate, npery) {
        return npery * (Math.pow(effect_rate + 1, 1 / npery) - 1);
    }
    function XNPV(rate, values, dates) {
        var npv = 0;
        for (var i = 0, n = values.length; i < n; i++) {
            npv += values[i] * Math.pow(1 + rate, (dates[0] - dates[i]) / 365);
        }
        return npv;
    }
    function XIRR(values, dates, guess) {
        function xfd(x) {
            var npv = values[0], npv1 = 0;
            for (var j = 1, n = values.length; j < n; j++) {
                var delta = (dates[0] - dates[j]) / 365;
                npv += values[j] * Math.pow(1 + x, delta);
                npv1 += delta * values[j] * Math.pow(1 + x, delta - 1);
            }
            return [
                npv,
                npv1
            ];
        }
        return root_newton(xfd, guess);
    }
    function ISPMT(rate, per, nper, pv) {
        var tmp = -pv * rate;
        return tmp * (1 - per / nper);
    }
    function DB(cost, salvage, life, period, month) {
        var rate = 1 - Math.pow(salvage / cost, 1 / life);
        rate = Math.floor(rate * 1000 + 0.5) / 1000;
        var db = cost * rate * month / 12;
        if (period == 1) {
            return db;
        }
        for (var i = 1; i < life; i++) {
            if (i == period - 1) {
                return (cost - db) * rate;
            }
            db += (cost - db) * rate;
        }
        return (cost - db) * rate * (12 - month) / 12;
    }
    function DDB(cost, salvage, life, period, factor) {
        var f = factor / life;
        var prior = -cost * (Math.pow(1 - f, period - 1) - 1);
        var dep = (cost - prior) * f;
        dep = Math.min(dep, Math.max(0, cost - prior - salvage));
        return dep;
    }
    function SLN(cost, salvage, life) {
        return (cost - salvage) / life;
    }
    function SYD(cost, salvage, life, per) {
        return (cost - salvage) * (life - per + 1) * 2 / (life * (life + 1));
    }
    function VDB(cost, salvage, life, start, end, factor, no_switch) {
        var interest = factor >= life ? 1 : factor / life;
        function _getGDA(value, period) {
            var gda, oldValue, newValue;
            if (interest == 1) {
                oldValue = period == 1 ? value : 0;
            } else {
                oldValue = value * Math.pow(1 - interest, period - 1);
            }
            newValue = value * Math.pow(1 - interest, period);
            gda = newValue < salvage ? oldValue - salvage : oldValue - newValue;
            return gda < 0 ? 0 : gda;
        }
        function _interVDB(cost, life1, period) {
            var remValue = cost - salvage;
            var intEnd = Math.ceil(period);
            var term, lia = 0, vdb = 0, nowLia = false;
            for (var i = 1; i <= intEnd; i++) {
                if (!nowLia) {
                    var gda = _getGDA(cost, i);
                    lia = remValue / (life1 - i + 1);
                    if (lia > gda) {
                        term = lia;
                        nowLia = true;
                    } else {
                        term = gda;
                        remValue -= gda;
                    }
                } else {
                    term = lia;
                }
                if (i == intEnd) {
                    term *= period + 1 - intEnd;
                }
                vdb += term;
            }
            return vdb;
        }
        var intStart = Math.floor(start), intEnd = Math.ceil(end);
        var vdb = 0;
        if (no_switch) {
            for (var i = intStart + 1; i <= intEnd; i++) {
                var term = _getGDA(cost, i);
                if (i == intStart + 1) {
                    term *= Math.min(end, intStart + 1) - start;
                } else {
                    if (i == intEnd) {
                        term *= end + 1 - intEnd;
                    }
                }
                vdb += term;
            }
        } else {
            var life1 = life;
            if (start != Math.floor(start)) {
                if (factor > 1) {
                    if (start >= life / 2) {
                        var part = start - life / 2;
                        start = life / 2;
                        end -= part;
                        life1 += 1;
                    }
                }
            }
            cost -= _interVDB(cost, life1, start);
            vdb = _interVDB(cost, life - start, end - start);
        }
        return vdb;
    }
    function _edate(base, months) {
        var d = unpackDate(base);
        var m = d.month + months;
        var y = d.year + Math.floor(m / 12);
        m %= 12;
        if (m < 0) {
            m += 12;
        }
        d = Math.min(d.date, daysInMonth(y, m));
        return packDate(y, m, d);
    }
    function _daysBetween(from, to, basis) {
        if (basis == 1 || basis == 2 || basis == 3) {
            return to - from;
        }
        return _days_360(from, to, basis);
    }
    function _borderCoupons(settlement, maturity, freq) {
        var sett = unpackDate(settlement), base = unpackDate(maturity);
        var periods = base.year - sett.year;
        if (periods > 0) {
            periods = (periods - 1) * freq;
        }
        var prev, next, months = 12 / freq;
        do {
            periods++;
            prev = _edate(maturity, -periods * months);
        } while (settlement < prev);
        periods--;
        next = _edate(maturity, -periods * months);
        return [
            prev,
            next
        ];
    }
    function _borderCoupons_fw(first, settlement, freq) {
        var sett = unpackDate(settlement), base = unpackDate(first);
        var periods = sett.year - base.year;
        if (periods > 0) {
            periods = (periods - 1) * freq;
        }
        var prev = first, next, months = 12 / freq;
        while (settlement > prev) {
            next = prev;
            periods++;
            prev = _edate(first, periods * months);
        }
        return [
            next,
            prev
        ];
    }
    function COUPDAYBS(settlement, maturity, frequency, basis) {
        var prev = _borderCoupons(settlement, maturity, frequency)[0];
        return _daysBetween(prev, settlement, basis);
    }
    function COUPDAYS(settl, matur, freq, basis) {
        if (basis == 1) {
            var borders = _borderCoupons(settl, matur, freq);
            return _daysBetween(borders[0], borders[1], 1);
        }
        if (basis == 3) {
            return 365 / freq;
        }
        return 360 / freq;
    }
    function COUPDAYSNC(settl, matur, freq, basis) {
        var next = _borderCoupons(settl, matur, freq)[1];
        return _daysBetween(settl, next, basis);
    }
    function COUPPCD(settl, matur, freq) {
        return _borderCoupons(settl, matur, freq)[0];
    }
    function COUPNCD(settl, matur, freq) {
        return _borderCoupons(settl, matur, freq)[1];
    }
    function COUPNUM(settl, matur, freq) {
        var sett = unpackDate(settl), mat = unpackDate(matur);
        var months = 12 * (mat.year - sett.year) + mat.month - sett.month;
        return 1 + (months * freq / 12 | 0);
    }
    function daysInYear(yr, basis) {
        if (basis == 3) {
            return 365;
        }
        if (basis == 1) {
            return isLeapYear(yr) ? 366 : 365;
        }
        return 360;
    }
    function ACCRINTM(issue, maturity, rate, par, basis) {
        var year_days = daysInYear(unpackDate(maturity).year, basis);
        return rate * par * _daysBetween(issue, maturity, basis) / year_days;
    }
    function ACCRINT(issue, first, settl, rate, par, freq, basis, calc) {
        var accr = 0, cost = par * rate / freq;
        var brace, prev, next, prev1, next1, nrc;
        var annual = basis % 2 === 0 ? 360 : 365;
        function _numCoupons(from, to) {
            return (to - from) * freq / annual | 0;
        }
        if (settl <= first) {
            brace = _borderCoupons(settl, first, freq);
            prev = brace[0];
            next = brace[1];
            if (prev <= issue) {
                return cost * _daysBetween(issue, settl, basis) / _daysBetween(prev, next, basis);
            }
            brace = _borderCoupons(issue, prev, freq);
            prev1 = brace[0];
            next1 = brace[1];
            nrc = _numCoupons(next1, settl);
            return cost * (nrc + _daysBetween(issue, next1, basis) / _daysBetween(prev1, next1, basis) + (settl < next ? _daysBetween(prev, settl, basis) / _daysBetween(prev, next, basis) : 0));
        } else {
            brace = _borderCoupons_fw(first, settl, freq);
            prev = brace[0];
            next = brace[1];
            nrc = _numCoupons(first, settl);
            if (next == settl) {
                accr = cost * nrc;
            } else {
                accr = cost * (nrc + _daysBetween(prev, settl, basis) / _daysBetween(prev, next, basis));
            }
            if (!calc) {
                return accr;
            }
            brace = _borderCoupons(issue, first, freq);
            prev = brace[0];
            next = brace[1];
            nrc = _numCoupons(issue, first);
            accr += cost * (nrc + _daysBetween(issue, next, basis) / _daysBetween(prev, next, basis));
            return accr;
        }
    }
    function DISC(settl, matur, pr, redemption, basis) {
        var annual = basis % 2 === 0 ? 360 : isLeapYear(unpackDate(settl).year) ? 366 : 365;
        return (redemption - pr) / redemption * annual / _daysBetween(settl, matur, basis);
    }
    function INTRATE(settl, matur, investment, redemption, basis) {
        var annual = basis % 2 === 0 ? 360 : isLeapYear(unpackDate(settl).year) ? 366 : 365;
        return (redemption - investment) / investment * annual / _daysBetween(settl, matur, basis);
    }
    function RECEIVED(settl, matur, investment, discount, basis) {
        var annual = basis % 2 === 0 ? 360 : isLeapYear(unpackDate(settl).year) ? 366 : 365;
        return investment / (1 - discount * _daysBetween(settl, matur, basis) / annual);
    }
    function PRICE(settl, matur, rate, yld, redemption, freq, basis) {
        var N = 1 + ((matur - settl) * freq / (basis % 2 === 0 ? 360 : 365) | 0);
        var brace = _borderCoupons(settl, matur, freq), prev = brace[0], next = brace[1];
        var beg_settl = _daysBetween(prev, settl, basis), settl_end = _daysBetween(settl, next, basis), beg_end = _daysBetween(prev, next, basis);
        var den = 100 * rate / freq, yf = yld / freq, frac = settl_end / beg_end;
        if (N == 1) {
            return (redemption + den) / (1 + frac * yf) - beg_settl / beg_end * den;
        }
        return redemption / Math.pow(1 + yf, N - 1 + frac) + den * Math.pow(1 + yf, 1 - N - frac) * (Math.pow(1 + yf, N) - 1) / yf - beg_settl / beg_end * den;
    }
    function PRICEDISC(settl, matur, discount, redemption, basis) {
        var dsm = _daysBetween(settl, matur, basis), dy = daysInYear(unpackDate(matur).year, basis);
        return redemption - discount * redemption * dsm / dy;
    }
    function whipNumberArrays(a, b) {
        for (var i = a.length; --i >= 0;) {
            if (typeof a[i] != 'number' || typeof b[i] != 'number') {
                a.splice(i, 1);
                b.splice(i, 1);
            }
        }
    }
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/borderpalette', [
        'kendo.core',
        'kendo.colorpicker',
        'kendo.popup'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var BORDER_TYPES = [
            'allBorders',
            'insideBorders',
            'insideHorizontalBorders',
            'insideVerticalBorders',
            'outsideBorders',
            'leftBorder',
            'topBorder',
            'rightBorder',
            'bottomBorder',
            'noBorders'
        ];
        var BORDER_PALETTE_MESSAGES = kendo.spreadsheet.messages.borderPalette = {
            allBorders: 'All borders',
            insideBorders: 'Inside borders',
            insideHorizontalBorders: 'Inside horizontal borders',
            insideVerticalBorders: 'Inside vertical borders',
            outsideBorders: 'Outside borders',
            leftBorder: 'Left border',
            topBorder: 'Top border',
            rightBorder: 'Right border',
            bottomBorder: 'Bottom border',
            noBorders: 'No border'
        };
        var COLOR_PICKER_MESSAGES = kendo.spreadsheet.messages.colorPicker = {
            reset: 'Reset color',
            customColor: 'Custom color...',
            apply: 'Apply',
            cancel: 'Cancel'
        };
        function withPreventDefault(f) {
            return function (e) {
                e.preventDefault();
                return f.apply(this, arguments);
            };
        }
        var ColorChooser = kendo.ui.Widget.extend({
            init: function (element, options) {
                kendo.ui.Widget.call(this, element, options);
                this.element = element;
                this.color = options.color;
                this._resetButton();
                this._colorPalette();
                this._customColorPalette();
                this._customColorButton();
                this.resetButton.on('click', withPreventDefault(this.resetColor.bind(this)));
                this.customColorButton.on('click', withPreventDefault(this.customColor.bind(this)));
            },
            options: { name: 'ColorChooser' },
            events: ['change'],
            destroy: function () {
                kendo.unbind(this.dialog.element.find('.k-action-buttons'));
                this.dialog.destroy();
                this.colorPalette.destroy();
                this.resetButton.off('click');
                this.customColorButton.off('click');
            },
            value: function (value) {
                if (value !== undefined) {
                    this.color = value;
                    this.customColorButton.find('.k-icon').css('background-color', this.color);
                    this.colorPalette.value(null);
                    this.flatColorPicker.value(this.color);
                } else {
                    return this.color;
                }
            },
            _change: function (value) {
                this.color = value;
                this.trigger('change', { value: value });
            },
            _colorPalette: function () {
                var element = $('<div />', { 'class': 'k-spreadsheet-color-palette' });
                var colorPalette = this.colorPalette = $('<div />').kendoColorPalette({
                    palette: [
                        '#ffffff',
                        '#000000',
                        '#d6ecff',
                        '#4e5b6f',
                        '#7fd13b',
                        '#ea157a',
                        '#feb80a',
                        '#00addc',
                        '#738ac8',
                        '#1ab39f',
                        '#f2f2f2',
                        '#7f7f7f',
                        '#a7d6ff',
                        '#d9dde4',
                        '#e5f5d7',
                        '#fad0e4',
                        '#fef0cd',
                        '#c5f2ff',
                        '#e2e7f4',
                        '#c9f7f1',
                        '#d8d8d8',
                        '#595959',
                        '#60b5ff',
                        '#b3bcca',
                        '#cbecb0',
                        '#f6a1c9',
                        '#fee29c',
                        '#8be6ff',
                        '#c7d0e9',
                        '#94efe3',
                        '#bfbfbf',
                        '#3f3f3f',
                        '#007dea',
                        '#8d9baf',
                        '#b2e389',
                        '#f272af',
                        '#fed46b',
                        '#51d9ff',
                        '#aab8de',
                        '#5fe7d5',
                        '#a5a5a5',
                        '#262626',
                        '#003e75',
                        '#3a4453',
                        '#5ea226',
                        '#af0f5b',
                        '#c58c00',
                        '#0081a5',
                        '#425ea9',
                        '#138677',
                        '#7f7f7f',
                        '#0c0c0c',
                        '#00192e',
                        '#272d37',
                        '#3f6c19',
                        '#750a3d',
                        '#835d00',
                        '#00566e',
                        '#2c3f71',
                        '#0c594f'
                    ],
                    value: this.color,
                    change: function (e) {
                        this.customColorButton.find('.k-icon').css('background-color', 'transparent');
                        this.flatColorPicker.value(null);
                        this._change(e.value);
                    }.bind(this)
                }).data('kendoColorPalette');
                element.append(colorPalette.wrapper).appendTo(this.element);
            },
            _customColorPalette: function () {
                var element = $('<div />', {
                    'class': 'k-spreadsheet-window',
                    'html': '<div></div>' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: apply\'>' + COLOR_PICKER_MESSAGES.apply + '</button>' + '<button class=\'k-button\' data-bind=\'click: close\'>' + COLOR_PICKER_MESSAGES.cancel + '</button>' + '</div>'
                });
                var dialog = this.dialog = element.appendTo(document.body).kendoWindow({
                    animation: false,
                    scrollable: false,
                    resizable: false,
                    maximizable: false,
                    modal: true,
                    visible: false,
                    width: 268,
                    open: function () {
                        this.center();
                    }
                }).data('kendoWindow');
                dialog.one('activate', function () {
                    this.element.find('[data-role=flatcolorpicker]').data('kendoFlatColorPicker')._hueSlider.resize();
                });
                var flatColorPicker = this.flatColorPicker = dialog.element.children().first().kendoFlatColorPicker().data('kendoFlatColorPicker');
                var viewModel = kendo.observable({
                    apply: function () {
                        this.customColorButton.find('.k-icon').css('background-color', flatColorPicker.value());
                        this.colorPalette.value(null);
                        this._change(flatColorPicker.value());
                        dialog.close();
                    }.bind(this),
                    close: function () {
                        flatColorPicker.value(null);
                        dialog.close();
                    }
                });
                kendo.bind(dialog.element.find('.k-action-buttons'), viewModel);
            },
            _resetButton: function () {
                this.resetButton = $('<a class=\'k-button k-reset-color\' href=\'#\'>' + '<span class=\'k-icon k-i-reset-color\'></span>' + COLOR_PICKER_MESSAGES.reset + '</a>').appendTo(this.element);
            },
            _customColorButton: function () {
                this.customColorButton = $('<a class=\'k-button k-custom-color\' href=\'#\'>' + '<span class=\'k-icon\'></span>' + COLOR_PICKER_MESSAGES.customColor + '</a>').appendTo(this.element);
            },
            resetColor: function () {
                this.colorPalette.value(null);
                this.flatColorPicker.value(null);
                this._change(null);
            },
            customColor: function () {
                this.dialog.open();
            }
        });
        var BorderPalette = kendo.ui.Widget.extend({
            init: function (element, options) {
                kendo.ui.Widget.call(this, element, options);
                this.element = element;
                this.color = '#000';
                this.element.addClass('k-spreadsheet-border-palette');
                this._borderTypePalette();
                this._borderColorPalette();
                this.element.on('click', '.k-spreadsheet-border-type-palette .k-button', withPreventDefault(this._click.bind(this)));
            },
            options: { name: 'BorderPalette' },
            events: ['change'],
            destroy: function () {
                this.colorChooser.destroy();
                this.element.off('click');
            },
            _borderTypePalette: function () {
                var messages = BORDER_PALETTE_MESSAGES;
                var buttons = BORDER_TYPES.map(function (type) {
                    return '<a title="' + messages[type] + '" aria-label="' + messages[type] + '" href="#" data-border-type="' + type + '" class="k-button k-button-icon">' + '<span class="k-icon k-i-' + kendo.toHyphens(type) + '"></span>' + '</a>';
                }).join('');
                var element = $('<div />', {
                    'class': 'k-spreadsheet-border-type-palette',
                    'html': buttons
                });
                element.appendTo(this.element);
            },
            _borderColorPalette: function () {
                var element = $('<div />', { 'class': 'k-spreadsheet-border-color-palette' });
                element.appendTo(this.element);
                this.colorChooser = new ColorChooser(element, {
                    color: this.color,
                    change: this._colorChange.bind(this)
                });
            },
            _click: function (e) {
                this.type = $(e.currentTarget).data('borderType');
                this.trigger('change', {
                    type: this.type,
                    color: this.color
                });
            },
            _colorChange: function (e) {
                this.color = e.value;
                if (this.type) {
                    this.trigger('change', {
                        type: this.type,
                        color: this.color
                    });
                }
            }
        });
        kendo.spreadsheet.ColorChooser = ColorChooser;
        kendo.spreadsheet.BorderPalette = BorderPalette;
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/toolbar', [
        'kendo.toolbar',
        'kendo.colorpicker',
        'kendo.combobox',
        'kendo.dropdownlist',
        'kendo.popup',
        'spreadsheet/borderpalette'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var ToolBar = kendo.ui.ToolBar;
        var MESSAGES = kendo.spreadsheet.messages.toolbar = {
            addColumnLeft: 'Add column left',
            addColumnRight: 'Add column right',
            addRowAbove: 'Add row above',
            addRowBelow: 'Add row below',
            alignment: 'Alignment',
            alignmentButtons: {
                justtifyLeft: 'Align left',
                justifyCenter: 'Center',
                justifyRight: 'Align right',
                justifyFull: 'Justify',
                alignTop: 'Align top',
                alignMiddle: 'Align middle',
                alignBottom: 'Align bottom'
            },
            backgroundColor: 'Background',
            bold: 'Bold',
            borders: 'Borders',
            copy: 'Copy',
            cut: 'Cut',
            deleteColumn: 'Delete column',
            deleteRow: 'Delete row',
            filter: 'Filter',
            fontFamily: 'Font',
            fontSize: 'Font size',
            format: 'Custom format...',
            formatTypes: {
                automatic: 'Automatic',
                text: 'Text',
                number: 'Number',
                percent: 'Percent',
                financial: 'Financial',
                currency: 'Currency',
                date: 'Date',
                time: 'Time',
                dateTime: 'Date time',
                duration: 'Duration',
                moreFormats: 'More formats...'
            },
            formatDecreaseDecimal: 'Decrease decimal',
            formatIncreaseDecimal: 'Increase decimal',
            freeze: 'Freeze panes',
            freezeButtons: {
                freezePanes: 'Freeze panes',
                freezeRows: 'Freeze rows',
                freezeColumns: 'Freeze columns',
                unfreeze: 'Unfreeze panes'
            },
            insertComment: 'Insert comment',
            insertImage: 'Insert image',
            italic: 'Italic',
            merge: 'Merge cells',
            mergeButtons: {
                mergeCells: 'Merge all',
                mergeHorizontally: 'Merge horizontally',
                mergeVertically: 'Merge vertically',
                unmerge: 'Unmerge'
            },
            open: 'Open...',
            paste: 'Paste',
            quickAccess: {
                redo: 'Redo',
                undo: 'Undo'
            },
            exportAs: 'Export...',
            toggleGridlines: 'Toggle gridlines',
            sort: 'Sort',
            sortButtons: {
                sortRangeAsc: 'Sort range A to Z',
                sortRangeDesc: 'Sort range Z to A'
            },
            textColor: 'Text Color',
            textWrap: 'Wrap text',
            underline: 'Underline',
            validation: 'Data validation...',
            hyperlink: 'Link'
        };
        var defaultTools = {
            home: [
                'open',
                'exportAs',
                [
                    'cut',
                    'copy',
                    'paste'
                ],
                [
                    'bold',
                    'italic',
                    'underline'
                ],
                'hyperlink',
                'insertComment',
                'insertImage',
                'backgroundColor',
                'textColor',
                'borders',
                'fontSize',
                'fontFamily',
                'alignment',
                'textWrap',
                [
                    'formatDecreaseDecimal',
                    'formatIncreaseDecimal'
                ],
                'format',
                'merge',
                'freeze',
                'filter',
                'toggleGridlines'
            ],
            insert: [
                [
                    'addColumnLeft',
                    'addColumnRight',
                    'addRowBelow',
                    'addRowAbove'
                ],
                [
                    'deleteColumn',
                    'deleteRow'
                ]
            ],
            data: [
                'sort',
                'filter',
                'validation'
            ]
        };
        var toolDefaults = {
            open: {
                type: 'open',
                overflow: 'never',
                iconClass: 'file-excel'
            },
            exportAs: {
                type: 'exportAsDialog',
                dialogName: 'exportAs',
                overflow: 'never',
                text: '',
                iconClass: 'file-excel'
            },
            bold: {
                type: 'button',
                command: 'PropertyChangeCommand',
                property: 'bold',
                value: true,
                iconClass: 'bold',
                togglable: true
            },
            italic: {
                type: 'button',
                command: 'PropertyChangeCommand',
                property: 'italic',
                value: true,
                iconClass: 'italic',
                togglable: true
            },
            underline: {
                type: 'button',
                command: 'PropertyChangeCommand',
                property: 'underline',
                value: true,
                iconClass: 'underline',
                togglable: true
            },
            formatDecreaseDecimal: {
                type: 'button',
                command: 'AdjustDecimalsCommand',
                value: -1,
                iconClass: 'decimal-decrease'
            },
            formatIncreaseDecimal: {
                type: 'button',
                command: 'AdjustDecimalsCommand',
                value: +1,
                iconClass: 'decimal-increase'
            },
            textWrap: {
                type: 'button',
                command: 'TextWrapCommand',
                property: 'wrap',
                value: true,
                iconClass: 'text-wrap',
                togglable: true
            },
            cut: {
                type: 'button',
                command: 'ToolbarCutCommand',
                iconClass: 'cut'
            },
            copy: {
                type: 'button',
                command: 'ToolbarCopyCommand',
                iconClass: 'copy'
            },
            paste: {
                type: 'button',
                command: 'ToolbarPasteCommand',
                iconClass: 'paste'
            },
            separator: { type: 'separator' },
            alignment: {
                type: 'alignment',
                iconClass: 'align-left'
            },
            backgroundColor: {
                type: 'colorPicker',
                property: 'background',
                iconClass: 'paint'
            },
            textColor: {
                type: 'colorPicker',
                property: 'color',
                iconClass: 'foreground-color'
            },
            fontFamily: {
                type: 'fontFamily',
                property: 'fontFamily',
                iconClass: 'font-family'
            },
            fontSize: {
                type: 'fontSize',
                property: 'fontSize',
                iconClass: 'font-size'
            },
            format: {
                type: 'format',
                property: 'format',
                iconClass: 'custom-format'
            },
            filter: {
                type: 'filter',
                property: 'hasFilter',
                iconClass: 'filter'
            },
            merge: {
                type: 'merge',
                iconClass: 'cells-merge'
            },
            freeze: {
                type: 'freeze',
                iconClass: 'pane-freeze'
            },
            borders: {
                type: 'borders',
                iconClass: 'borders-all'
            },
            formatCells: {
                type: 'dialog',
                dialogName: 'formatCells',
                overflow: 'never'
            },
            hyperlink: {
                type: 'dialog',
                dialogName: 'hyperlink',
                iconClass: 'link-horizontal',
                overflow: 'never',
                text: ''
            },
            toggleGridlines: {
                type: 'button',
                command: 'GridLinesChangeCommand',
                property: 'gridLines',
                value: true,
                iconClass: 'border-no',
                togglable: true
            },
            insertComment: {
                type: 'dialog',
                dialogName: 'insertComment',
                property: 'comment',
                togglable: true,
                overflow: 'never',
                iconClass: 'comment',
                text: ''
            },
            insertImage: {
                type: 'dialog',
                dialogName: 'insertImage',
                overflow: 'never',
                iconClass: 'image',
                text: ''
            },
            addColumnLeft: {
                type: 'button',
                command: 'AddColumnCommand',
                value: 'left',
                iconClass: 'table-column-insert-left'
            },
            addColumnRight: {
                type: 'button',
                command: 'AddColumnCommand',
                value: 'right',
                iconClass: 'table-column-insert-right'
            },
            addRowBelow: {
                type: 'button',
                command: 'AddRowCommand',
                value: 'below',
                iconClass: 'table-row-insert-below'
            },
            addRowAbove: {
                type: 'button',
                command: 'AddRowCommand',
                value: 'above',
                iconClass: 'table-row-insert-above'
            },
            deleteColumn: {
                type: 'button',
                command: 'DeleteColumnCommand',
                iconClass: 'table-column-delete'
            },
            deleteRow: {
                type: 'button',
                command: 'DeleteRowCommand',
                iconClass: 'table-row-delete'
            },
            sort: {
                type: 'sort',
                iconClass: 'sort-desc'
            },
            validation: {
                type: 'dialog',
                dialogName: 'validation',
                iconClass: 'exception',
                overflow: 'never'
            }
        };
        var SpreadsheetToolBar = ToolBar.extend({
            init: function (element, options) {
                options.items = this._expandTools(options.tools || SpreadsheetToolBar.prototype.options.tools[options.toolbarName]);
                ToolBar.fn.init.call(this, element, options);
                var handleClick = this._click.bind(this);
                this.element.addClass('k-spreadsheet-toolbar');
                this._addSeparators(this.element);
                var that = this;
                this.element.on('keydown', function (e) {
                    var tool;
                    if (e.keyCode === 9) {
                        tool = that._nextTool(e.shiftKey ? -1 : 1);
                        if (tool) {
                            document.activeElement.blur();
                            if ($(tool).is('.k-upload-button')) {
                                $(tool).addClass('k-state-focused');
                            }
                            if ($(tool).find('input').length) {
                                $(tool).find('input').focus();
                            } else {
                                tool.focus();
                            }
                            e.preventDefault();
                        }
                    }
                });
                this.element.on('focusout', function () {
                    $(this).find('.k-toolbar-first-visible').removeClass('k-state-focused');
                });
                this.bind({
                    click: handleClick,
                    toggle: handleClick
                });
            },
            _nextTool: function (direction) {
                var that = this;
                var tools = that.element.find('.k-widget, .k-button, .k-button-group > a');
                var activeIndex = tools.index($(document.activeElement).closest('.k-widget, .k-button, .k-button-group > a'));
                if (activeIndex > 0) {
                    return tools[activeIndex + direction];
                }
            },
            _addSeparators: function (element) {
                var groups = element.children('.k-widget, a.k-button, .k-button-group');
                groups.before('<span class=\'k-separator\' />');
            },
            _expandTools: function (tools) {
                function expandTool(toolName) {
                    var options = $.isPlainObject(toolName) ? toolName : toolDefaults[toolName] || {};
                    var spriteCssClass = 'k-icon k-i-' + options.iconClass;
                    var type = options.type;
                    var typeDefaults = {
                        button: { showText: 'overflow' },
                        colorPicker: {
                            toolIcon: spriteCssClass,
                            spriteCssClass: spriteCssClass
                        },
                        borders: { spriteCssClass: spriteCssClass },
                        alignment: { spriteCssClass: spriteCssClass },
                        merge: { spriteCssClass: spriteCssClass },
                        freeze: { spriteCssClass: spriteCssClass }
                    };
                    var tool = $.extend({
                        name: options.name || toolName,
                        text: MESSAGES[options.name || toolName],
                        icon: options.iconClass,
                        attributes: {
                            title: MESSAGES[options.name || toolName],
                            'aria-label': MESSAGES[options.name || toolName]
                        }
                    }, typeDefaults[type], options);
                    if (type == 'splitButton') {
                        tool.menuButtons = tool.menuButtons.map(expandTool);
                    }
                    tool.attributes['data-tool'] = toolName;
                    if (options.property) {
                        tool.attributes['data-property'] = options.property;
                    }
                    return tool;
                }
                return tools.reduce(function (tools, tool) {
                    if ($.isArray(tool)) {
                        tools.push({
                            type: 'buttonGroup',
                            buttons: tool.map(expandTool)
                        });
                    } else {
                        tools.push(expandTool.call(this, tool));
                    }
                    return tools;
                }, []);
            },
            _click: function (e) {
                var toolName = e.target.attr('data-tool');
                var tool = toolDefaults[toolName] || {};
                var commandType = tool.command;
                if (!commandType) {
                    return;
                }
                var args = {
                    command: commandType,
                    options: {
                        property: tool.property || null,
                        value: tool.value || null
                    }
                };
                if (typeof args.options.value === 'boolean') {
                    args.options.value = e.checked ? true : null;
                }
                this.action(args);
            },
            events: [
                'click',
                'toggle',
                'open',
                'close',
                'overflowOpen',
                'overflowClose',
                'action',
                'dialog'
            ],
            options: {
                name: 'SpreadsheetToolBar',
                resizable: true,
                tools: defaultTools
            },
            action: function (args) {
                this.trigger('action', args);
            },
            dialog: function (args) {
                this.trigger('dialog', args);
            },
            refresh: function (activeCell) {
                var range = activeCell;
                var tools = this._tools();
                function setToggle(tool, value) {
                    var toolbar = tool.toolbar;
                    var overflow = tool.overflow;
                    var togglable = toolbar && toolbar.options.togglable || overflow && overflow.options.togglable;
                    if (!togglable) {
                        return;
                    }
                    var toggle = false;
                    if (typeof value === 'boolean') {
                        toggle = value;
                    } else if (typeof value === 'string') {
                        if (toolbar.options.hasOwnProperty('value')) {
                            toggle = toolbar.options.value === value;
                        } else {
                            toggle = value != null;
                        }
                    }
                    toolbar.toggle(toggle);
                    if (overflow) {
                        overflow.toggle(toggle);
                    }
                }
                function update(tool, value) {
                    var toolbar = tool.toolbar;
                    var overflow = tool.overflow;
                    if (toolbar && toolbar.update) {
                        toolbar.update(value);
                    }
                    if (overflow && overflow.update) {
                        overflow.update(value);
                    }
                }
                for (var i = 0; i < tools.length; i++) {
                    var property = tools[i].property;
                    var tool = tools[i].tool;
                    var value = kendo.isFunction(range[property]) ? range[property]() : range;
                    if (property == 'gridLines') {
                        value = range.sheet().showGridLines();
                    }
                    if (tool.type === 'button') {
                        setToggle(tool, value);
                    } else {
                        update(tool, value);
                    }
                }
                this.resize();
            },
            _tools: function () {
                return this.element.find('[data-property]').toArray().map(function (element) {
                    element = $(element);
                    return {
                        property: element.attr('data-property'),
                        tool: this._getItem(element)
                    };
                }.bind(this));
            },
            destroy: function () {
                this.element.find('[data-command],.k-button').each(function () {
                    var element = $(this);
                    var instance = element.data('instance');
                    if (instance && instance.destroy) {
                        instance.destroy();
                    }
                });
                ToolBar.fn.destroy.call(this);
            }
        });
        kendo.spreadsheet.ToolBar = SpreadsheetToolBar;
        var DropDownTool = kendo.toolbar.Item.extend({
            init: function (options, toolbar) {
                var dropDownList = $('<select />').attr('title', options.attributes.title).attr('aria-label', options.attributes.title).kendoDropDownList({ height: 'auto' }).data('kendoDropDownList');
                this.dropDownList = dropDownList;
                this.element = dropDownList.wrapper;
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                dropDownList.bind('open', this._open.bind(this));
                dropDownList.bind('change', this._change.bind(this));
                this.element.width(options.width).attr({
                    'data-command': 'PropertyChangeCommand',
                    'data-property': options.property
                });
            },
            _open: function () {
                var ddl = this.dropDownList;
                var list = ddl.list;
                var listWidth;
                list.css({
                    whiteSpace: 'nowrap',
                    width: 'auto'
                });
                listWidth = list.width();
                if (listWidth > 0) {
                    listWidth += 20;
                } else {
                    listWidth = ddl._listWidth;
                }
                list.css('width', listWidth + kendo.support.scrollbar());
                ddl._listWidth = listWidth;
            },
            _change: function (e) {
                var that = this;
                var instance = e.sender;
                var value = instance.value();
                var dataItem = instance.dataItem();
                var popupName = dataItem ? dataItem.popup : undefined;
                if (popupName) {
                    setTimeout(function () {
                        that.toolbar.dialog({ name: popupName });
                    });
                } else {
                    that.toolbar.action({
                        command: 'PropertyChangeCommand',
                        options: {
                            property: this.options.property,
                            value: value == 'null' ? null : value
                        }
                    });
                }
            },
            value: function (value) {
                if (value !== undefined) {
                    this.dropDownList.value(value);
                } else {
                    return this.dropDownList.value();
                }
            }
        });
        var PopupTool = kendo.toolbar.Item.extend({
            init: function (options, toolbar) {
                this.element = $('<a href=\'#\' class=\'k-button k-button-icon\'>' + '<span class=\'' + options.spriteCssClass + '\'>' + '</span><span class=\'k-icon k-i-arrow-60-down\'></span>' + '</a>');
                this.element.on('click touchend', this.open.bind(this)).attr('data-command', options.command);
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                this._popup();
            },
            destroy: function () {
                this.popup.destroy();
            },
            open: function (ev) {
                ev.preventDefault();
                this.popup.toggle();
            },
            _popup: function () {
                var element = this.element;
                this.popup = $('<div class=\'k-spreadsheet-popup\' />').appendTo(element).kendoPopup({ anchor: element }).data('kendoPopup');
            }
        });
        kendo.toolbar.registerComponent('dialog', kendo.toolbar.ToolBarButton.extend({
            init: function (options, toolbar) {
                kendo.toolbar.ToolBarButton.fn.init.call(this, options, toolbar);
                this._dialogName = options.dialogName;
                this.element.bind('click touchend', this.open.bind(this)).data('instance', this);
            },
            open: function () {
                this.toolbar.dialog({ name: this._dialogName });
            }
        }));
        kendo.toolbar.registerComponent('exportAsDialog', kendo.toolbar.Item.extend({
            init: function (options, toolbar) {
                this._dialogName = options.dialogName;
                this.toolbar = toolbar;
                this._title = options.attributes.title;
                this.element = $('<button type=\'button\' class=\'k-button k-button-icon\'>' + '<span class=\'k-icon k-i-download\' />' + '</button>').attr('title', this._title).attr('aria-label', this._title).data('instance', this);
                this.element.bind('click', this.open.bind(this)).data('instance', this);
            },
            open: function () {
                this.toolbar.dialog({ name: this._dialogName });
            }
        }));
        var OverflowDialogButton = kendo.toolbar.OverflowButton.extend({
            init: function (options, toolbar) {
                kendo.toolbar.OverflowButton.fn.init.call(this, options, toolbar);
                this.element.on('click touchend', this._click.bind(this));
                this.message = this.options.text;
                var instance = this.element.data('button');
                this.element.data(this.options.type, instance);
            },
            _click: $.noop
        });
        var ColorPicker = PopupTool.extend({
            init: function (options, toolbar) {
                PopupTool.fn.init.call(this, options, toolbar);
                this.popup.element.addClass('k-spreadsheet-colorpicker');
                this.colorChooser = new kendo.spreadsheet.ColorChooser(this.popup.element, { change: this._colorChange.bind(this) });
                this.element.attr({ 'data-property': options.property });
                this.element.data({
                    type: 'colorPicker',
                    colorPicker: this,
                    instance: this
                });
            },
            destroy: function () {
                this.colorChooser.destroy();
                PopupTool.fn.destroy.call(this);
            },
            update: function (value) {
                this.value(value);
            },
            value: function (value) {
                this.colorChooser.value(value);
            },
            _colorChange: function (e) {
                this.toolbar.action({
                    command: 'PropertyChangeCommand',
                    options: {
                        property: this.options.property,
                        value: e.sender.value()
                    }
                });
                this.popup.close();
            }
        });
        var ColorPickerButton = OverflowDialogButton.extend({
            init: function (options, toolbar) {
                options.iconName = 'text';
                OverflowDialogButton.fn.init.call(this, options, toolbar);
            },
            _click: function () {
                this.toolbar.dialog({
                    name: 'colorPicker',
                    options: {
                        title: this.options.property,
                        property: this.options.property
                    }
                });
            }
        });
        kendo.toolbar.registerComponent('colorPicker', ColorPicker, ColorPickerButton);
        var FONT_SIZES = [
            8,
            9,
            10,
            11,
            12,
            13,
            14,
            16,
            18,
            20,
            22,
            24,
            26,
            28,
            36,
            48,
            72
        ];
        var DEFAULT_FONT_SIZE = 12;
        var FontSize = kendo.toolbar.Item.extend({
            init: function (options, toolbar) {
                var comboBox = $('<input />').attr('aria-label', options.attributes.title).kendoComboBox({
                    change: this._valueChange.bind(this),
                    clearButton: false,
                    dataSource: options.fontSizes || FONT_SIZES,
                    value: DEFAULT_FONT_SIZE
                }).data('kendoComboBox');
                this.comboBox = comboBox;
                this.element = comboBox.wrapper;
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                this.element.width(options.width).attr({
                    'data-command': 'PropertyChangeCommand',
                    'data-property': options.property
                });
                this.element.data({
                    type: 'fontSize',
                    fontSize: this
                });
            },
            _valueChange: function (e) {
                this.toolbar.action({
                    command: 'PropertyChangeCommand',
                    options: {
                        property: this.options.property,
                        value: kendo.parseInt(e.sender.value())
                    }
                });
            },
            update: function (value) {
                this.value(kendo.parseInt(value) || DEFAULT_FONT_SIZE);
            },
            value: function (value) {
                if (value !== undefined) {
                    this.comboBox.value(value);
                } else {
                    return this.comboBox.value();
                }
            }
        });
        var FontSizeButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({
                    name: 'fontSize',
                    options: {
                        sizes: FONT_SIZES,
                        defaultSize: DEFAULT_FONT_SIZE
                    }
                });
            },
            update: function (value) {
                this._value = value || DEFAULT_FONT_SIZE;
                this.element.find('.k-text').text(this.message + ' (' + this._value + ') ...');
            }
        });
        kendo.toolbar.registerComponent('fontSize', FontSize, FontSizeButton);
        var FONT_FAMILIES = [
            'Arial',
            'Courier New',
            'Georgia',
            'Times New Roman',
            'Trebuchet MS',
            'Verdana'
        ];
        var DEFAULT_FONT_FAMILY = 'Arial';
        var FontFamily = DropDownTool.extend({
            init: function (options, toolbar) {
                DropDownTool.fn.init.call(this, options, toolbar);
                var ddl = this.dropDownList;
                ddl.setDataSource(options.fontFamilies || FONT_FAMILIES);
                ddl.value(DEFAULT_FONT_FAMILY);
                this.element.data({
                    type: 'fontFamily',
                    fontFamily: this
                });
            },
            update: function (value) {
                this.value(value || DEFAULT_FONT_FAMILY);
            }
        });
        var FontFamilyButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({
                    name: 'fontFamily',
                    options: {
                        fonts: FONT_FAMILIES,
                        defaultFont: DEFAULT_FONT_FAMILY
                    }
                });
            },
            update: function (value) {
                this._value = value || DEFAULT_FONT_FAMILY;
                this.element.find('.k-text').text(this.message + ' (' + this._value + ') ...');
            }
        });
        kendo.toolbar.registerComponent('fontFamily', FontFamily, FontFamilyButton);
        var defaultFormats = kendo.spreadsheet.formats = {
            automatic: null,
            text: '@',
            number: '#,0.00',
            percent: '0.00%',
            financial: '_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_)',
            currency: '$#,##0.00;[Red]$#,##0.00',
            date: 'm/d/yyyy',
            time: 'h:mm:ss AM/PM',
            dateTime: 'm/d/yyyy h:mm',
            duration: '[h]:mm:ss'
        };
        var Format = DropDownTool.extend({
            _revertTitle: function (e) {
                e.sender.value('');
                e.sender.wrapper.width('auto');
            },
            init: function (options, toolbar) {
                DropDownTool.fn.init.call(this, options, toolbar);
                var ddl = this.dropDownList;
                var icon = '<span class=\'k-icon k-i-' + options.iconClass + '\' style=\'line-height: 1em; width: 1.35em;\'></span>';
                ddl.bind('change', this._revertTitle.bind(this));
                ddl.bind('dataBound', this._revertTitle.bind(this));
                ddl.setOptions({
                    dataValueField: 'format',
                    dataTextField: 'name',
                    dataValuePrimitive: true,
                    valueTemplate: icon,
                    template: '# if (data.sample) { #' + '<span class=\'k-spreadsheet-sample\'>#: data.sample #</span>' + '# } #' + '#: data.name #'
                });
                ddl.text(icon);
                ddl.setDataSource([
                    {
                        format: defaultFormats.automatic,
                        name: MESSAGES.formatTypes.automatic
                    },
                    {
                        format: defaultFormats.text,
                        name: MESSAGES.formatTypes.text
                    },
                    {
                        format: defaultFormats.number,
                        name: MESSAGES.formatTypes.number,
                        sample: '1,499.99'
                    },
                    {
                        format: defaultFormats.percent,
                        name: MESSAGES.formatTypes.percent,
                        sample: '14.50%'
                    },
                    {
                        format: defaultFormats.financial,
                        name: MESSAGES.formatTypes.financial,
                        sample: '(1,000.12)'
                    },
                    {
                        format: defaultFormats.currency,
                        name: MESSAGES.formatTypes.currency,
                        sample: '$1,499.99'
                    },
                    {
                        format: defaultFormats.date,
                        name: MESSAGES.formatTypes.date,
                        sample: '4/21/2012'
                    },
                    {
                        format: defaultFormats.time,
                        name: MESSAGES.formatTypes.time,
                        sample: '5:49:00 PM'
                    },
                    {
                        format: defaultFormats.dateTime,
                        name: MESSAGES.formatTypes.dateTime,
                        sample: '4/21/2012 5:49:00'
                    },
                    {
                        format: defaultFormats.duration,
                        name: MESSAGES.formatTypes.duration,
                        sample: '168:05:00'
                    },
                    {
                        popup: 'formatCells',
                        name: MESSAGES.formatTypes.moreFormats
                    }
                ]);
                this.element.data({
                    type: 'format',
                    format: this
                });
            }
        });
        var FormatButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({ name: 'formatCells' });
            }
        });
        kendo.toolbar.registerComponent('format', Format, FormatButton);
        var BorderChangeTool = PopupTool.extend({
            init: function (options, toolbar) {
                PopupTool.fn.init.call(this, options, toolbar);
                this._borderPalette();
                this.element.data({
                    type: 'borders',
                    instance: this
                });
            },
            destroy: function () {
                this.borderPalette.destroy();
                PopupTool.fn.destroy.call(this);
            },
            _borderPalette: function () {
                var element = $('<div />').appendTo(this.popup.element);
                this.borderPalette = new kendo.spreadsheet.BorderPalette(element, { change: this._action.bind(this) });
            },
            _action: function (e) {
                this.toolbar.action({
                    command: 'BorderChangeCommand',
                    options: {
                        border: e.type,
                        style: {
                            size: 1,
                            color: e.color
                        }
                    }
                });
            }
        });
        var BorderChangeButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({ name: 'borders' });
            }
        });
        kendo.toolbar.registerComponent('borders', BorderChangeTool, BorderChangeButton);
        var AlignmentTool = PopupTool.extend({
            init: function (options, toolbar) {
                PopupTool.fn.init.call(this, options, toolbar);
                this.element.attr({ 'data-property': 'alignment' });
                this._defineButtons();
                this._commandPalette();
                this.popup.element.on('click', '.k-button', function (e) {
                    this._action($(e.currentTarget));
                }.bind(this));
                this.element.data({
                    type: 'alignment',
                    alignment: this,
                    instance: this
                });
            },
            _defineButtons: function () {
                this.buttons = [
                    {
                        property: 'textAlign',
                        value: 'left',
                        iconClass: 'align-left',
                        text: MESSAGES.alignmentButtons.justtifyLeft
                    },
                    {
                        property: 'textAlign',
                        value: 'center',
                        iconClass: 'align-center',
                        text: MESSAGES.alignmentButtons.justifyCenter
                    },
                    {
                        property: 'textAlign',
                        value: 'right',
                        iconClass: 'align-right',
                        text: MESSAGES.alignmentButtons.justifyRight
                    },
                    {
                        property: 'textAlign',
                        value: 'justify',
                        iconClass: 'align-justify',
                        text: MESSAGES.alignmentButtons.justifyFull
                    },
                    {
                        property: 'verticalAlign',
                        value: 'top',
                        iconClass: 'align-top',
                        text: MESSAGES.alignmentButtons.alignTop
                    },
                    {
                        property: 'verticalAlign',
                        value: 'center',
                        iconClass: 'align-middle',
                        text: MESSAGES.alignmentButtons.alignMiddle
                    },
                    {
                        property: 'verticalAlign',
                        value: 'bottom',
                        iconClass: 'align-bottom',
                        text: MESSAGES.alignmentButtons.alignBottom
                    }
                ];
            },
            destroy: function () {
                this.popup.element.off();
                PopupTool.fn.destroy.call(this);
            },
            update: function (range) {
                var textAlign = range.textAlign();
                var verticalAlign = range.verticalAlign();
                var element = this.popup.element;
                element.find('.k-button').removeClass('k-state-active');
                if (textAlign) {
                    element.find('[data-property=textAlign][data-value=' + textAlign + ']').addClass('k-state-active');
                }
                if (verticalAlign) {
                    element.find('[data-property=verticalAlign][data-value=' + verticalAlign + ']').addClass('k-state-active');
                }
            },
            _commandPalette: function () {
                var buttons = this.buttons;
                var element = $('<div />').appendTo(this.popup.element);
                buttons.forEach(function (options, index) {
                    var button = '<a title=\'' + options.text + '\' data-property=\'' + options.property + '\' data-value=\'' + options.value + '\' class=\'k-button k-button-icon\'>' + '<span class=\'k-icon k-i-' + options.iconClass + '\'></span>' + '</a>';
                    if (index !== 0 && buttons[index - 1].property !== options.property) {
                        element.append($('<span class=\'k-separator\' />'));
                    }
                    element.append(button);
                });
            },
            _action: function (button) {
                var property = button.attr('data-property');
                var value = button.attr('data-value');
                this.toolbar.action({
                    command: 'PropertyChangeCommand',
                    options: {
                        property: property,
                        value: value
                    }
                });
            }
        });
        var AlignmentButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({ name: 'alignment' });
            }
        });
        kendo.toolbar.registerComponent('alignment', AlignmentTool, AlignmentButton);
        var MergeTool = PopupTool.extend({
            init: function (options, toolbar) {
                PopupTool.fn.init.call(this, options, toolbar);
                this._defineButtons();
                this._commandPalette();
                this.popup.element.on('click', '.k-button', function (e) {
                    this._action($(e.currentTarget));
                }.bind(this));
                this.element.data({
                    type: 'merge',
                    merge: this,
                    instance: this
                });
            },
            _defineButtons: function () {
                this.buttons = [
                    {
                        value: 'cells',
                        iconClass: 'cells-merge',
                        text: MESSAGES.mergeButtons.mergeCells
                    },
                    {
                        value: 'horizontally',
                        iconClass: 'cells-merge-horizontally',
                        text: MESSAGES.mergeButtons.mergeHorizontally
                    },
                    {
                        value: 'vertically',
                        iconClass: 'cells-merge-vertically',
                        text: MESSAGES.mergeButtons.mergeVertically
                    },
                    {
                        value: 'unmerge',
                        iconClass: 'table-unmerge',
                        text: MESSAGES.mergeButtons.unmerge
                    }
                ];
            },
            destroy: function () {
                this.popup.element.off();
                PopupTool.fn.destroy.call(this);
            },
            _commandPalette: function () {
                var element = $('<div />').appendTo(this.popup.element);
                this.buttons.forEach(function (options) {
                    var button = '<a title=\'' + options.text + '\' data-value=\'' + options.value + '\' class=\'k-button k-button-icontext\'>' + '<span class=\'k-icon k-i-' + options.iconClass + '\'></span>' + options.text + '</a>';
                    element.append(button);
                });
            },
            _action: function (button) {
                var value = button.attr('data-value');
                this.toolbar.action({
                    command: 'MergeCellCommand',
                    options: { value: value }
                });
            }
        });
        var MergeButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({ name: 'merge' });
            }
        });
        kendo.toolbar.registerComponent('merge', MergeTool, MergeButton);
        var FreezeTool = PopupTool.extend({
            init: function (options, toolbar) {
                PopupTool.fn.init.call(this, options, toolbar);
                this._defineButtons();
                this._commandPalette();
                this.popup.element.on('click', '.k-button', function (e) {
                    this._action($(e.currentTarget));
                }.bind(this));
                this.element.data({
                    type: 'freeze',
                    freeze: this,
                    instance: this
                });
            },
            _defineButtons: function () {
                this.buttons = [
                    {
                        value: 'panes',
                        iconClass: 'pane-freeze',
                        text: MESSAGES.freezeButtons.freezePanes
                    },
                    {
                        value: 'rows',
                        iconClass: 'row-freeze',
                        text: MESSAGES.freezeButtons.freezeRows
                    },
                    {
                        value: 'columns',
                        iconClass: 'column-freeze',
                        text: MESSAGES.freezeButtons.freezeColumns
                    },
                    {
                        value: 'unfreeze',
                        iconClass: 'table-unmerge',
                        text: MESSAGES.freezeButtons.unfreeze
                    }
                ];
            },
            destroy: function () {
                this.popup.element.off();
                PopupTool.fn.destroy.call(this);
            },
            _commandPalette: function () {
                var element = $('<div />').appendTo(this.popup.element);
                this.buttons.forEach(function (options) {
                    var button = '<a title=\'' + options.text + '\' data-value=\'' + options.value + '\' class=\'k-button k-button-icontext\'>' + '<span class=\'k-icon k-i-' + options.iconClass + '\'></span>' + options.text + '</a>';
                    element.append(button);
                });
            },
            _action: function (button) {
                var value = button.attr('data-value');
                this.toolbar.action({
                    command: 'FreezePanesCommand',
                    options: { value: value }
                });
            }
        });
        var FreezeButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({ name: 'freeze' });
            }
        });
        kendo.toolbar.registerComponent('freeze', FreezeTool, FreezeButton);
        var Sort = DropDownTool.extend({
            _revertTitle: function (e) {
                e.sender.value('');
                e.sender.wrapper.width('auto');
            },
            init: function (options, toolbar) {
                DropDownTool.fn.init.call(this, options, toolbar);
                var ddl = this.dropDownList;
                ddl.bind('change', this._revertTitle.bind(this));
                ddl.bind('dataBound', this._revertTitle.bind(this));
                ddl.setOptions({
                    valueTemplate: '<span class=\'k-icon k-i-' + options.iconClass + '\' style=\'line-height: 1em; width: 1.35em;\'></span>',
                    template: '<span class=\'k-icon k-i-#= iconClass #\' style=\'line-height: 1em; width: 1.35em;\'></span>#=text#',
                    dataTextField: 'text',
                    dataValueField: 'value'
                });
                ddl.setDataSource([
                    {
                        value: 'asc',
                        sheet: false,
                        text: MESSAGES.sortButtons.sortRangeAsc,
                        iconClass: 'sort-asc'
                    },
                    {
                        value: 'desc',
                        sheet: false,
                        text: MESSAGES.sortButtons.sortRangeDesc,
                        iconClass: 'sort-desc'
                    }
                ]);
                ddl.select(0);
                this.element.data({
                    type: 'sort',
                    sort: this
                });
            },
            _change: function (e) {
                var instance = e.sender;
                var dataItem = instance.dataItem();
                if (dataItem) {
                    this.toolbar.action({
                        command: 'SortCommand',
                        options: {
                            value: dataItem.value,
                            sheet: dataItem.sheet
                        }
                    });
                }
            },
            value: $.noop
        });
        var SortButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({ name: 'sort' });
            }
        });
        kendo.toolbar.registerComponent('sort', Sort, SortButton);
        var Filter = kendo.toolbar.ToolBarButton.extend({
            init: function (options, toolbar) {
                options.showText = 'overflow';
                kendo.toolbar.ToolBarButton.fn.init.call(this, options, toolbar);
                this.element.on('click', this._click.bind(this));
                this.element.data({
                    type: 'filter',
                    filter: this
                });
            },
            _click: function () {
                this.toolbar.action({ command: 'FilterCommand' });
            },
            update: function (value) {
                this.toggle(value);
            }
        });
        var FilterButton = OverflowDialogButton.extend({
            init: function (options, toolbar) {
                OverflowDialogButton.fn.init.call(this, options, toolbar);
                this.element.data({
                    type: 'filter',
                    filter: this
                });
            },
            _click: function () {
                this.toolbar.action({ command: 'FilterCommand' });
            },
            update: function (value) {
                this.toggle(value);
            }
        });
        kendo.toolbar.registerComponent('filter', Filter, FilterButton);
        var Open = kendo.toolbar.Item.extend({
            init: function (options, toolbar) {
                this.toolbar = toolbar;
                this.element = $('<div class=\'k-button k-upload-button k-button-icon\'>' + '<span class=\'k-icon k-i-folder-open\' />' + '</div>').data('instance', this);
                this._title = options.attributes.title;
                this._reset();
            },
            _reset: function () {
                this.element.find('input').remove();
                $('<input type=\'file\' autocomplete=\'off\' accept=\'.xlsx\'/>').attr('title', this._title).attr('aria-label', this._title).one('change', this._change.bind(this)).appendTo(this.element);
            },
            _change: function (e) {
                this.toolbar.action({
                    command: 'OpenCommand',
                    options: { file: e.target.files[0] }
                });
                this._reset();
            }
        });
        kendo.toolbar.registerComponent('open', Open);
        kendo.spreadsheet.TabStrip = kendo.ui.TabStrip.extend({
            init: function (element, options) {
                kendo.ui.TabStrip.fn.init.call(this, element, options);
                element.addClass('k-spreadsheet-tabstrip');
                this._quickAccessButtons();
                this.toolbars = {};
                var tabs = options.dataSource;
                this.contentElements.each(function (idx, element) {
                    this._toolbar($(element), tabs[idx].id, options.toolbarOptions[tabs[idx].id]);
                }.bind(this));
                this.one('activate', function () {
                    this.toolbars[this.options.dataSource[0].id].resize();
                });
            },
            events: kendo.ui.TabStrip.fn.events.concat([
                'action',
                'dialog'
            ]),
            destroy: function () {
                this.quickAccessToolBar.off('click');
                kendo.ui.TabStrip.fn.destroy.call(this);
                for (var name in this.toolbars) {
                    this.toolbars[name].destroy();
                }
            },
            action: function (args) {
                this.trigger('action', args);
            },
            dialog: function (args) {
                this.trigger('dialog', args);
            },
            refreshTools: function (range) {
                var toolbars = this.toolbars;
                for (var name in toolbars) {
                    if (toolbars.hasOwnProperty(name)) {
                        toolbars[name].refresh(range);
                    }
                }
            },
            _quickAccessButtons: function () {
                var buttons = [
                    {
                        title: MESSAGES.quickAccess.undo,
                        iconClass: 'undo',
                        action: 'undo'
                    },
                    {
                        title: MESSAGES.quickAccess.redo,
                        iconClass: 'redo',
                        action: 'redo'
                    }
                ];
                var buttonTemplate = kendo.template('<a href=\'\\#\' title=\'#= title #\' data-action=\'#= action #\' class=\'k-button k-button-icon\' aria-label=\'#= title #\'><span class=\'k-icon k-i-#=iconClass#\'></span></a>');
                this.quickAccessToolBar = $('<div />', {
                    'class': 'k-spreadsheet-quick-access-toolbar',
                    'html': kendo.render(buttonTemplate, buttons)
                }).insertBefore(this.wrapper);
                this.quickAccessToolBar.on('click', '.k-button', function (e) {
                    e.preventDefault();
                    var action = $(e.currentTarget).attr('data-action');
                    this.action({ action: action });
                }.bind(this));
                this.quickAccessAdjust();
            },
            quickAccessAdjust: function () {
                this.tabGroup.css('padding-left', kendo._outerWidth(this.quickAccessToolBar));
            },
            _toolbar: function (container, name, tools) {
                var element;
                var options;
                if (this.toolbars[name]) {
                    this.toolbars[name].destroy();
                    container.children('.k-toolbar').remove();
                }
                if (tools) {
                    element = container.html('<div />').children('div');
                    options = {
                        tools: typeof tools === 'boolean' ? undefined : tools,
                        toolbarName: name,
                        action: this.action.bind(this),
                        dialog: this.dialog.bind(this)
                    };
                    this.toolbars[name] = new kendo.spreadsheet.ToolBar(element, options);
                }
            }
        });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/dialogs', [
        'kendo.core',
        'kendo.binder',
        'kendo.validator'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var ObservableObject = kendo.data.ObservableObject;
        var MESSAGES = kendo.spreadsheet.messages.dialogs = {
            apply: 'Apply',
            save: 'Save',
            cancel: 'Cancel',
            remove: 'Remove',
            retry: 'Retry',
            revert: 'Revert',
            okText: 'OK',
            formatCellsDialog: {
                title: 'Format',
                categories: {
                    number: 'Number',
                    currency: 'Currency',
                    date: 'Date'
                }
            },
            fontFamilyDialog: { title: 'Font' },
            fontSizeDialog: { title: 'Font size' },
            bordersDialog: { title: 'Borders' },
            alignmentDialog: {
                title: 'Alignment',
                buttons: {
                    justtifyLeft: 'Align left',
                    justifyCenter: 'Center',
                    justifyRight: 'Align right',
                    justifyFull: 'Justify',
                    alignTop: 'Align top',
                    alignMiddle: 'Align middle',
                    alignBottom: 'Align bottom'
                }
            },
            mergeDialog: {
                title: 'Merge cells',
                buttons: {
                    mergeCells: 'Merge all',
                    mergeHorizontally: 'Merge horizontally',
                    mergeVertically: 'Merge vertically',
                    unmerge: 'Unmerge'
                }
            },
            freezeDialog: {
                title: 'Freeze panes',
                buttons: {
                    freezePanes: 'Freeze panes',
                    freezeRows: 'Freeze rows',
                    freezeColumns: 'Freeze columns',
                    unfreeze: 'Unfreeze panes'
                }
            },
            confirmationDialog: {
                text: 'Are you sure you want to remove this sheet?',
                title: 'Sheet remove'
            },
            validationDialog: {
                title: 'Data Validation',
                hintMessage: 'Please enter a valid {0} value {1}.',
                hintTitle: 'Validation {0}',
                criteria: {
                    any: 'Any value',
                    number: 'Number',
                    text: 'Text',
                    date: 'Date',
                    custom: 'Custom Formula',
                    list: 'List'
                },
                comparers: {
                    greaterThan: 'greater than',
                    lessThan: 'less than',
                    between: 'between',
                    notBetween: 'not between',
                    equalTo: 'equal to',
                    notEqualTo: 'not equal to',
                    greaterThanOrEqualTo: 'greater than or equal to',
                    lessThanOrEqualTo: 'less than or equal to'
                },
                comparerMessages: {
                    greaterThan: 'greater than {0}',
                    lessThan: 'less than {0}',
                    between: 'between {0} and {1}',
                    notBetween: 'not between {0} and {1}',
                    equalTo: 'equal to {0}',
                    notEqualTo: 'not equal to {0}',
                    greaterThanOrEqualTo: 'greater than or equal to {0}',
                    lessThanOrEqualTo: 'less than or equal to {0}',
                    custom: 'that satisfies the formula: {0}'
                },
                labels: {
                    criteria: 'Criteria',
                    comparer: 'Comparer',
                    min: 'Min',
                    max: 'Max',
                    value: 'Value',
                    start: 'Start',
                    end: 'End',
                    onInvalidData: 'On invalid data',
                    rejectInput: 'Reject input',
                    showWarning: 'Show warning',
                    showHint: 'Show hint',
                    hintTitle: 'Hint title',
                    hintMessage: 'Hint message',
                    ignoreBlank: 'Ignore blank',
                    showListButton: 'Display button to show list',
                    showCalendarButton: 'Display button to show calendar'
                },
                placeholders: {
                    typeTitle: 'Type title',
                    typeMessage: 'Type message'
                }
            },
            exportAsDialog: {
                title: 'Export...',
                defaultFileName: 'Workbook',
                xlsx: { description: 'Excel Workbook (.xlsx)' },
                pdf: {
                    description: 'Portable Document Format (.pdf)',
                    area: {
                        workbook: 'Entire Workbook',
                        sheet: 'Active Sheet',
                        selection: 'Selection'
                    },
                    paper: {
                        a2: 'A2 (420 mm \xD7 594 mm)',
                        a3: 'A3 (297 mm x 420 mm)',
                        a4: 'A4 (210 mm x 297 mm)',
                        a5: 'A5 (148 mm x 210 mm)',
                        b3: 'B3 (353 mm \xD7 500 mm)',
                        b4: 'B4 (250 mm x 353 mm)',
                        b5: 'B5 (176 mm x 250 mm)',
                        folio: 'Folio (8.5" x 13")',
                        legal: 'Legal (8.5" x 14")',
                        letter: 'Letter (8.5" x 11")',
                        tabloid: 'Tabloid (11" x 17")',
                        executive: 'Executive (7.25" x 10.5")'
                    },
                    margin: {
                        normal: 'Normal',
                        narrow: 'Narrow',
                        wide: 'Wide'
                    }
                },
                labels: {
                    scale: 'Scale',
                    fit: 'Fit to page',
                    fileName: 'File name',
                    saveAsType: 'Save as type',
                    exportArea: 'Export',
                    paperSize: 'Paper size',
                    margins: 'Margins',
                    orientation: 'Orientation',
                    print: 'Print',
                    guidelines: 'Guidelines',
                    center: 'Center',
                    horizontally: 'Horizontally',
                    vertically: 'Vertically'
                }
            },
            modifyMergedDialog: { errorMessage: 'Cannot change part of a merged cell.' },
            rangeDisabledDialog: { errorMessage: 'Destination range contains disabled cells.' },
            intersectsArrayDialog: { errorMessage: 'You cannot alter part of an array' },
            incompatibleRangesDialog: { errorMessage: 'Incompatible ranges' },
            noFillDirectionDialog: { errorMessage: 'Cannot determine fill direction' },
            duplicateSheetNameDialog: { errorMessage: 'Duplicate sheet name' },
            overflowDialog: { errorMessage: 'Cannot paste, because the copy area and the paste area are not the same size and shape.' },
            useKeyboardDialog: {
                title: 'Copying and pasting',
                errorMessage: 'These actions cannot be invoked through the menu. Please use the keyboard shortcuts instead:',
                labels: {
                    forCopy: 'for copy',
                    forCut: 'for cut',
                    forPaste: 'for paste'
                }
            },
            unsupportedSelectionDialog: { errorMessage: 'That action cannot be performed on multiple selection.' },
            linkDialog: {
                title: 'Hyperlink',
                labels: {
                    text: 'Text',
                    url: 'Address',
                    removeLink: 'Remove link'
                }
            },
            insertCommentDialog: {
                title: 'Insert comment',
                labels: {
                    comment: 'Comment',
                    removeComment: 'Remove comment'
                }
            },
            insertImageDialog: {
                title: 'Insert image',
                info: 'Drag an image here, or click to select',
                typeError: 'Please select a JPEG, PNG or GIF image'
            }
        };
        var registry = {};
        kendo.spreadsheet.dialogs = {
            register: function (name, dialogClass) {
                registry[name] = dialogClass;
            },
            registered: function (name) {
                return !!registry[name];
            },
            create: function (name, options) {
                var dialogClass = registry[name];
                if (dialogClass) {
                    return new dialogClass(options);
                }
            }
        };
        var SpreadsheetDialog = kendo.spreadsheet.SpreadsheetDialog = kendo.Observable.extend({
            init: function (options) {
                kendo.Observable.fn.init.call(this, options);
                this.options = translate($.extend(true, {}, this.options, options));
                this.bind(this.events, options);
            },
            events: [
                'close',
                'activate'
            ],
            options: { autoFocus: true },
            dialog: function () {
                if (!this._dialog) {
                    var options = {
                        autoFocus: false,
                        scrollable: false,
                        resizable: false,
                        modal: true,
                        visible: false,
                        width: this.options.width || 320,
                        title: this.options.title,
                        open: function () {
                            this.center();
                        },
                        close: this._onDialogClose.bind(this),
                        activate: this._onDialogActivate.bind(this),
                        deactivate: this._onDialogDeactivate.bind(this)
                    };
                    this._dialog = $('<div class=\'k-spreadsheet-window k-action-window k-popup-edit-form\' />').addClass(this.options.className || '').append(kendo.template(this.options.template)({
                        messages: kendo.spreadsheet.messages.dialogs || MESSAGES,
                        errors: this.options.errors
                    })).kendoWindow(options).data('kendoWindow');
                }
                return this._dialog;
            },
            _onDialogClose: function () {
                this.trigger('close', { action: this._action });
            },
            _onDialogActivate: function () {
                this.trigger('activate');
            },
            _onDialogDeactivate: function () {
                this.trigger('deactivate');
                this.destroy();
            },
            destroy: function () {
                if (this._dialog) {
                    this._dialog.destroy();
                    this._dialog = null;
                }
            },
            open: function () {
                this.dialog().open();
                this.dialog().element.find('.k-primary').focus();
            },
            apply: function () {
                this.close();
            },
            close: function () {
                this._action = 'close';
                this.dialog().close();
            }
        });
        function formattedValue(value, format) {
            return kendo.spreadsheet.formatting.text(value, format);
        }
        var FormatCellsViewModel = kendo.spreadsheet.FormatCellsViewModel = ObservableObject.extend({
            init: function (options) {
                ObservableObject.fn.init.call(this, options);
                this.useCategory(this.category);
            },
            useCategory: function (category) {
                var type = category && category.type || 'number';
                var formatCurrency = type == 'currency';
                this.category = category;
                this.set('showCurrencyFilter', formatCurrency && this.currencies.length > 1);
                if (!formatCurrency) {
                    this.set('formats', this.allFormats[type + 'Formats']);
                } else {
                    this.currency(this.currencies[0]);
                }
                this.useFirstFormat();
            },
            useFirstFormat: function () {
                if (this.formats.length) {
                    this.set('format', this.formats[0].value);
                }
            },
            currency: function (currency) {
                if (currency !== undefined) {
                    this._currency = currency;
                    var info = currency.value;
                    var formats = [
                        {
                            currency: info,
                            decimals: true
                        },
                        {
                            currency: info,
                            decimals: true,
                            iso: true
                        },
                        {
                            currency: info,
                            decimals: false
                        }
                    ];
                    formats = formats.map(function (format) {
                        format = FormatCellsViewModel.convert.currency(format);
                        return {
                            value: format,
                            name: formattedValue(1000, format)
                        };
                    });
                    this.set('formats', formats);
                    this.useFirstFormat();
                }
                return this._currency || this.currencies[0];
            },
            categoryFilter: function (category) {
                if (category !== undefined) {
                    this.useCategory(category);
                }
                return this.category;
            },
            preview: function () {
                var format = this.get('format');
                var value = this.value || 0;
                if (format && format.length) {
                    return formattedValue(value, format);
                } else {
                    return value;
                }
            }
        });
        FormatCellsViewModel.convert = {
            currency: function (options) {
                function repeat(token, n) {
                    return new Array(n + 1).join(token);
                }
                var info = options.currency;
                var format = info.pattern[1];
                if (options.decimals) {
                    format = format.replace(/n/g, 'n' + info['.'] + repeat('0', info.decimals));
                }
                if (options.iso) {
                    format = '"' + info.abbr + '" ' + format.replace(/\s*\$\s*/g, '');
                } else {
                    format = format.replace(/\$/g, JSON.stringify(info.symbol));
                }
                format = format.replace(/n/g, '?');
                return format;
            },
            date: function (format) {
                if (/T|Z/.test(format)) {
                    return '';
                }
                return format.toLowerCase().replace(/tt/g, 'AM/PM').replace(/'/g, '"');
            }
        };
        function uniqueBy(field, array) {
            var result = [];
            var values = [];
            for (var i = 0; i < array.length; i++) {
                if ($.inArray(array[i][field], values) == -1) {
                    result.push(array[i]);
                    values.push(array[i][field]);
                }
            }
            return result;
        }
        var FormatCellsDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.formatCellsDialog || MESSAGES;
                var defaultOptions = {
                    title: messages.title,
                    categories: [
                        {
                            type: 'number',
                            name: messages.categories.number
                        },
                        {
                            type: 'currency',
                            name: messages.categories.currency
                        },
                        {
                            type: 'date',
                            name: messages.categories.date
                        }
                    ]
                };
                SpreadsheetDialog.fn.init.call(this, $.extend(defaultOptions, options));
                this._generateFormats();
            },
            options: {
                className: 'k-spreadsheet-format-cells',
                template: '<div class=\'k-edit-form-container\'>' + '<div class=\'k-root-tabs\' data-role=\'tabstrip\' ' + 'data-text-field=\'name\' ' + 'data-bind=\'source: categories, value: categoryFilter\' ' + 'data-animation=\'false\' />' + '<div class=\'k-spreadsheet-preview\' data-bind=\'text: preview\' />' + '<script type=\'text/x-kendo-template\' id=\'format-item-template\'>' + '\\#: data.name \\#' + '</script>' + '<select data-role=\'dropdownlist\' class=\'k-format-filter\' ' + 'data-text-field=\'description\' ' + 'data-value-field=\'value.name\' ' + 'data-bind=\'visible: showCurrencyFilter, value: currency, source: currencies\' />' + '<ul data-role=\'staticlist\' tabindex=\'0\' ' + 'class=\'k-list k-reset\' ' + 'data-template=\'format-item-template\' ' + 'data-value-primitive=\'true\' ' + 'data-value-field=\'value\' ' + 'data-bind=\'source: formats, value: format\' />' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: apply\'>#: messages.apply #</button>' + '<button class=\'k-button\' data-bind=\'click: close\'>#: messages.cancel #</button>' + '</div>' + '</div>'
            },
            _generateFormats: function () {
                var options = this.options;
                if (!options.currencies) {
                    options.currencies = FormatCellsDialog.currenciesFrom(kendo.cultures);
                }
                if (!options.numberFormats) {
                    options.numberFormats = [
                        {
                            value: '#.00%',
                            name: '100.00%'
                        },
                        {
                            value: '#%',
                            name: '100%'
                        },
                        {
                            value: '#.00',
                            name: '1024.00'
                        },
                        {
                            value: '#,###.00',
                            name: '1,024.00'
                        }
                    ];
                }
                if (!options.dateFormats) {
                    var calendarPatterns = kendo.cultures.current.calendars.standard.patterns;
                    options.dateFormats = uniqueBy('value', $.map(calendarPatterns, function (format) {
                        format = FormatCellsViewModel.convert.date(format);
                        if (!format) {
                            return;
                        }
                        return {
                            value: format,
                            name: formattedValue(34567.7678, format)
                        };
                    }));
                }
            },
            open: function (range) {
                var options = this.options;
                var value = range.value();
                var categories = options.categories.slice(0);
                var element;
                this.viewModel = new FormatCellsViewModel({
                    currencies: options.currencies.slice(0),
                    allFormats: {
                        numberFormats: options.numberFormats.slice(0),
                        dateFormats: options.dateFormats.slice(0)
                    },
                    categories: categories,
                    format: range.format(),
                    category: value instanceof Date ? categories[2] : categories[0],
                    apply: this.apply.bind(this),
                    close: this.close.bind(this),
                    value: value
                });
                SpreadsheetDialog.fn.open.call(this);
                element = this.dialog().element;
                kendo.bind(element, this.viewModel);
                var currencyFilter = element.find('select.k-format-filter').data('kendoDropDownList');
                if (options.currencies.length > 10) {
                    currencyFilter.setOptions({ filter: 'contains' });
                }
                element.find(kendo.roleSelector('staticlist')).parent().addClass('k-list-wrapper');
            },
            apply: function () {
                var format = this.viewModel.format;
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'PropertyChangeCommand',
                    options: {
                        property: 'format',
                        value: format
                    }
                });
            }
        });
        FormatCellsDialog.currenciesFrom = function (cultures) {
            return uniqueBy('description', $.map(cultures, function (culture, name) {
                if (!/-/.test(name)) {
                    return;
                }
                var currency = culture.numberFormat.currency;
                var description = kendo.format('{0} ({1}, {2})', currency.name, currency.abbr, currency.symbol);
                return {
                    description: description,
                    value: currency
                };
            }));
        };
        kendo.spreadsheet.dialogs.register('formatCells', FormatCellsDialog);
        kendo.spreadsheet.dialogs.FormatCellsDialog = FormatCellsDialog;
        var MessageDialog = SpreadsheetDialog.extend({
            options: {
                className: 'k-spreadsheet-message',
                title: '',
                messageId: '',
                text: '',
                template: '<div class=\'k-spreadsheet-message-content\' data-bind=\'text: text\' />' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: close\'>' + '#= messages.okText #' + '</button>' + '</div>'
            },
            open: function () {
                SpreadsheetDialog.fn.open.call(this);
                var options = this.options;
                var text = options.text;
                if (options.messageId) {
                    text = kendo.getter(options.messageId, true)(kendo.spreadsheet.messages.dialogs);
                }
                kendo.bind(this.dialog().element, {
                    text: text,
                    close: this.close.bind(this)
                });
            }
        });
        kendo.spreadsheet.dialogs.register('message', MessageDialog);
        var ConfirmationDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.confirmationDialog || MESSAGES;
                var defaultOptions = {
                    title: messages.title,
                    text: messages.text
                };
                SpreadsheetDialog.fn.init.call(this, $.extend(defaultOptions, options));
            },
            options: {
                className: 'k-spreadsheet-message',
                messageId: '',
                template: '<div class=\'k-spreadsheet-message-content\' data-bind=\'text: text\' />' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: confirm\'>' + '#= messages.okText #' + '</button>' + '<button class=\'k-button\' data-bind=\'click: cancel\'>' + '#= messages.cancel #' + '</button>' + '</div>'
            },
            open: function () {
                SpreadsheetDialog.fn.open.call(this);
                var options = this.options;
                var text = options.text;
                if (options.messageId) {
                    text = kendo.getter(options.messageId, true)(kendo.spreadsheet.messages.dialogs);
                }
                kendo.bind(this.dialog().element, {
                    text: text,
                    confirm: this.confirm.bind(this),
                    cancel: this.close.bind(this)
                });
            },
            isConfirmed: function () {
                return this._confirmed;
            },
            confirm: function () {
                this._confirmed = true;
                this.close();
            }
        });
        kendo.spreadsheet.dialogs.register('confirmation', ConfirmationDialog);
        var ValidationErrorDialog = SpreadsheetDialog.extend({
            options: {
                className: 'k-spreadsheet-message',
                title: '',
                messageId: '',
                text: '',
                template: '<div class=\'k-spreadsheet-message-content\' data-bind=\'text: text\' />' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: retry\'>' + '#= messages.retry #' + '</button>' + '<button class=\'k-button\' data-bind=\'click: cancel\'>' + '#= messages.cancel #' + '</button>' + '</div>'
            },
            open: function () {
                SpreadsheetDialog.fn.open.call(this);
                var options = this.options;
                var text = options.text;
                if (options.messageId) {
                    text = kendo.getter(options.messageId, true)(kendo.spreadsheet.messages.dialogs);
                }
                kendo.bind(this.dialog().element, {
                    text: text,
                    retry: this.retry.bind(this),
                    cancel: this.close.bind(this)
                });
            },
            retry: function () {
                this._retry = true;
                this.close();
            }
        });
        kendo.spreadsheet.dialogs.register('validationError', ValidationErrorDialog);
        var FontFamilyDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.fontFamilyDialog || MESSAGES;
                SpreadsheetDialog.fn.init.call(this, $.extend({ title: messages.title }, options));
                this._list();
            },
            options: { template: '<ul class=\'k-list k-reset\'></ul>' },
            _list: function () {
                var ul = this.dialog().element.find('ul');
                var fonts = this.options.fonts;
                var defaultFont = this.options.defaultFont;
                this.list = new kendo.ui.StaticList(ul, {
                    dataSource: new kendo.data.DataSource({ data: fonts }),
                    template: '#: data #',
                    value: defaultFont,
                    change: this.apply.bind(this)
                });
                this.list.dataSource.fetch();
            },
            apply: function (e) {
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'PropertyChangeCommand',
                    options: {
                        property: 'fontFamily',
                        value: e.sender.value()[0]
                    }
                });
            }
        });
        kendo.spreadsheet.dialogs.register('fontFamily', FontFamilyDialog);
        var FontSizeDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.fontSizeDialog || MESSAGES;
                SpreadsheetDialog.fn.init.call(this, $.extend({ title: messages.title }, options));
                this._list();
            },
            options: { template: '<ul class=\'k-list k-reset\'></ul>' },
            _list: function () {
                var ul = this.dialog().element.find('ul');
                var sizes = this.options.sizes;
                var defaultSize = this.options.defaultSize;
                this.list = new kendo.ui.StaticList(ul, {
                    dataSource: new kendo.data.DataSource({ data: sizes }),
                    template: '#: data #',
                    value: defaultSize,
                    change: this.apply.bind(this)
                });
                this.list.dataSource.fetch();
            },
            apply: function (e) {
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'PropertyChangeCommand',
                    options: {
                        property: 'fontSize',
                        value: kendo.parseInt(e.sender.value()[0])
                    }
                });
            }
        });
        kendo.spreadsheet.dialogs.register('fontSize', FontSizeDialog);
        var BordersDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.bordersDialog || MESSAGES;
                SpreadsheetDialog.fn.init.call(this, $.extend({ title: messages.title }, options));
                this.element = this.dialog().element;
                this._borderPalette();
                this.viewModel = kendo.observable({
                    apply: this.apply.bind(this),
                    close: this.close.bind(this)
                });
                kendo.bind(this.element.find('.k-action-buttons'), this.viewModel);
            },
            options: {
                width: 177,
                template: '<div></div>' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: apply\'>#: messages.apply #</button>' + '<button class=\'k-button\' data-bind=\'click: close\'>#: messages.cancel #</button>' + '</div>'
            },
            apply: function () {
                SpreadsheetDialog.fn.apply.call(this);
                var state = this.value();
                this.trigger('action', {
                    command: 'BorderChangeCommand',
                    options: {
                        border: state.type,
                        style: {
                            size: 1,
                            color: state.color
                        }
                    }
                });
            },
            _borderPalette: function () {
                var element = this.dialog().element.find('div:first');
                this.borderPalette = new kendo.spreadsheet.BorderPalette(element, { change: this.value.bind(this) });
            },
            value: function (state) {
                if (state === undefined) {
                    return this._state;
                } else {
                    this._state = state;
                }
            }
        });
        kendo.spreadsheet.dialogs.register('borders', BordersDialog);
        var ColorChooser = SpreadsheetDialog.extend({
            init: function (options) {
                SpreadsheetDialog.fn.init.call(this, options);
                this.element = this.dialog().element;
                this.property = options.property;
                this.options.title = options.title;
                this.viewModel = kendo.observable({
                    apply: this.apply.bind(this),
                    close: this.close.bind(this)
                });
                kendo.bind(this.element.find('.k-action-buttons'), this.viewModel);
            },
            options: { template: '<div></div>' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: apply\'>#: messages.apply #</button>' + '<button class=\'k-button\' data-bind=\'click: close\'>#: messages.cancel #</button>' + '</div>' },
            apply: function () {
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'PropertyChangeCommand',
                    options: {
                        property: this.property,
                        value: this.value()
                    }
                });
            },
            value: function (e) {
                if (e === undefined) {
                    return this._value;
                } else {
                    this._value = e.value;
                }
            }
        });
        var ColorPickerDialog = ColorChooser.extend({
            init: function (options) {
                options.width = 177;
                ColorChooser.fn.init.call(this, options);
                this._colorPalette();
            },
            _colorPalette: function () {
                var element = this.dialog().element.find('div:first');
                this.colorPalette = element.kendoColorPalette({
                    palette: [
                        '#ffffff',
                        '#000000',
                        '#d6ecff',
                        '#4e5b6f',
                        '#7fd13b',
                        '#ea157a',
                        '#feb80a',
                        '#00addc',
                        '#738ac8',
                        '#1ab39f',
                        '#f2f2f2',
                        '#7f7f7f',
                        '#a7d6ff',
                        '#d9dde4',
                        '#e5f5d7',
                        '#fad0e4',
                        '#fef0cd',
                        '#c5f2ff',
                        '#e2e7f4',
                        '#c9f7f1',
                        '#d8d8d8',
                        '#595959',
                        '#60b5ff',
                        '#b3bcca',
                        '#cbecb0',
                        '#f6a1c9',
                        '#fee29c',
                        '#8be6ff',
                        '#c7d0e9',
                        '#94efe3',
                        '#bfbfbf',
                        '#3f3f3f',
                        '#007dea',
                        '#8d9baf',
                        '#b2e389',
                        '#f272af',
                        '#fed46b',
                        '#51d9ff',
                        '#aab8de',
                        '#5fe7d5',
                        '#a5a5a5',
                        '#262626',
                        '#003e75',
                        '#3a4453',
                        '#5ea226',
                        '#af0f5b',
                        '#c58c00',
                        '#0081a5',
                        '#425ea9',
                        '#138677',
                        '#7f7f7f',
                        '#0c0c0c',
                        '#00192e',
                        '#272d37',
                        '#3f6c19',
                        '#750a3d',
                        '#835d00',
                        '#00566e',
                        '#2c3f71',
                        '#0c594f'
                    ],
                    change: this.value.bind(this)
                }).data('kendoColorPalette');
            }
        });
        kendo.spreadsheet.dialogs.register('colorPicker', ColorPickerDialog);
        var CustomColorDialog = ColorChooser.extend({
            init: function (options) {
                options.width = 268;
                ColorChooser.fn.init.call(this, options);
                this.dialog().setOptions({ animation: false });
                this.dialog().one('activate', this._colorPicker.bind(this));
            },
            _colorPicker: function () {
                var element = this.dialog().element.find('div:first');
                this.colorPicker = element.kendoFlatColorPicker({ change: this.value.bind(this) }).data('kendoFlatColorPicker');
            }
        });
        kendo.spreadsheet.dialogs.register('customColor', CustomColorDialog);
        var AlignmentDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.alignmentDialog || MESSAGES;
                var defaultOptions = {
                    title: messages.title,
                    buttons: [
                        {
                            property: 'textAlign',
                            value: 'left',
                            iconClass: 'align-left',
                            text: messages.buttons.justtifyLeft
                        },
                        {
                            property: 'textAlign',
                            value: 'center',
                            iconClass: 'align-center',
                            text: messages.buttons.justifyCenter
                        },
                        {
                            property: 'textAlign',
                            value: 'right',
                            iconClass: 'align-right',
                            text: messages.buttons.justifyRight
                        },
                        {
                            property: 'textAlign',
                            value: 'justify',
                            iconClass: 'align-justify',
                            text: messages.buttons.justifyFull
                        },
                        {
                            property: 'verticalAlign',
                            value: 'top',
                            iconClass: 'align-top',
                            text: messages.buttons.alignTop
                        },
                        {
                            property: 'verticalAlign',
                            value: 'center',
                            iconClass: 'align-middle',
                            text: messages.buttons.alignMiddle
                        },
                        {
                            property: 'verticalAlign',
                            value: 'bottom',
                            iconClass: 'align-bottom',
                            text: messages.buttons.alignBottom
                        }
                    ]
                };
                SpreadsheetDialog.fn.init.call(this, $.extend(defaultOptions, options));
                this._list();
            },
            options: { template: '<ul class=\'k-list k-reset\'></ul>' },
            _list: function () {
                var ul = this.dialog().element.find('ul');
                this.list = new kendo.ui.StaticList(ul, {
                    dataSource: new kendo.data.DataSource({ data: this.options.buttons }),
                    template: '<a title=\'#=text#\' data-property=\'#=property#\' data-value=\'#=value#\'>' + '<span class=\'k-icon k-i-#=iconClass#\'></span>' + '#=text#' + '</a>',
                    change: this.apply.bind(this)
                });
                this.list.dataSource.fetch();
            },
            apply: function (e) {
                var dataItem = e.sender.value()[0];
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'PropertyChangeCommand',
                    options: {
                        property: dataItem.property,
                        value: dataItem.value
                    }
                });
            }
        });
        kendo.spreadsheet.dialogs.register('alignment', AlignmentDialog);
        var MergeDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.mergeDialog || MESSAGES;
                var defaultOptions = {
                    title: messages.title,
                    buttons: [
                        {
                            value: 'cells',
                            iconClass: 'cells-merge',
                            text: messages.buttons.mergeCells
                        },
                        {
                            value: 'horizontally',
                            iconClass: 'cells-merge-horizontally',
                            text: messages.buttons.mergeHorizontally
                        },
                        {
                            value: 'vertically',
                            iconClass: 'cells-merge-vertically',
                            text: messages.buttons.mergeVertically
                        },
                        {
                            value: 'unmerge',
                            iconClass: 'table-unmerge',
                            text: messages.buttons.unmerge
                        }
                    ]
                };
                SpreadsheetDialog.fn.init.call(this, $.extend(defaultOptions, options));
                this._list();
            },
            options: { template: '<ul class=\'k-list k-reset\'></ul>' },
            _list: function () {
                var ul = this.dialog().element.find('ul');
                this.list = new kendo.ui.StaticList(ul, {
                    dataSource: new kendo.data.DataSource({ data: this.options.buttons }),
                    template: '<a title=\'#=text#\' data-value=\'#=value#\'>' + '<span class=\'k-icon k-icon k-i-#=iconClass#\'></span>#=text#' + '</a>',
                    change: this.apply.bind(this)
                });
                this.list.dataSource.fetch();
            },
            apply: function (e) {
                var dataItem = e.sender.value()[0];
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'MergeCellCommand',
                    options: { value: dataItem.value }
                });
            }
        });
        kendo.spreadsheet.dialogs.register('merge', MergeDialog);
        var FreezeDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.freezeDialog || MESSAGES;
                var defaultOptions = {
                    title: messages.title,
                    buttons: [
                        {
                            value: 'panes',
                            iconClass: 'pane-freeze',
                            text: messages.buttons.freezePanes
                        },
                        {
                            value: 'rows',
                            iconClass: 'row-freeze',
                            text: messages.buttons.freezeRows
                        },
                        {
                            value: 'columns',
                            iconClass: 'column-freeze',
                            text: messages.buttons.freezeColumns
                        },
                        {
                            value: 'unfreeze',
                            iconClass: 'table-unmerge',
                            text: messages.buttons.unfreeze
                        }
                    ]
                };
                SpreadsheetDialog.fn.init.call(this, $.extend(defaultOptions, options));
                this._list();
            },
            options: { template: '<ul class=\'k-list k-reset\'></ul>' },
            _list: function () {
                var ul = this.dialog().element.find('ul');
                this.list = new kendo.ui.StaticList(ul, {
                    dataSource: new kendo.data.DataSource({ data: this.options.buttons }),
                    template: '<a title=\'#=text#\' data-value=\'#=value#\'>' + '<span class=\'k-icon k-icon k-i-#=iconClass#\'></span>#=text#' + '</a>',
                    change: this.apply.bind(this)
                });
                this.list.dataSource.fetch();
            },
            apply: function (e) {
                var dataItem = e.sender.value()[0];
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'FreezePanesCommand',
                    options: { value: dataItem.value }
                });
            }
        });
        kendo.spreadsheet.dialogs.register('freeze', FreezeDialog);
        var ValidationViewModel = kendo.spreadsheet.ValidationCellsViewModel = ObservableObject.extend({
            init: function (options) {
                ObservableObject.fn.init.call(this, options);
                this.bind('change', function (e) {
                    if (e.field === 'criterion') {
                        this.reset();
                        if (this.criterion === 'custom' || this.criterion === 'list') {
                            this.setHintMessageTemplate();
                        }
                    }
                    if (e.field === 'comparer') {
                        this.setHintMessageTemplate();
                    }
                    if ((e.field == 'hintMessage' || e.field == 'hintTitle') && !this._mute) {
                        this.shouldBuild = false;
                    }
                    if ((e.field == 'from' || e.field == 'to' || e.field == 'hintMessageTemplate' || e.field == 'type') && this.shouldBuild) {
                        this.buildMessages();
                    }
                }.bind(this));
                this.reset();
            },
            buildMessages: function () {
                this._mute = true;
                this.set('hintTitle', this.hintTitleTemplate ? kendo.format(this.hintTitleTemplate, this.type) : '');
                this.set('hintMessage', this.hintMessageTemplate ? kendo.format(this.hintMessageTemplate, this.from, this.to) : '');
                this._mute = false;
            },
            reset: function () {
                this.setComparers();
                this.set('comparer', this.comparers[0].type);
                this.set('from', null);
                this.set('to', null);
                this.set('useCustomMessages', false);
                this.shouldBuild = true;
                this.hintTitleTemplate = this.defaultHintTitle;
                this.buildMessages();
            },
            setComparers: function () {
                var all = this.defaultComparers;
                var comparers = [];
                if (this.criterion === 'text') {
                    var text_comparers = [
                        'equalTo',
                        'notEqualTo'
                    ];
                    for (var idx = 0; idx < all.length; idx++) {
                        if (text_comparers[0] == all[idx].type) {
                            comparers.push(all[idx]);
                            text_comparers.shift();
                        }
                    }
                } else {
                    comparers = all.slice();
                }
                this.set('comparers', comparers);
            },
            setHintMessageTemplate: function () {
                if (this.criterion !== 'custom' && this.criterion !== 'list') {
                    this.set('hintMessageTemplate', kendo.format(this.defaultHintMessage, this.criterion, this.comparerMessages[this.comparer]));
                } else {
                    this.set('hintMessageTemplate', '');
                    this.set('hintMessage', '');
                }
            },
            isAny: function () {
                return this.get('criterion') === 'any';
            },
            isNumber: function () {
                return this.get('criterion') === 'number';
            },
            showToForNumber: function () {
                return this.showTo() && this.isNumber();
            },
            showToForDate: function () {
                return this.showTo() && this.isDate();
            },
            isText: function () {
                return this.get('criterion') === 'text';
            },
            isDate: function () {
                return this.get('criterion') === 'date';
            },
            isList: function () {
                return this.get('criterion') === 'list';
            },
            isCustom: function () {
                return this.get('criterion') === 'custom';
            },
            showRemove: function () {
                return this.get('hasValidation');
            },
            showTo: function () {
                return this.get('comparer') == 'between' || this.get('comparer') == 'notBetween';
            },
            update: function (validation) {
                this.set('hasValidation', !!validation);
                if (validation) {
                    this.fromValidationObject(validation);
                }
            },
            fromValidationObject: function (validation) {
                this.set('criterion', validation.dataType);
                this.set('comparer', validation.comparerType);
                this.set('from', validation.from);
                this.set('to', validation.to);
                this.set('type', validation.type);
                this.set('ignoreBlank', validation.allowNulls);
                this.set('showButton', validation.showButton);
                if (validation.messageTemplate || validation.titleTemplate) {
                    this.hintMessageTemplate = validation.messageTemplate;
                    this.hintMessage = validation.messageTemplate;
                    this.hintTitleTemplate = validation.titleTemplate;
                    this.hintTitle = validation.titleTemplate;
                    this.useCustomMessages = true;
                    this.buildMessages();
                } else {
                    this.useCustomMessages = false;
                }
            },
            toValidationObject: function () {
                if (this.criterion === 'any') {
                    return null;
                }
                var options = {
                    type: this.type,
                    dataType: this.criterion,
                    comparerType: this.comparer,
                    from: this.from,
                    to: this.to,
                    allowNulls: this.ignoreBlank,
                    showButton: this.showButton
                };
                if (this.useCustomMessages) {
                    options.messageTemplate = this.shouldBuild ? this.hintMessageTemplate : this.hintMessage;
                    options.titleTemplate = this.hintTitle;
                }
                return options;
            }
        });
        var ValidationDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.validationDialog || MESSAGES;
                var defaultOptions = {
                    title: messages.title,
                    hintMessage: messages.hintMessage,
                    hintTitle: messages.hintTitle,
                    criteria: [
                        {
                            type: 'any',
                            name: messages.criteria.any
                        },
                        {
                            type: 'number',
                            name: messages.criteria.number
                        },
                        {
                            type: 'text',
                            name: messages.criteria.text
                        },
                        {
                            type: 'date',
                            name: messages.criteria.date
                        },
                        {
                            type: 'custom',
                            name: messages.criteria.custom
                        },
                        {
                            type: 'list',
                            name: messages.criteria.list
                        }
                    ],
                    comparers: [
                        {
                            type: 'greaterThan',
                            name: messages.comparers.greaterThan
                        },
                        {
                            type: 'lessThan',
                            name: messages.comparers.lessThan
                        },
                        {
                            type: 'between',
                            name: messages.comparers.between
                        },
                        {
                            type: 'notBetween',
                            name: messages.comparers.notBetween
                        },
                        {
                            type: 'equalTo',
                            name: messages.comparers.equalTo
                        },
                        {
                            type: 'notEqualTo',
                            name: messages.comparers.notEqualTo
                        },
                        {
                            type: 'greaterThanOrEqualTo',
                            name: messages.comparers.greaterThanOrEqualTo
                        },
                        {
                            type: 'lessThanOrEqualTo',
                            name: messages.comparers.lessThanOrEqualTo
                        }
                    ],
                    comparerMessages: messages.comparerMessages
                };
                SpreadsheetDialog.fn.init.call(this, $.extend(defaultOptions, options));
            },
            options: {
                width: 450,
                criterion: 'any',
                type: 'reject',
                ignoreBlank: true,
                showButton: true,
                useCustomMessages: false,
                errorTemplate: '<div class="k-widget k-tooltip k-tooltip-validation" style="margin:0.5em"><span class="k-icon k-i-warning"> </span>' + '#= message #<div class="k-callout k-callout-n"></div></div>',
                template: '<div class="k-edit-form-container">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.criteria #:</label></div>' + '<div class="k-edit-field">' + '<select data-role="dropdownlist" ' + 'title="#: messages.validationDialog.labels.criteria #"' + 'data-text-field="name" ' + 'data-value-field="type" ' + 'data-bind="value: criterion, source: criteria" />' + '</div>' + '<div data-bind="visible: isNumber">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.comparer #:</label></div>' + '<div class="k-edit-field">' + '<select data-role="dropdownlist" ' + 'title="#: messages.validationDialog.labels.comparer #"' + 'data-text-field="name" ' + 'data-value-field="type" ' + 'data-bind="value: comparer, source: comparers" />' + '</div>' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.min #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.min #" title="#: messages.validationDialog.labels.min #" placeholder="e.g. 10" class="k-textbox" data-bind="value: from, enabled: isNumber" required="required" />' + '</div>' + '<div data-bind="visible: showTo">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.max #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.max #" title="#: messages.validationDialog.labels.max #" placeholder="e.g. 100" class="k-textbox" data-bind="value: to, enabled: showToForNumber" required="required" />' + '</div>' + '</div>' + '</div>' + '<div data-bind="visible: isText">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.comparer #:</label></div>' + '<div class="k-edit-field">' + '<select data-role="dropdownlist" ' + 'title="#: messages.validationDialog.labels.comparer #"' + 'data-text-field="name" ' + 'data-value-field="type" ' + 'data-bind="value: comparer, source: comparers" />' + '</div>' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.value #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.value #" title="#: messages.validationDialog.labels.value #" class="k-textbox" data-bind="value: from, enabled: isText" required="required" />' + '</div>' + '</div>' + '<div data-bind="visible: isDate">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.comparer #:</label></div>' + '<div class="k-edit-field">' + '<select data-role="dropdownlist" ' + 'title="#: messages.validationDialog.labels.comparer #"' + 'data-text-field="name" ' + 'data-value-field="type" ' + 'data-bind="value: comparer, source: comparers" />' + '</div>' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.start #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.start #" title="#: messages.validationDialog.labels.start #" class="k-textbox" data-bind="value: from, enabled: isDate" required="required" />' + '</div>' + '<div data-bind="visible: showTo">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.end #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.end #" title="#: messages.validationDialog.labels.end #" class="k-textbox" data-bind="value: to, enabled: showToForDate" required="required" />' + '</div>' + '</div>' + '</div>' + '<div data-bind="visible: isCustom">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.value #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.value #" title="#: messages.validationDialog.labels.value #" class="k-textbox" data-bind="value: from, enabled: isCustom" required="required" />' + '</div>' + '</div>' + '<div data-bind="visible: isList">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.value #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.value #" title="#: messages.validationDialog.labels.value #" class="k-textbox" data-bind="value: from, enabled: isList" required="required" />' + '</div>' + '</div>' + '<div data-bind="visible: isList">' + '<div class="k-edit-field">' + '<input type="checkbox" name="showButton" id="listShowButton" class="k-checkbox" data-bind="checked: showButton"/>' + '<label for="listShowButton" class="k-checkbox-label">' + ' #: messages.validationDialog.labels.showListButton #' + '</label>' + '</div>' + '</div>' + '<div data-bind="visible: isDate">' + '<div class="k-edit-field">' + '<input type="checkbox" name="showButton" id="dateShowButton" class="k-checkbox" data-bind="checked: showButton"/>' + '<label for="dateShowButton" class="k-checkbox-label">' + ' #: messages.validationDialog.labels.showCalendarButton #' + '</label>' + '</div>' + '</div>' + '<div data-bind="invisible: isAny">' + '<div class="k-edit-field">' + '<input type="checkbox" title="#: messages.validationDialog.labels.ignoreBlank #" name="ignoreBlank" id="ignoreBlank" class="k-checkbox" data-bind="checked: ignoreBlank"/>' + '<label for="ignoreBlank" class="k-checkbox-label">' + ' #: messages.validationDialog.labels.ignoreBlank #' + '</label>' + '</div>' + '</div>' + '<div data-bind="invisible: isAny">' + '<div class="k-hr"></div>' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.onInvalidData #:</label></div>' + '<div class="k-edit-field">' + '<input type="radio" title="#: messages.validationDialog.labels.rejectInput #" id="validationTypeReject" name="validationType" value="reject" data-bind="checked: type" class="k-radio" />' + '<label for="validationTypeReject" class="k-radio-label">' + '#: messages.validationDialog.labels.rejectInput #' + '</label> ' + '<input type="radio" title="#: messages.validationDialog.labels.showWarning #" id="validationTypeWarning"  name="validationType" value="warning" data-bind="checked: type" class="k-radio" />' + '<label for="validationTypeWarning" class="k-radio-label">' + '#: messages.validationDialog.labels.showWarning #' + '</label>' + '</div>' + '</div>' + '<div data-bind="invisible: isAny" class="hint-wrapper">' + '<div class="k-edit-field">' + '<input type="checkbox" title="#: messages.validationDialog.labels.showHint #" name="useCustomMessages" id="useCustomMessages" class="k-checkbox" data-bind="checked: useCustomMessages" />' + '<label class="k-checkbox-label" for="useCustomMessages">' + ' #: messages.validationDialog.labels.showHint #' + '</label>' + '</div>' + '<div data-bind="visible: useCustomMessages">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.hintTitle #:</label></div>' + '<div class="k-edit-field">' + '<input class="k-textbox" title="#: messages.validationDialog.labels.hintTitle #" placeholder="#: messages.validationDialog.placeholders.typeTitle #" data-bind="value: hintTitle" />' + '</div>' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.hintMessage #:</label></div>' + '<div class="k-edit-field">' + '<input class="k-textbox" title="#: messages.validationDialog.labels.hintMessage #" placeholder="#: messages.validationDialog.placeholders.typeMessage #" data-bind="value: hintMessage" />' + '</div>' + '</div>' + '</div>' + '<div class="k-action-buttons">' + '<button class="k-button" data-bind="visible: showRemove, click: remove">#: messages.remove #</button>' + '<button class="k-button k-primary" data-bind="click: apply">#: messages.apply #</button>' + '<button class="k-button" data-bind="click: close">#: messages.cancel #</button>' + '</div>' + '</div>'
            },
            open: function (range) {
                var options = this.options;
                var element;
                this.viewModel = new ValidationViewModel({
                    type: options.type,
                    defaultHintMessage: options.hintMessage,
                    defaultHintTitle: options.hintTitle,
                    defaultComparers: options.comparers.slice(0),
                    comparerMessages: options.comparerMessages,
                    criteria: options.criteria.slice(0),
                    criterion: options.criterion,
                    ignoreBlank: options.ignoreBlank,
                    showButton: options.showButton,
                    apply: this.apply.bind(this),
                    close: this.close.bind(this),
                    remove: this.remove.bind(this)
                });
                this.viewModel.update(range.validation());
                SpreadsheetDialog.fn.open.call(this);
                element = this.dialog().element;
                if (this.validatable) {
                    this.validatable.destroy();
                }
                kendo.bind(element, this.viewModel);
                this.validatable = new kendo.ui.Validator(element.find('.k-edit-form-container'), {
                    validateOnBlur: false,
                    errorTemplate: this.options.errorTemplate || undefined
                });
            },
            apply: function () {
                if (this.validatable.validate()) {
                    SpreadsheetDialog.fn.apply.call(this);
                    this.trigger('action', {
                        command: 'EditValidationCommand',
                        options: { value: this.viewModel.toValidationObject() }
                    });
                }
            },
            remove: function () {
                this.viewModel.set('criterion', 'any');
                this.apply();
            }
        });
        kendo.spreadsheet.dialogs.register('validation', ValidationDialog);
        kendo.spreadsheet.dialogs.ValidationDialog = ValidationDialog;
        function PDF_PAPER_SIZE(size) {
            return {
                value: size,
                text: TEXT('exportAsDialog.pdf.paper.' + size)
            };
        }
        var ExportAsDialog = SpreadsheetDialog.extend({
            init: function (options) {
                SpreadsheetDialog.fn.init.call(this, options);
                options = this.options;
                this.viewModel = kendo.observable({
                    title: options.title,
                    name: options.name,
                    extension: options.extension,
                    fileFormats: options.fileFormats,
                    excel: options.excelExport,
                    pdf: {
                        proxyURL: options.pdfExport.proxyURL,
                        forceProxy: options.pdfExport.forceProxy,
                        title: options.pdfExport.title,
                        author: options.pdfExport.author,
                        subject: options.pdfExport.subject,
                        keywords: options.pdfExport.keywords,
                        creator: options.pdfExport.creator,
                        date: options.pdfExport.date,
                        fitWidth: options.pdf.fitWidth,
                        area: options.pdf.area,
                        areas: options.pdf.areas,
                        paperSize: options.pdf.paperSize,
                        paperSizes: options.pdf.paperSizes,
                        margin: options.pdf.margin,
                        margins: options.pdf.margins,
                        landscape: options.pdf.landscape,
                        guidelines: options.pdf.guidelines,
                        hCenter: options.pdf.hCenter,
                        vCenter: options.pdf.vCenter
                    },
                    apply: this.apply.bind(this),
                    close: this.close.bind(this)
                });
                var dialog = this.dialog();
                this.viewModel.bind('change', function (e) {
                    if (e.field === 'extension') {
                        this.set('showPdfOptions', this.extension === '.pdf' ? true : false);
                        dialog.center();
                    }
                });
                kendo.bind(dialog.element, this.viewModel);
            },
            options: {
                title: TEXT('exportAsDialog.title', 'Export...'),
                name: TEXT('exportAsDialog.defaultFileName', 'Workbook'),
                extension: '.xlsx',
                fileFormats: [
                    {
                        description: TEXT('exportAsDialog.xlsx.description', 'Excel Workbook (.xlsx)'),
                        extension: '.xlsx'
                    },
                    {
                        description: TEXT('exportAsDialog.pdf.description', 'Portable Document Format (.pdf)'),
                        extension: '.pdf'
                    }
                ],
                pdf: {
                    fitWidth: true,
                    area: 'workbook',
                    areas: [
                        {
                            area: 'workbook',
                            text: TEXT('exportAsDialog.pdf.area.workbook', 'Entire Workbook')
                        },
                        {
                            area: 'sheet',
                            text: TEXT('exportAsDialog.pdf.area.sheet', 'Active Sheet')
                        },
                        {
                            area: 'selection',
                            text: TEXT('exportAsDialog.pdf.area.selection', 'Selection')
                        }
                    ],
                    paperSize: 'a4',
                    paperSizes: [
                        'a2',
                        'a3',
                        'a4',
                        'a5',
                        'b3',
                        'b4',
                        'b5',
                        'folio',
                        'legal',
                        'letter',
                        'tabloid',
                        'executive'
                    ].map(PDF_PAPER_SIZE),
                    margin: {
                        bottom: '0.75in',
                        left: '0.7in',
                        right: '0.7in',
                        top: '0.75in'
                    },
                    margins: [
                        {
                            value: {
                                bottom: '0.75in',
                                left: '0.7in',
                                right: '0.7in',
                                top: '0.75in'
                            },
                            text: TEXT('exportAsDialog.pdf.margin.normal', 'Normal')
                        },
                        {
                            value: {
                                bottom: '0.75in',
                                left: '0.25in',
                                right: '0.25in',
                                top: '0.75in'
                            },
                            text: TEXT('exportAsDialog.pdf.margin.narrow', 'Narrow')
                        },
                        {
                            value: {
                                bottom: '1in',
                                left: '1in',
                                right: '1in',
                                top: '1in'
                            },
                            text: TEXT('exportAsDialog.pdf.margin.wide', 'Wide')
                        }
                    ],
                    landscape: true,
                    guidelines: true,
                    hCenter: true,
                    vCenter: true
                },
                width: 520,
                template: '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.fileName #:</label></div>' + '<div class=\'k-edit-field\'>' + '<input class=\'k-textbox\' data-bind=\'value: name\' />' + '</div>' + '<div >' + '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.saveAsType #:</label></div>' + '<div class=\'k-edit-field\'>' + '<select data-role=\'dropdownlist\' class=\'k-file-format\' ' + 'data-text-field=\'description\' ' + 'data-value-field=\'extension\' ' + 'data-bind=\'value: extension, source: fileFormats\' />' + '</div>' + '</div>' + '<div class=\'k-export-config\' data-bind=\'visible: showPdfOptions\'>' + '<hr class=\'k-hr\' />' + '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.exportArea #:</label></div>' + '<div class=\'k-edit-field\'>' + '<select data-role=\'dropdownlist\' class=\'k-file-format\' ' + 'data-text-field=\'text\' ' + 'data-value-field=\'area\' ' + 'data-bind=\'value: pdf.area, source: pdf.areas\' />' + '</div>' + '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.paperSize#:</label></div>' + '<div class=\'k-edit-field\'>' + '<select data-role=\'dropdownlist\' class=\'k-file-format\' ' + 'data-text-field=\'text\' ' + 'data-value-field=\'value\' ' + 'data-bind=\'value: pdf.paperSize, source: pdf.paperSizes\' />' + '</div>' + '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.margins #:</label></div>' + '<div class=\'k-edit-field\'>' + '<select data-role=\'dropdownlist\' class=\'k-file-format\' ' + 'data-value-primitive=\'true\'' + 'data-text-field=\'text\' ' + 'data-value-field=\'value\' ' + 'data-bind=\'value: pdf.margin, source: pdf.margins\' />' + '</div>' + '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.orientation #:</label></div>' + '<div class=\'k-edit-field\'>' + '<div class=\'k-button-group\'>' + '<input type=\'radio\' id=\'k-orientation-portrait\' name=\'orientation\' data-type=\'boolean\' data-bind=\'checked: pdf.landscape\' value=\'false\' />' + '<label class=\'k-button k-button-icon k-group-start k-orientation-button\' for=\'k-orientation-portrait\'><span class=\'k-icon k-i-page-portrait\'></span></label>' + '<input type=\'radio\' id=\'k-orientation-landscape\' name=\'orientation\' data-type=\'boolean\' data-bind=\'checked: pdf.landscape\' value=\'true\' />' + '<label class=\'k-button k-button-icon k-group-end k-orientation-button\' for=\'k-orientation-landscape\'><span class=\'k-icon k-i-page-landscape\'></span></label>' + '</div>' + '</div>' + '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.print #:</label></div>' + '<div class=\'k-edit-field\'>' + '<input class=\'k-checkbox\' id=\'guidelines\' type=\'checkbox\' data-bind=\'checked: pdf.guidelines\'/><label class=\'k-checkbox-label\' for=\'guidelines\'>#: messages.exportAsDialog.labels.guidelines#</label>' + '</div>' + '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.scale #:</label></div>' + '<div class=\'k-edit-field\'>' + '<input class=\'k-checkbox\' id=\'fitWidth\' type=\'checkbox\' data-bind=\'checked: pdf.fitWidth\'/><label class=\'k-checkbox-label\' for=\'fitWidth\'>#: messages.exportAsDialog.labels.fit #</label>' + '</div>' + '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.center #:</label></div>' + '<div class=\'k-edit-field\'>' + '<input class=\'k-checkbox\' id=\'hCenter\' type=\'checkbox\' data-bind=\'checked: pdf.hCenter\'/><label class=\'k-checkbox-label\' for=\'hCenter\'>#: messages.exportAsDialog.labels.horizontally #</label>' + '<input class=\'k-checkbox\' id=\'vCenter\' type=\'checkbox\' data-bind=\'checked: pdf.vCenter\'/><label class=\'k-checkbox-label\' for=\'vCenter\'>#: messages.exportAsDialog.labels.vertically #</label>' + '</div>' + '<div class=\'k-page-orientation\'>' + '<span class=\'k-icon k-i-page-portrait\' data-bind=\'invisible: pdf.landscape\'></span>' + '<span class=\'k-icon k-i-page-landscape\' data-bind=\'visible: pdf.landscape\'></span>' + '</div>' + '</div>' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: apply\'>#: messages.save #</button>' + '<button class=\'k-button\' data-bind=\'click: close\'>#: messages.cancel #</button>' + '</div>'
            },
            apply: function () {
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'SaveAsCommand',
                    options: this.viewModel
                });
            }
        });
        kendo.spreadsheet.dialogs.register('exportAs', ExportAsDialog);
        function basicErrorDialog(id, msg) {
            kendo.spreadsheet.dialogs.register(id, MessageDialog.extend({ options: { messageId: msg } }));
        }
        basicErrorDialog('modifyMerged', 'modifyMergedDialog.errorMessage');
        basicErrorDialog('rangeDisabled', 'rangeDisabledDialog.errorMessage');
        basicErrorDialog('intersectsArray', 'intersectsArrayDialog.errorMessage');
        basicErrorDialog('overflow', 'overflowDialog.errorMessage');
        basicErrorDialog('unsupportedSelection', 'unsupportedSelectionDialog.errorMessage');
        basicErrorDialog('incompatibleRanges', 'incompatibleRangesDialog.errorMessage');
        basicErrorDialog('noFillDirection', 'noFillDirectionDialog.errorMessage');
        basicErrorDialog('duplicateSheetName', 'duplicateSheetNameDialog.errorMessage');
        var ImportErrorDialog = MessageDialog.extend({
            options: {
                width: 640,
                title: 'Errors in import',
                template: '<div class=\'k-spreadsheet-message-content k-spreadsheet-import-errors\'>' + '<div class=\'k--header-message\'>We encountered #= errors.length # errors while reading this file.  Please be aware that some formulas might be missing, or contain invalid results.</div>' + '<div class=\'k--errors\'>' + '<table>' + '<thead>' + '<tr><th>Context</th><th>Error message</th></tr>' + '</thead>' + '# for (var i = 0; i < errors.length; ++i) { #' + '# var err = errors[i]; #' + '<tr><td>#: err.context #</td><td>#: err.error #</td></tr>' + '# } #' + '</table>' + '</div>' + '</div>' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: close\'>' + '#: messages.okText #' + '</button>' + '</div>'
            }
        });
        kendo.spreadsheet.dialogs.register('importError', ImportErrorDialog);
        var UseKeyboardDialog = MessageDialog.extend({
            options: {
                title: TEXT('useKeyboardDialog.title', 'Copying and pasting'),
                template: '#: messages.useKeyboardDialog.errorMessage #' + '<div>Ctrl+C #: messages.useKeyboardDialog.labels.forCopy #</div>' + '<div>Ctrl+X #: messages.useKeyboardDialog.labels.forCut #</div>' + '<div>Ctrl+V #: messages.useKeyboardDialog.labels.forPaste #</div>' + '<div class="k-action-buttons">' + '<button class=\'k-button k-primary\' data-bind=\'click: close\'>' + '#= messages.okText #' + '</button>' + '</div>'
            }
        });
        kendo.spreadsheet.dialogs.register('useKeyboard', UseKeyboardDialog);
        var HyperlinkDialog = SpreadsheetDialog.extend({
            options: {
                title: TEXT('linkDialog.title', 'Hyperlink'),
                template: '<div class=\'k-edit-label\'><label>#: messages.linkDialog.labels.url #:</label></div>' + '<div class=\'k-edit-field\'><input class=\'k-textbox\' data-bind=\'value: url\' title=\'#: messages.linkDialog.labels.url #\' /></div>' + '<div class=\'k-action-buttons\'>' + ('<button class=\'k-button k-left\' data-bind=\'click: remove\'>#= messages.linkDialog.labels.removeLink #</button>' + '<button class=\'k-button k-primary\' data-bind=\'click: apply\'>#= messages.okText #</button>' + '<button class=\'k-button\' data-bind=\'click: cancel\'>#= messages.cancel #</button>') + '</div>',
                autoFocus: false
            },
            open: function (range) {
                var self = this;
                SpreadsheetDialog.fn.open.apply(self, arguments);
                var element = self.dialog().element;
                var model = kendo.observable({
                    url: range.link(),
                    apply: function () {
                        if (!/\S/.test(model.url)) {
                            model.url = null;
                        }
                        self.trigger('action', {
                            command: 'HyperlinkCommand',
                            options: { link: model.url }
                        });
                        self.close();
                    },
                    remove: function () {
                        model.url = null;
                        model.apply();
                    },
                    cancel: self.close.bind(self)
                });
                kendo.bind(element, model);
                element.find('input').focus().on('keydown', function (ev) {
                    if (ev.keyCode == 13) {
                        model.url = $(this).val();
                        ev.stopPropagation();
                        ev.preventDefault();
                        model.apply();
                    } else if (ev.keyCode == 27) {
                        ev.stopPropagation();
                        ev.preventDefault();
                        model.cancel();
                    }
                });
            }
        });
        kendo.spreadsheet.dialogs.register('hyperlink', HyperlinkDialog);
        var InsertCommentDialog = SpreadsheetDialog.extend({
            options: {
                className: 'k-spreadsheet-insert-comment',
                template: '<div class=\'k-edit-label\'><label>#: messages.insertCommentDialog.labels.comment #:</label></div><div class=\'k-edit-field\'><textarea rows=\'5\' class=\'k-textbox\' data-bind=\'value: comment\'></textarea></div><div class=\'k-action-buttons\'>  <button class=\'k-button k-left\' data-bind=\'click: remove\'>#: messages.insertCommentDialog.labels.removeComment #</button>  <button class=\'k-button k-primary\' data-bind=\'click: apply\'>#: messages.okText #</button>  <button class=\'k-button\' data-bind=\'click: cancel\'>#= messages.cancel #</button></div>',
                title: TEXT('insertCommentDialog.title', 'Insert comment'),
                autoFocus: false,
                width: 450
            },
            open: function (range) {
                var self = this;
                SpreadsheetDialog.fn.open.apply(self, arguments);
                var element = self.dialog().element;
                var model = kendo.observable({
                    comment: range.comment(),
                    apply: function () {
                        if (!/\S/.test(model.comment)) {
                            model.comment = null;
                        }
                        self.trigger('action', {
                            command: 'InsertCommentCommand',
                            options: { value: model.comment }
                        });
                        self.close();
                    },
                    remove: function () {
                        model.comment = null;
                        model.apply();
                    },
                    cancel: self.close.bind(self)
                });
                kendo.bind(element, model);
                element.find('textarea').focus();
            }
        });
        kendo.spreadsheet.dialogs.register('insertComment', InsertCommentDialog);
        var InsertImageDialog = SpreadsheetDialog.extend({
            options: {
                template: '<div class=\'k-spreadsheet-insert-image-dialog\'>  <label data-bind=\'style: { background-image: imageUrl },                    css: { k-spreadsheet-has-image: hasImage, k-state-hovered: isHovered },                    events: { dragenter: dragEnter, dragover: stopEvent, dragleave: dragLeave, drop: drop }\'>    <div data-bind=\'text: info\'></div>    <input type=\'file\' data-bind=\'events: { change: change }\'           accept=\'image/png, image/jpeg, image/gif\' />  </label></div><div class=\'k-action-buttons\'>  <button class=\'k-button k-primary\' data-bind=\'enabled: okEnabled, click: apply\'>#: messages.okText #</button>  <button class=\'k-button\' data-bind=\'click: cancel\'>#= messages.cancel #</button></div>',
                title: TEXT('insertImageDialog.title', 'Insert image'),
                width: 'auto'
            },
            open: function () {
                var self = this;
                SpreadsheetDialog.fn.open.apply(self, arguments);
                var element = self.dialog().element;
                var model = kendo.observable({
                    okEnabled: false,
                    info: kendo.spreadsheet.messages.dialogs.insertImageDialog.info,
                    imageUrl: '',
                    hasImage: false,
                    isHovered: false,
                    _url: null,
                    _image: null,
                    apply: function () {
                        window.URL.revokeObjectURL(model._url);
                        self.trigger('action', {
                            command: 'InsertImageCommand',
                            options: {
                                blob: model._image,
                                width: model._width,
                                height: model._height
                            }
                        });
                        self.close();
                    },
                    cancel: self.close.bind(self),
                    stopEvent: function (ev) {
                        ev.stopPropagation();
                        ev.preventDefault();
                    },
                    drop: function (ev) {
                        model.stopEvent(ev);
                        model.selectFile(ev.originalEvent.dataTransfer.files);
                        model.set('isHovered', false);
                    },
                    dragEnter: function (ev) {
                        model.stopEvent(ev);
                        model.set('isHovered', true);
                    },
                    dragLeave: function (ev) {
                        model.stopEvent(ev);
                        model.set('isHovered', false);
                    },
                    change: function (ev) {
                        model.selectFile(ev.target.files);
                    },
                    selectFile: function (files) {
                        var image;
                        for (var i = 0; i < files.length; ++i) {
                            if (/^image\//i.test(files[i].type)) {
                                image = files[i];
                                break;
                            }
                        }
                        if (model._url) {
                            window.URL.revokeObjectURL(model._url);
                        }
                        if (image) {
                            model._image = image;
                            model._url = window.URL.createObjectURL(image);
                            var img = new Image();
                            img.src = model._url;
                            img.onload = function () {
                                model._width = img.width;
                                model._height = img.height;
                                model.set('info', kendo.spreadsheet.messages.dialogs.insertImageDialog.info);
                                model.set('okEnabled', true);
                                model.set('imageUrl', 'url(\'' + model._url + '\')');
                                model.set('hasImage', true);
                            };
                        } else {
                            model._image = null;
                            model.set('info', kendo.spreadsheet.messages.dialogs.insertImageDialog.typeError);
                            model.set('okEnabled', false);
                            model.set('imageUrl', '');
                            model.set('hasImage', false);
                        }
                    }
                });
                kendo.bind(element, model);
            }
        });
        kendo.spreadsheet.dialogs.register('insertImage', InsertImageDialog);
        function Localizable(path, def) {
            this.path = path.split('.');
            this.def = def;
        }
        Localizable.prototype.trans = function () {
            var msg = kendo.spreadsheet.messages.dialogs;
            for (var i = 0; i < this.path.length; ++i) {
                msg = msg[this.path[i]];
                if (!msg) {
                    return this.def;
                }
            }
            return msg;
        };
        function TEXT(path, def) {
            return new Localizable(path, def);
        }
        function translate(thing) {
            if (thing instanceof Localizable) {
                return thing.trans();
            } else if (Array.isArray(thing)) {
                return thing.map(translate);
            } else if (thing != null && typeof thing == 'object') {
                return Object.keys(thing).reduce(function (ret, key) {
                    ret[key] = translate(thing[key]);
                    return ret;
                }, {});
            }
            return thing;
        }
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/sheetbinder', [
        'kendo.core',
        'kendo.data',
        'spreadsheet/sheet'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var identity = function (o) {
            return o;
        };
        var SheetDataSourceBinder = kendo.Class.extend({
            init: function (options) {
                this.options = kendo.jQuery.extend({}, this.options, options);
                this.columns = this._normalizeColumns(this.options.columns);
                this._sheet();
                this._dataSource();
                this._header();
                this._boundRowsCount = 0;
                this.dataSource.fetch();
            },
            _sheet: function () {
                this.sheet = this.options.sheet;
                this._sheetChangeHandler = this._sheetChange.bind(this);
                this._sheetDeleteRowHandler = this._sheetDeleteRow.bind(this);
                this._sheetInsertRowHandler = this._sheetInsertRow.bind(this);
                this.sheet.bind('change', this._sheetChangeHandler).bind('afterDeleteRow', this._sheetDeleteRowHandler).bind('afterInsertRow', this._sheetInsertRowHandler);
            },
            _sheetInsertRow: function (e) {
                if (e.index !== undefined) {
                    this.dataSource.insert(Math.max(e.index - 1, 0), {});
                }
            },
            _sheetDeleteRow: function (e) {
                if (e.index !== undefined) {
                    var dataSource = this.dataSource;
                    var model = dataSource.view()[e.index - 1];
                    if (model) {
                        dataSource.remove(model);
                    }
                }
            },
            _header: function () {
                this.sheet.batch(function () {
                    this.columns.forEach(function (column, index) {
                        this.sheet.range(0, index).value(column.title);
                    }.bind(this));
                }.bind(this));
            },
            _sheetChange: function (e) {
                if (e.insertRow || e.deleteRow) {
                    return;
                }
                if (e.recalc && e.ref) {
                    var dataSource = this.dataSource;
                    var data = dataSource.view();
                    var columns = this.columns;
                    var fields;
                    if (dataSource.reader.model) {
                        fields = dataSource.reader.model.fields;
                    }
                    if (!columns.length && data.length) {
                        columns = Object.keys(data[0].toJSON());
                    }
                    var getters = columns.map(function (column) {
                        var field = column.field;
                        if (field && fields && fields[field] && fields[field].type == 'date') {
                            return kendo.spreadsheet.numberToDate;
                        }
                        return identity;
                    });
                    this._skipRebind = true;
                    var normalizedRef = this.sheet._grid.normalize(e.ref);
                    var values = this.sheet.range(normalizedRef).values();
                    normalizedRef.forEach(function (ref) {
                        ref = ref.toRangeRef();
                        var record;
                        var valueIndex = 0;
                        for (var ri = ref.topLeft.row; ri <= ref.bottomRight.row; ri++) {
                            record = data[ri - 1];
                            if (!record) {
                                record = dataSource.insert(ri - 1, {});
                                data = dataSource.view();
                            }
                            var colValueIndex = 0;
                            for (var ci = ref.topLeft.col; ci <= ref.bottomRight.col && ci < columns.length; ci++) {
                                record.set(columns[ci].field, getters[ci](values[valueIndex][colValueIndex++]));
                            }
                            valueIndex++;
                        }
                    });
                    this._boundRowsCount = dataSource.view().length;
                    this._skipRebind = false;
                }
            },
            _normalizeColumns: function (columns) {
                return columns.map(function (column) {
                    var field = column.field || column;
                    return {
                        field: field,
                        title: column.title || field
                    };
                });
            },
            _dataSource: function () {
                var options = this.options;
                var dataSource = options.dataSource;
                dataSource = Array.isArray(dataSource) ? { data: dataSource } : dataSource;
                if (this.dataSource && this._changeHandler) {
                    this.dataSource.unbind('change', this._changeHandler);
                } else {
                    this._changeHandler = this._change.bind(this);
                }
                this.dataSource = kendo.data.DataSource.create(dataSource).bind('change', this._changeHandler);
            },
            _change: function () {
                if (this._skipRebind) {
                    return;
                }
                if (this.sheet.trigger('dataBinding')) {
                    return;
                }
                var data = this.dataSource.view();
                var columns = this.columns;
                if (!columns.length && data.length) {
                    this.columns = columns = this._normalizeColumns(Object.keys(data[0].toJSON()));
                    this._header();
                }
                var getters = columns.map(function (column) {
                    return kendo.getter(column.field);
                });
                this.sheet.batch(function () {
                    var length = Math.max(data.length, this._boundRowsCount);
                    for (var idx = 0; idx < length; idx++) {
                        for (var getterIdx = 0; getterIdx < getters.length; getterIdx++) {
                            var value = data[idx] ? getters[getterIdx](data[idx]) : null;
                            this.sheet.range(idx + 1, getterIdx).value(value);
                        }
                    }
                }.bind(this));
                this._boundRowsCount = data.length;
                this.sheet.trigger('dataBound');
            },
            destroy: function () {
                this.dataSource.unbind('change', this._changeHandler);
                this.sheet.unbind('change', this._sheetChangeHandler).unbind('deleteRow', this._sheetDeleteRowHandler).unbind('insertRow', this._sheetInsertRowHandler);
            },
            options: { columns: [] }
        });
        kendo.spreadsheet.SheetDataSourceBinder = SheetDataSourceBinder;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/filtermenu', [
        'kendo.core',
        'kendo.popup',
        'kendo.treeview',
        'kendo.numerictextbox',
        'kendo.datepicker',
        'kendo.datetimepicker'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var Widget = kendo.ui.Widget;
        var classNames = {
            details: 'k-details',
            button: 'k-button',
            detailsSummary: 'k-details-summary',
            detailsContent: 'k-details-content',
            icon: 'k-icon',
            iconCollapse: 'k-i-arrow-45-down-right',
            iconExpand: 'k-i-arrow-60-right',
            iconSearch: 'k-i-zoom',
            textbox: 'k-textbox',
            wrapper: 'k-spreadsheet-filter-menu',
            filterByCondition: 'k-spreadsheet-condition-filter',
            filterByValue: 'k-spreadsheet-value-filter',
            valuesTreeViewWrapper: 'k-spreadsheet-value-treeview-wrapper',
            actionButtons: 'k-action-buttons'
        };
        kendo.spreadsheet.messages.filterMenu = {
            all: 'All',
            sortAscending: 'Sort range A to Z',
            sortDescending: 'Sort range Z to A',
            filterByValue: 'Filter by value',
            filterByCondition: 'Filter by condition',
            apply: 'Apply',
            search: 'Search',
            addToCurrent: 'Add to current selection',
            clear: 'Clear',
            blanks: '(Blanks)',
            operatorNone: 'None',
            and: 'AND',
            or: 'OR',
            operators: {
                string: {
                    contains: 'Text contains',
                    doesnotcontain: 'Text does not contain',
                    startswith: 'Text starts with',
                    endswith: 'Text ends with',
                    matches: 'Text matches',
                    doesnotmatch: 'Text does not match'
                },
                date: {
                    eq: 'Date is',
                    neq: 'Date is not',
                    lt: 'Date is before',
                    gt: 'Date is after'
                },
                number: {
                    eq: 'Is equal to',
                    neq: 'Is not equal to',
                    gte: 'Is greater than or equal to',
                    gt: 'Is greater than',
                    lte: 'Is less than or equal to',
                    lt: 'Is less than'
                }
            }
        };
        var Details = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.element.addClass(FilterMenu.classNames.details);
                this._summary = this.element.find('.' + FilterMenu.classNames.detailsSummary).on('click', this._toggle.bind(this));
                var iconClass = options.expanded ? FilterMenu.classNames.iconCollapse : FilterMenu.classNames.iconExpand;
                this._icon = $('<span />', { 'class': FilterMenu.classNames.icon + ' ' + iconClass }).prependTo(this._summary);
                this._container = kendo.wrap(this._summary.next(), true);
                if (!options.expanded) {
                    this._container.hide();
                }
            },
            options: { name: 'Details' },
            events: ['toggle'],
            visible: function () {
                return this.options.expanded;
            },
            toggle: function (show) {
                var animation = kendo.fx(this._container).expand('vertical');
                animation.stop()[show ? 'reverse' : 'play']();
                this._icon.toggleClass(FilterMenu.classNames.iconExpand, show).toggleClass(FilterMenu.classNames.iconCollapse, !show);
                this.options.expanded = !show;
            },
            _toggle: function () {
                var show = this.visible();
                this.toggle(show);
                this.trigger('toggle', { show: show });
            }
        });
        kendo.data.binders.spreadsheetFilterValue = kendo.data.Binder.extend({
            init: function (element, bindings, options) {
                kendo.data.Binder.fn.init.call(this, element, bindings, options);
                this._change = $.proxy(this.change, this);
                $(this.element).on('change', this._change);
            },
            refresh: function () {
                var that = this, value = that.bindings.spreadsheetFilterValue.get();
                $(that.element).val(value instanceof Date ? '' : value);
            },
            change: function () {
                var value = this.element.value;
                this.bindings.spreadsheetFilterValue.set(value);
            }
        });
        kendo.data.binders.widget.spreadsheetFilterValue = kendo.data.Binder.extend({
            init: function (widget, bindings, options) {
                kendo.data.Binder.fn.init.call(this, widget.element[0], bindings, options);
                this.widget = widget;
                this._change = $.proxy(this.change, this);
                this.widget.first('change', this._change);
            },
            refresh: function () {
                var binding = this.bindings.spreadsheetFilterValue, value = binding.get(), type = $(this.widget.element).data('filterType');
                if (type === 'date' && value instanceof Date || type === 'number' && !isNaN(value)) {
                    this.widget.value(value);
                } else {
                    this.widget.value(null);
                }
            },
            change: function () {
                var value = this.widget.value(), binding = this.bindings.spreadsheetFilterValue;
                binding.set(value);
            }
        });
        var templates = {
            filterByValue: '<div class=\'' + classNames.detailsSummary + '\'>#= messages.filterByValue #</div>' + '<div class=\'' + classNames.detailsContent + '\'>' + '<div class=\'k-textbox k-space-right\'>' + '<input placeholder=\'#= messages.search #\' data-#=ns#bind=\'events: { input: filterValues }\' />' + '<span class=\'k-icon k-i-zoom\' />' + '</div>' + '<div data-#=ns#bind=\'visible: hasActiveSearch\'><input class=\'k-checkbox\' type=\'checkbox\' data-#=ns#bind=\'checked: appendToSearch\' id=\'_#=guid#\' /><label class=\'k-checkbox-label\' for=\'_#=guid#\'>#= messages.addToCurrent #</label></div>' + '<div class=\'' + classNames.valuesTreeViewWrapper + '\'>' + '<div data-#=ns#role=\'treeview\' ' + 'data-#=ns#checkboxes=\'{ checkChildren: true }\' ' + 'data-#=ns#bind=\'source: valuesDataSource, events: { check: valuesChange, select: valueSelect }\' ' + '/>' + '</div>' + '</div>',
            filterByCondition: '<div class=\'' + classNames.detailsSummary + '\'>#= messages.filterByCondition #</div>' + '<div class=\'' + classNames.detailsContent + '\'>' + '<div>' + '<select ' + 'data-#=ns#role="dropdownlist"' + 'data-#=ns#bind="value: operator, source: operators, events: { change: operatorChange } "' + 'data-value-primitive="false"' + 'data-option-label="#=messages.operatorNone#"' + 'data-height="auto"' + 'data-text-field="text"' + 'data-value-field="unique">' + '</select>' + '</div>' + '<div data-#=ns#bind="visible: isString">' + '<input data-filter-type="string" data-#=ns#bind="spreadsheetFilterValue: customFilter.criteria[0].value" class="k-textbox" />' + '</div>' + '<div data-#=ns#bind="visible: isNumber">' + '<input data-filter-type="number" data-#=ns#role="numerictextbox" data-#=ns#bind="spreadsheetFilterValue: customFilter.criteria[0].value" />' + '</div>' + '<div data-#=ns#bind="visible: isDate">' + '<input data-filter-type="date" data-#=ns#role="datepicker" data-#=ns#bind="spreadsheetFilterValue: customFilter.criteria[0].value" />' + '</div>' + '</div>',
            menuItem: '<li data-command=\'#=command#\' data-dir=\'#=dir#\'>' + '<span class=\'k-icon k-i-#=iconClass#\'></span>#=text#' + '</li>',
            actionButtons: '<button data-#=ns#bind=\'click: apply\' class=\'k-button k-primary\'>#=messages.apply#</button>' + '<button data-#=ns#bind=\'click: clear\' class=\'k-button\'>#=messages.clear#</button>'
        };
        function distinctValues(values) {
            var hash = {};
            var result = [];
            for (var i = 0; i < values.length; i++) {
                if (!hash[values[i].value]) {
                    hash[values[i].value] = values[i];
                    result.push(values[i]);
                } else if (!hash[values[i].value].checked && values[i].checked) {
                    hash[values[i].value].checked = true;
                }
            }
            return result;
        }
        function filter(dataSource, query) {
            var hasVisibleChildren = false;
            var data = dataSource instanceof kendo.data.HierarchicalDataSource && dataSource.data();
            var valuesFilter = this;
            var values = this.values;
            for (var i = 0; i < data.length; i++) {
                var item = data[i];
                var text = item.text.toString().toLowerCase();
                var itemVisible = query === true || query === '' || text.indexOf(query) >= 0;
                var filterSpread = filter.bind(valuesFilter);
                var anyVisibleChildren = filterSpread(item.children, query);
                hasVisibleChildren = hasVisibleChildren || anyVisibleChildren || itemVisible;
                item.hidden = !itemVisible && !anyVisibleChildren;
                if (query.length || values && !values.length) {
                    item.checked = !item.hidden;
                } else if (values && values.indexOf(item.text) != -1) {
                    item.checked = true;
                }
            }
            if (data) {
                dataSource.filter({
                    field: 'hidden',
                    operator: 'neq',
                    value: true
                });
            }
            return hasVisibleChildren;
        }
        function uncheckAll(dataSource) {
            var data = dataSource instanceof kendo.data.HierarchicalDataSource && dataSource.data();
            for (var i = 0; i < data.length; i++) {
                var item = data[i];
                item.checked = false;
                if (item.hasChildren) {
                    uncheckAll(item.children);
                }
            }
        }
        var FilterMenuViewModel = kendo.spreadsheet.FilterMenuViewModel = kendo.data.ObservableObject.extend({
            valuesChange: function (e) {
                var dataSource = e ? e.sender.dataSource : this.valuesDataSource;
                var checked = function (item) {
                    return item.checked;
                };
                var value = function (item) {
                    return item.dataType === 'date' ? kendo.spreadsheet.dateToNumber(item.value) : item.value;
                };
                var unique = function (value, index, array) {
                    return array.lastIndexOf(value) === index;
                };
                var data = dataSource.data();
                var values = data[0].children.data().toJSON();
                var blanks = values.filter(function (item) {
                    return item.dataType === 'blank';
                });
                blanks = blanks.length ? blanks[0].checked : false;
                values = values.filter(checked).map(value);
                if (this.appendToSearch && this.valueFilter && this.valueFilter.values.length) {
                    values = values.concat(this.valueFilter.values.toJSON()).sort().filter(unique);
                }
                this.set('valueFilter', {
                    values: values,
                    blanks: blanks
                });
            },
            valueSelect: function (e) {
                e.preventDefault();
                var node = e.sender.dataItem(e.node);
                node.set('checked', !node.checked);
            },
            hasActiveSearch: false,
            appendToSearch: false,
            filterValues: function (e) {
                var query = typeof e == 'string' ? e : $(e.target).val().toLowerCase();
                var dataSource = this.valuesDataSource;
                this.set('hasActiveSearch', !!query);
                var filterSpread = filter.bind(this.valueFilter);
                uncheckAll(dataSource);
                filterSpread(dataSource, query);
            },
            reset: function () {
                this.set('customFilter', {
                    logic: 'and',
                    criteria: [{
                            operator: null,
                            value: null
                        }]
                });
                this.set('valueFilter', { values: [] });
            },
            operatorChange: function (e) {
                var dataItem = e.sender.dataItem();
                this.set('operatorType', dataItem.type);
                if (!this.get('customFilter')) {
                    this.reset();
                }
                this.set('customFilter.criteria[0].operator', dataItem.value);
            },
            isNone: function () {
                return this.get('operatorType') === undefined;
            },
            isString: function () {
                return this.get('operatorType') === 'string';
            },
            isNumber: function () {
                return this.get('operatorType') === 'number';
            },
            isDate: function () {
                return this.get('operatorType') === 'date';
            }
        });
        function flattenOperators(operators) {
            var messages = kendo.spreadsheet.messages.filterMenu.operators;
            var result = [];
            for (var type in operators) {
                if (!operators.hasOwnProperty(type)) {
                    continue;
                }
                for (var operator in operators[type]) {
                    if (!operators[type].hasOwnProperty(operator)) {
                        continue;
                    }
                    result.push({
                        text: messages[type][operator],
                        value: operator,
                        unique: type + '_' + operator,
                        type: type
                    });
                }
            }
            return result;
        }
        var FilterMenuController = kendo.spreadsheet.FilterMenuController = {
            valuesTree: function (range, column) {
                return [{
                        text: kendo.spreadsheet.messages.filterMenu.all,
                        expanded: true,
                        checked: false,
                        items: this.values(range.resize({ top: 1 }), column)
                    }];
            },
            values: function (range, column) {
                var values = [];
                var messages = kendo.spreadsheet.messages.filterMenu;
                var columnRange = range.column(column);
                var sheet = range.sheet();
                columnRange.forEachCell(function (row, col, cell) {
                    var checked = true;
                    if (sheet.isHiddenRow(row)) {
                        checked = false;
                    }
                    var value = cell.value;
                    var dataType = cell.dataType;
                    var text = cell.text;
                    if (value === undefined) {
                        dataType = 'blank';
                    } else if (cell.format) {
                        dataType = kendo.spreadsheet.formatting.type(value, cell.format);
                    } else {
                        dataType = typeof value;
                    }
                    if (value !== null && cell.format) {
                        text = kendo.spreadsheet.formatting.text(value, cell.format);
                    } else {
                        text = dataType == 'blank' ? messages.blanks : value;
                    }
                    if (dataType === 'percent' || dataType === 'currency') {
                        dataType = 'number';
                    }
                    if (dataType === 'date') {
                        value = kendo.spreadsheet.numberToDate(value);
                    }
                    values.push({
                        dataType: dataType,
                        value: value,
                        text: text,
                        checked: checked
                    });
                });
                values = distinctValues(values);
                values.sort(function (a, b) {
                    if (a.dataType === b.dataType) {
                        return 0;
                    }
                    if (a.dataType === 'blank' || b.dataType === 'blank') {
                        return a.dataType === 'blank' ? -1 : 1;
                    }
                    if (a.dataType === 'number' || b.dataType === 'number') {
                        return a.dataType === 'number' ? -1 : 1;
                    }
                    if (a.dataType === 'date' || b.dataType === 'date') {
                        return a.dataType === 'date' ? -1 : 1;
                    }
                    return 0;
                });
                return values;
            },
            filterType: function (range, column) {
                var sheet = range.sheet();
                var filter = this.filterForColumn(column, sheet);
                var type;
                filter = filter && filter.filter.toJSON();
                if (filter && filter.filter == 'custom') {
                    var value = filter.criteria[0].value;
                    if (value instanceof Date) {
                        type = 'date';
                    } else if (typeof value == 'string') {
                        type = 'string';
                    } else if (typeof value == 'number') {
                        type = 'number';
                    }
                }
                if (!type) {
                    var topValue = this.values(range.row(1), column)[0];
                    type = topValue && topValue.dataType;
                    if (type == 'blank') {
                        type = null;
                    }
                }
                return type;
            },
            filterForColumn: function (column, sheet) {
                var allFilters = sheet.filter();
                var filters;
                if (allFilters) {
                    filters = allFilters.columns.filter(function (item) {
                        return item.index === column;
                    })[0];
                }
                return filters;
            },
            filter: function (column, sheet) {
                var columnFilters = this.filterForColumn(column, sheet);
                if (!columnFilters) {
                    return;
                }
                var options = columnFilters.filter.toJSON();
                var type = options.filter;
                delete options.filter;
                var result = {
                    type: type,
                    options: options
                };
                var criteria = options.criteria;
                if (criteria && criteria.length) {
                    result.operator = criteria[0].operator;
                }
                return result;
            }
        };
        var FilterMenu = Widget.extend({
            init: function (element, options) {
                Widget.call(this, element, options);
                this.element.addClass(FilterMenu.classNames.wrapper);
                this.viewModel = new FilterMenuViewModel({
                    active: 'value',
                    operator: null,
                    operators: flattenOperators(this.options.operators),
                    clear: this.clear.bind(this),
                    apply: this.apply.bind(this)
                });
                this._filterInit();
                this._popup();
                this._sort();
                this._filterByCondition();
                this._filterByValue();
                this._actionButtons();
            },
            options: {
                name: 'FilterMenu',
                column: 0,
                range: null,
                operators: {
                    string: {
                        contains: 'Text contains',
                        doesnotcontain: 'Text does not contain',
                        startswith: 'Text starts with',
                        endswith: 'Text ends with',
                        matches: 'Text matches',
                        doesnotmatch: 'Text does not match'
                    },
                    date: {
                        eq: 'Date is',
                        neq: 'Date is not',
                        lt: 'Date is before',
                        gt: 'Date is after'
                    },
                    number: {
                        eq: 'Is equal to',
                        neq: 'Is not equal to',
                        gte: 'Is greater than or equal to',
                        gt: 'Is greater than',
                        lte: 'Is less than or equal to',
                        lt: 'Is less than'
                    }
                }
            },
            events: ['action'],
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.menu.destroy();
                this.valuesTreeView.destroy();
                this.popup.destroy();
            },
            openFor: function (anchor) {
                this.popup.setOptions({ anchor: anchor });
                this.popup.open();
            },
            close: function () {
                this.popup.close();
            },
            clear: function () {
                this.action({
                    command: 'ClearFilterCommand',
                    options: { column: this.options.column }
                });
                this.viewModel.reset();
                this.close();
            },
            apply: function () {
                this._active();
                var options = {
                    operatingRange: this.options.range,
                    column: this.options.column
                };
                var valueFilter;
                var customFilter;
                if (this.viewModel.active === 'value') {
                    this.viewModel.valuesChange({ sender: this.valuesTreeView });
                    valueFilter = this.viewModel.valueFilter.toJSON();
                    if (valueFilter.blanks || valueFilter.values && valueFilter.values.length) {
                        options.valueFilter = valueFilter;
                    }
                } else if (this.viewModel.active === 'custom') {
                    customFilter = this.viewModel.customFilter.toJSON();
                    if (customFilter.criteria.length && customFilter.criteria[0].value !== null) {
                        options.customFilter = customFilter;
                    }
                }
                if (options.valueFilter || options.customFilter) {
                    this.action({
                        command: 'ApplyFilterCommand',
                        options: options
                    });
                }
            },
            action: function (options) {
                this.trigger('action', $.extend({}, options));
            },
            _filterInit: function () {
                var column = this.options.column;
                var range = this.options.range;
                var sheet = range.sheet();
                var activeFilter = FilterMenuController.filter(column, sheet);
                if (activeFilter) {
                    var filterType = FilterMenuController.filterType(range, column);
                    this.viewModel.set('active', activeFilter.type);
                    this.viewModel.set(activeFilter.type + 'Filter', activeFilter.options);
                    if (activeFilter.type == 'custom') {
                        this.viewModel.set('operator', filterType + '_' + activeFilter.operator);
                        this.viewModel.set('operatorType', filterType);
                    }
                } else {
                    this.viewModel.reset();
                }
            },
            _popup: function () {
                this.popup = this.element.kendoPopup({ copyAnchorStyles: false }).data('kendoPopup');
            },
            _sort: function () {
                var template = kendo.template(FilterMenu.templates.menuItem);
                var messages = kendo.spreadsheet.messages.filterMenu;
                var items = [
                    {
                        command: 'sort',
                        dir: 'asc',
                        text: messages.sortAscending,
                        iconClass: 'sort-asc'
                    },
                    {
                        command: 'sort',
                        dir: 'desc',
                        text: messages.sortDescending,
                        iconClass: 'sort-desc'
                    }
                ];
                var ul = $('<ul />', { 'html': kendo.render(template, items) }).appendTo(this.element);
                this.menu = ul.kendoMenu({
                    orientation: 'vertical',
                    select: function (e) {
                        var dir = $(e.item).data('dir');
                        var range = this.options.range.resize({ top: 1 });
                        var options = {
                            value: dir,
                            sheet: false,
                            operatingRange: range,
                            column: this.options.column
                        };
                        if (range.isSortable()) {
                            this.action({
                                command: 'SortCommand',
                                options: options
                            });
                        } else {
                            this.close();
                        }
                    }.bind(this)
                }).data('kendoMenu');
            },
            _appendTemplate: function (template, className, details, expanded) {
                var compiledTemplate = kendo.template(template);
                var wrapper = $('<div class=\'' + className + '\'/>').html(compiledTemplate({
                    messages: kendo.spreadsheet.messages.filterMenu,
                    guid: kendo.guid(),
                    ns: kendo.ns
                }));
                this.element.append(wrapper);
                if (details) {
                    details = new Details(wrapper, {
                        expanded: expanded,
                        toggle: this._detailToggle.bind(this)
                    });
                }
                kendo.bind(wrapper, this.viewModel);
                return wrapper;
            },
            _detailToggle: function (e) {
                this.element.find('[data-role=details]').not(e.sender.element).data('kendoDetails').toggle(!e.show);
            },
            _filterByCondition: function () {
                var isExpanded = this.viewModel.active === 'custom';
                this._appendTemplate(FilterMenu.templates.filterByCondition, FilterMenu.classNames.filterByCondition, true, isExpanded);
            },
            _filterByValue: function () {
                var isExpanded = this.viewModel.active === 'value';
                var wrapper = this._appendTemplate(FilterMenu.templates.filterByValue, FilterMenu.classNames.filterByValue, true, isExpanded);
                this.valuesTreeView = wrapper.find('[data-role=treeview]').data('kendoTreeView');
                var values = FilterMenuController.valuesTree(this.options.range, this.options.column);
                this.viewModel.set('valuesDataSource', new kendo.data.HierarchicalDataSource({ data: values }));
            },
            _actionButtons: function () {
                this._appendTemplate(FilterMenu.templates.actionButtons, FilterMenu.classNames.actionButtons, false);
            },
            _active: function () {
                var activeContainer = this.element.find('[data-role=details]').filter(function (index, element) {
                    return $(element).data('kendoDetails').visible();
                });
                if (activeContainer.hasClass(FilterMenu.classNames.filterByValue)) {
                    this.viewModel.set('active', 'value');
                } else if (activeContainer.hasClass(FilterMenu.classNames.filterByCondition)) {
                    this.viewModel.set('active', 'custom');
                }
            }
        });
        kendo.spreadsheet.FilterMenu = FilterMenu;
        $.extend(true, FilterMenu, {
            classNames: classNames,
            templates: templates
        });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/editor', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var SheetEditor = kendo.Observable.extend({
            init: function (view) {
                kendo.Observable.fn.init.call(this);
                this.view = view;
                this.formulaBar = view.formulaBar;
                this._active = false;
                this.barInput = view.formulaBar.formulaInput;
                this.cellInput = view.formulaInput;
                this.barInput.syncWith(this.cellInput);
                this.cellInput.syncWith(this.barInput);
                this.barInput.bind('keyup', this._triggerUpdate.bind(this));
                this.cellInput.bind('keyup', this._triggerUpdate.bind(this));
                this.barInput.bind('blur', this._blur.bind(this));
                this.cellInput.bind('blur', this._blur.bind(this));
            },
            events: [
                'activate',
                'deactivate',
                'change',
                'update'
            ],
            _blur: function () {
                this.deactivate();
            },
            _triggerUpdate: function () {
                this.trigger('update', { value: this.value() });
            },
            activeEditor: function () {
                var editor = null;
                var activeElement = kendo._activeElement();
                if (this.barElement()[0] === activeElement) {
                    editor = this.barInput;
                } else if (this.cellElement()[0] === activeElement) {
                    editor = this.cellInput;
                }
                return editor;
            },
            activate: function (options) {
                this._active = true;
                this._rect = options.rect;
                this._range = options.range;
                this.cellInput.position(options.rect);
                this.cellInput.resize(options.rect);
                this.cellInput.tooltip(options.tooltip);
                this.cellInput.activeCell = this.barInput.activeCell = this._range.topLeft();
                this.cellInput.activeSheet = this.barInput.activeSheet = this._range._sheet;
                this.trigger('activate');
                return this;
            },
            deactivate: function (noChange) {
                var cellInput = this.cellInput;
                if (!this._active) {
                    return;
                }
                this._active = false;
                if (!noChange && cellInput.value() != this._value) {
                    this.trigger('change', {
                        value: cellInput.value(),
                        range: this._range
                    });
                }
                this._rect = null;
                cellInput.hide();
                this.trigger('deactivate');
            },
            enable: function (enable) {
                this.barInput.enable(enable);
                this.cellInput.enable(enable);
            },
            barElement: function () {
                return this.barInput.element;
            },
            cellElement: function () {
                return this.cellInput.element;
            },
            focus: function (inputType) {
                inputType = inputType || 'cell';
                if (inputType === 'cell') {
                    this.cellInput.element.focus();
                    this.cellInput.end();
                } else {
                    this.barInput.element.focus();
                }
            },
            isActive: function () {
                return this._active;
            },
            isFiltered: function () {
                return this.barInput.popup.visible() || this.cellInput.popup.visible();
            },
            canInsertRef: function (isKeyboardAction) {
                var editor = this.activeEditor();
                return editor && editor.canInsertRef(isKeyboardAction);
            },
            highlightedRefs: function () {
                var editor = this.activeEditor();
                var refs = [];
                if (editor) {
                    refs = editor.highlightedRefs();
                }
                return refs;
            },
            scale: function () {
                this.cellInput.scale();
            },
            toggleTooltip: function (rect) {
                this.cellInput.toggleTooltip(notEqual(this._rect, rect));
            },
            value: function (value, isArrayFormula) {
                if (value === undefined) {
                    return this.barInput.value();
                }
                if (value === null) {
                    value = '';
                }
                this._value = value;
                this.barInput.value(value);
                this.cellInput.value(value);
                this.barInput.element.toggleClass('k-spreadsheet-array-formula', !!isArrayFormula);
            },
            insertNewline: function () {
                this.activeEditor().insertNewline();
                this.scale();
            },
            select: function () {
                this.activeEditor().select();
            }
        });
        function notEqual(oldRect, newRect) {
            return oldRect && (oldRect.top !== newRect.top || oldRect.left !== newRect.left);
        }
        kendo.spreadsheet.SheetEditor = SheetEditor;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/autofill', [
        'spreadsheet/runtime',
        'spreadsheet/range'
    ], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var spreadsheet = kendo.spreadsheet;
    var Range = spreadsheet.Range;
    var runtime = spreadsheet.calc.runtime;
    var Formula = runtime.Formula;
    var ERR_INCOMPATIBLE = 'incompatibleRanges';
    var ERR_NO_DIRECTION = 'noFillDirection';
    var FillError = Range.FillError = function (msg) {
        this.code = msg;
    };
    Range.prototype._previewFillFrom = function (srcRange, direction) {
        var destRange = this, sheet = destRange._sheet;
        if (typeof srcRange == 'string') {
            srcRange = sheet.range(srcRange);
        }
        var src = srcRange._ref.toRangeRef().clone().setSheet(sheet.name());
        var dest = destRange._ref.toRangeRef().clone().setSheet(sheet.name());
        if (src.intersects(dest)) {
            if (src.eq(dest)) {
                return null;
            }
            dest = dest.clone();
            if (src.topLeft.eq(dest.topLeft)) {
                if (src.width() == dest.width()) {
                    dest.topLeft.row += src.height();
                    direction = 0;
                } else if (src.height() == dest.height()) {
                    dest.topLeft.col += src.width();
                    direction = 1;
                } else {
                    throw new FillError(ERR_INCOMPATIBLE);
                }
            } else if (src.bottomRight.eq(dest.bottomRight)) {
                if (src.width() == dest.width()) {
                    dest.bottomRight.row -= src.height();
                    direction = 2;
                } else if (src.height() == dest.height()) {
                    dest.bottomRight.col -= src.width();
                    direction = 3;
                } else {
                    throw new FillError(ERR_INCOMPATIBLE);
                }
            } else {
                throw new FillError(ERR_INCOMPATIBLE);
            }
            return sheet.range(dest)._previewFillFrom(srcRange, direction);
        }
        if (direction == null) {
            if (src.topLeft.col == dest.topLeft.col) {
                direction = src.topLeft.row < dest.topLeft.row ? 0 : 2;
            } else if (src.topLeft.row == dest.topLeft.row) {
                direction = src.topLeft.col < dest.topLeft.col ? 1 : 3;
            } else {
                throw new FillError(ERR_NO_DIRECTION);
            }
        }
        var horizontal = direction & 1;
        var descending = direction & 2;
        if (horizontal && src.height() != dest.height() || !horizontal && src.width() != dest.width()) {
            throw new FillError(ERR_INCOMPATIBLE);
        }
        var data = srcRange._properties(), n;
        if (!horizontal) {
            data = transpose(data);
            n = dest.height();
        } else {
            n = dest.width();
        }
        var fill = new Array(data.length);
        var hint = null;
        for (var i = 0; i < data.length; ++i) {
            var s = data[i];
            var f = findSeries(s);
            var a = fill[i] = new Array(n);
            for (var j = 0; j < n; ++j) {
                var idx = descending ? -j - 1 : s.length + j;
                var srcIdx = descending ? s.length - j % s.length - 1 : j % s.length;
                var cell = a[descending ? n - j - 1 : j] = f(idx, srcIdx);
                if (cell.value != null) {
                    hint = cell.value;
                }
            }
        }
        if (!horizontal) {
            fill = transpose(fill);
        }
        return {
            props: fill,
            direction: direction,
            dest: destRange,
            hint: hint
        };
    };
    Range.prototype.fillFrom = function (srcRange, direction) {
        var x = this._previewFillFrom(srcRange, direction);
        x.dest._properties(x.props, true);
        return x.dest;
    };
    function linearRegression(data) {
        var N = data.length;
        var mx = (N + 1) / 2, my = data.reduce(function (a, b) {
                return a + b;
            }, 0) / N;
        var s1 = 0, s2 = 0;
        for (var i = 0; i < N; i++) {
            var t1 = i + 1 - mx, t2 = data[i] - my;
            s1 += t1 * t2;
            s2 += t1 * t1;
        }
        if (!s2) {
            return function (N) {
                return data[N % data.length];
            };
        }
        var b = s1 / s2, a = my - b * mx;
        return function (N) {
            return a + b * (N + 1);
        };
    }
    function findSeries(properties) {
        function findStep(a) {
            var diff = a[1] - a[0];
            for (var i = 2; i < a.length; ++i) {
                if (a[i] - a[i - 1] != diff) {
                    return null;
                }
            }
            return diff;
        }
        function getData(a) {
            return a.map(function (v) {
                return v.number;
            });
        }
        var series = [];
        var data = properties.map(function (x) {
            return x.formula || x.value;
        });
        forEachSeries(data, function (begin, end, type, a) {
            var f, values;
            if (type == 'number') {
                values = getData(a);
                f = linearRegression(values);
            } else if (type == 'string' || type == 'formula' || type == 'boolean') {
                f = function (N, i) {
                    return data[i];
                };
            } else if (Array.isArray(type)) {
                if (a.length == 1) {
                    f = function (N) {
                        return type[(a[0].number + N) % type.length];
                    };
                } else {
                    var diff = findStep(getData(a));
                    if (diff == null) {
                        f = function (N) {
                            return a[N % a.length].value;
                        };
                    } else {
                        f = function (N) {
                            var idx = a[0].number + diff * N;
                            return type[idx % type.length];
                        };
                    }
                }
            } else if (type != 'null') {
                values = getData(a);
                if (values.length == 1) {
                    values.push(values[0] + 1);
                }
                values = linearRegression(values);
                f = function (N, i) {
                    return data[i].replace(/^(.*\D)\d+/, '$1' + values(N, i));
                };
            } else {
                f = function () {
                    return null;
                };
            }
            var s = {
                f: f,
                begin: begin,
                end: end,
                len: end - begin
            };
            for (var i = begin; i < end; ++i) {
                series[i] = s;
            }
        });
        return function (N, i) {
            var s = series[i];
            var q = N / data.length | 0;
            var r = N % data.length;
            var n = q * s.len + r - s.begin;
            var value = s.f(n, i);
            var props = clone(properties[i]);
            delete props.enable;
            if (value instanceof Formula) {
                props.formula = value;
            } else {
                props.value = value;
            }
            return props;
        };
    }
    function clone(obj) {
        var copy = {};
        Object.keys(obj || {}).forEach(function (key) {
            copy[key] = obj[key];
        });
        return copy;
    }
    function forEachSeries(data, f) {
        var prev = null, start = 0, a = [], type;
        for (var i = 0; i < data.length; ++i) {
            type = getType(data[i]);
            a.push(type);
            if (prev != null && type.type !== prev.type) {
                f(start, i, prev.type, a.slice(start, i));
                start = i;
            }
            prev = type;
        }
        f(start, i, prev.type, a.slice(start, i));
    }
    function getType(el) {
        if (typeof el == 'number') {
            return {
                type: 'number',
                number: el
            };
        }
        if (typeof el == 'string') {
            var lst = findStringList(el);
            if (lst) {
                return lst;
            }
            var m = /^(.*\D)(\d+)/.exec(el);
            if (m) {
                el = el.replace(/^(.*\D)\d+/, '$1-######');
                return {
                    type: el,
                    match: m,
                    number: parseFloat(m[2])
                };
            }
            return { type: 'string' };
        }
        if (typeof el == 'boolean') {
            return { type: 'boolean' };
        }
        if (el == null) {
            return { type: 'null' };
        }
        if (el instanceof Formula) {
            return { type: 'formula' };
        }
        window.console.error(el);
        throw new Error('Cannot fill data');
    }
    function stringLists() {
        var culture = kendo.culture();
        return [
            culture.calendars.standard.days.namesAbbr,
            culture.calendars.standard.days.names,
            culture.calendars.standard.months.namesAbbr,
            culture.calendars.standard.months.names
        ];
    }
    function findStringList(str) {
        var strl = str.toLowerCase();
        var lists = stringLists();
        for (var i = 0; i < lists.length; ++i) {
            var a = lists[i];
            for (var j = a.length; --j >= 0;) {
                var el = a[j].toLowerCase();
                if (el == strl) {
                    return {
                        type: a,
                        number: j,
                        value: str
                    };
                }
            }
        }
    }
    function transpose(a) {
        var height = a.length, width = a[0].length;
        var t = [];
        for (var i = 0; i < width; ++i) {
            t[i] = [];
            for (var j = 0; j < height; ++j) {
                t[i][j] = a[j][i];
            }
        }
        return t;
    }
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/nameeditor', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var CLASS_NAMES = {
            input: 'k-spreadsheet-name-editor',
            list: 'k-spreadsheet-name-list'
        };
        var NameEditor = kendo.ui.Widget.extend({
            init: function (element, options) {
                kendo.ui.Widget.call(this, element, options);
                element.addClass(CLASS_NAMES.input);
                var comboBoxTitle = options.messages.nameBox || 'Name Box';
                var dataSource = new kendo.data.DataSource({
                    transport: {
                        read: function (options) {
                            var data = [];
                            this._workbook.forEachName(function (def) {
                                if (!def.hidden && def.value instanceof kendo.spreadsheet.Ref) {
                                    data.push({ name: def.name });
                                }
                            });
                            options.success(data);
                        }.bind(this),
                        cache: false
                    }
                });
                var comboElement = $('<input />').attr('title', comboBoxTitle).attr('aria-label', comboBoxTitle);
                this.combo = comboElement.appendTo(element).kendoComboBox({
                    clearButton: false,
                    dataTextField: 'name',
                    dataValueField: 'name',
                    template: '#:data.name#<a class=\'k-button-delete\' href=\'\\#\'><span class=\'k-icon k-i-close\'></span></a>',
                    dataSource: dataSource,
                    autoBind: false,
                    ignoreCase: true,
                    change: this._on_listChange.bind(this),
                    noDataTemplate: '<div></div>',
                    open: function () {
                        dataSource.read();
                    }
                }).getKendoComboBox();
                this.combo.input.on('keydown', this._on_keyDown.bind(this)).on('focus', this._on_focus.bind(this));
                this.combo.popup.element.addClass('k-spreadsheet-names-popup').on('mousemove', function (ev) {
                    ev.stopPropagation();
                }).on('click', '.k-button-delete', function (ev) {
                    ev.preventDefault();
                    ev.stopPropagation();
                    var item = $(ev.target).closest('.k-item');
                    item = this.combo.dataItem(item);
                    this._deleteItem(item.name);
                }.bind(this));
            },
            value: function (val) {
                if (val === undefined) {
                    return this.combo.value();
                } else {
                    this.combo.value(val);
                }
            },
            _deleteItem: function (name) {
                this.trigger('delete', { name: name });
            },
            _on_keyDown: function (ev) {
                switch (ev.keyCode) {
                case 27:
                    this.combo.value(this._prevValue);
                    this.trigger('cancel');
                    break;
                case 13:
                    this.trigger('enter');
                    break;
                }
            },
            _on_focus: function () {
                this._prevValue = this.combo.value();
            },
            _on_listChange: function () {
                var name = this.combo.value();
                if (name) {
                    this.trigger('select', { name: name });
                }
            }
        });
        kendo.spreadsheet.NameEditor = NameEditor;
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/print', [
        'kendo.pdf',
        'spreadsheet/sheet',
        'spreadsheet/range',
        'spreadsheet/references',
        'spreadsheet/numformat',
        'util/text-metrics'
    ], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var spreadsheet = kendo.spreadsheet;
    var CellRef = spreadsheet.CellRef;
    var kdrw = kendo.drawing;
    var formatting = spreadsheet.formatting;
    var geo = kendo.geometry;
    var GUIDELINE_WIDTH = 0.8;
    function distributeCoords(heights, pageHeight, maxEmpty, headerRows, headerCoords) {
        var curr = 0;
        var out = [];
        var bottom = pageHeight;
        var header = 0;
        if (pageHeight && maxEmpty) {
            maxEmpty *= pageHeight;
        }
        heights.forEach(function (h, i) {
            if (headerRows != null && i < headerRows) {
                header += h;
            }
            if (pageHeight && curr + h > bottom) {
                if (bottom - curr < maxEmpty) {
                    curr = pageHeight * Math.ceil(curr / pageHeight) + header;
                    if (header > 0) {
                        headerCoords.push(curr - header);
                    }
                }
                bottom += pageHeight * Math.ceil(h / pageHeight);
            }
            out.push(curr);
            curr += h;
        });
        out.push(curr);
        return out;
    }
    function doLayout(sheet, range, options) {
        var grid = sheet._grid;
        range = grid.normalize(range);
        var wholeRect = grid.rectangle(range);
        var drawings = [];
        sheet._drawings.forEach(function (d) {
            var box = sheet.drawingBoundingBox(d);
            if (box.intersects(wholeRect)) {
                drawings.push({
                    drawing: d,
                    box: box.offset(-wholeRect.left, -wholeRect.top)
                });
            }
        });
        var cells = [];
        var rowHeights = [];
        var colWidths = [];
        var mergedCells = sheet._getMergedCells(range);
        var maxRow = -1, maxCol = -1;
        sheet.forEach(range, function (row, col, cell) {
            var relrow = row - range.topLeft.row;
            var relcol = col - range.topLeft.col;
            var rh = sheet.rowHeight(row);
            var cw = sheet.columnWidth(col);
            if (!options.forScreen) {
                cell.drawings = drawings.filter(function (d) {
                    var tl = d.drawing.topLeftCell;
                    return tl && tl.row == row && tl.col == col;
                });
            }
            if (!relcol) {
                rowHeights.push(rh);
            }
            if (!relrow) {
                colWidths.push(cw);
            }
            if (sheet.isHiddenColumn(col) || sheet.isHiddenRow(row) || !rh || !cw) {
                return;
            }
            var nonEmpty = options.forScreen || shouldDrawCell(cell);
            if (!(options.emptyCells || nonEmpty)) {
                return;
            }
            var id = new CellRef(row, col).print();
            if (mergedCells.secondary[id]) {
                return;
            }
            if (nonEmpty) {
                maxRow = Math.max(maxRow, relrow);
                maxCol = Math.max(maxCol, relcol);
            } else {
                cell.empty = true;
            }
            cell.row = relrow;
            cell.col = relcol;
            var m = mergedCells.primary[id];
            if (m) {
                delete mergedCells.primary[id];
                cell.merged = true;
                cell.rowspan = m.height();
                cell.colspan = m.width();
                if (options.forScreen) {
                    cell.width = sheet._columns.sum(m.topLeft.col, m.bottomRight.col);
                    cell.height = sheet._rows.sum(m.topLeft.row, m.bottomRight.row);
                }
            } else {
                cell.rowspan = 1;
                cell.colspan = 1;
            }
            cells.push(cell);
        });
        rowHeights = rowHeights.slice(0, maxRow + 1);
        colWidths = colWidths.slice(0, maxCol + 1);
        var pageWidth = options.pageWidth;
        var pageHeight = options.pageHeight;
        var scaleFactor = options.scale || 1;
        if (options.fitWidth) {
            var width = colWidths.reduce(sum, 0);
            if (width > pageWidth) {
                scaleFactor = pageWidth / width;
            }
        }
        pageWidth = Math.ceil(pageWidth / scaleFactor);
        pageHeight = Math.ceil(pageHeight / scaleFactor);
        var hyCoords = [];
        var yCoords = distributeCoords(rowHeights, pageHeight || 0, options.maxEmpty, options.headerRows, hyCoords);
        var xCoords = distributeCoords(colWidths, pageWidth || 0, options.maxEmpty);
        var boxWidth = 0;
        var boxHeight = 0;
        var headerCells = [];
        cells = cells.filter(function (cell) {
            if (cell.empty && (cell.row > maxRow || cell.col > maxCol)) {
                return false;
            }
            if (options.headerRows && cell.row < options.headerRows) {
                headerCells.push(cell);
            }
            cell.left = xCoords[cell.col];
            cell.top = yCoords[cell.row];
            if (cell.merged) {
                if (!options.forScreen) {
                    cell.right = orlast(xCoords, cell.col + cell.colspan);
                    cell.bottom = orlast(yCoords, cell.row + cell.rowspan);
                    cell.width = cell.right - cell.left;
                    cell.height = cell.bottom - cell.top;
                } else {
                    cell.right = cell.left + cell.width;
                    cell.bottom = cell.top + cell.height;
                }
            } else {
                cell.width = colWidths[cell.col];
                cell.height = rowHeights[cell.row];
                cell.bottom = cell.top + cell.height;
                cell.right = cell.left + cell.width;
            }
            if (!options.forScreen) {
                cell.drawings.forEach(function (d) {
                    var box = d.box;
                    box.left = cell.left + d.drawing.offsetX;
                    box.top = cell.top + d.drawing.offsetY;
                    box.right = box.left + box.width;
                    box.bottom = box.top + box.height;
                });
            }
            boxWidth = Math.max(boxWidth, cell.right);
            boxHeight = Math.max(boxHeight, cell.bottom);
            return true;
        });
        Object.keys(mergedCells.primary).forEach(function (id) {
            var ref = mergedCells.primary[id];
            sheet.forEach(ref.topLeft.toRangeRef(), function (row, col, cell) {
                var relrow = row - range.topLeft.row;
                var relcol = col - range.topLeft.col;
                cell.merged = true;
                cell.colspan = ref.width();
                cell.rowspan = ref.height();
                if (relrow < 0) {
                    cell.top = -sheet._rows.sum(row, row - relrow - 1);
                } else {
                    cell.top = yCoords[relrow];
                }
                if (relcol < 0) {
                    cell.left = -sheet._columns.sum(col, col - relcol - 1);
                } else {
                    cell.left = xCoords[relcol];
                }
                cell.height = sheet._rows.sum(ref.topLeft.row, ref.bottomRight.row);
                cell.width = sheet._columns.sum(ref.topLeft.col, ref.bottomRight.col);
                if (cell.height > 0 && cell.width > 0) {
                    cell.right = cell.left + cell.width;
                    cell.bottom = cell.top + cell.height;
                    cell.row = relrow;
                    cell.col = relcol;
                    cells.push(cell);
                }
            });
        });
        if (options.headerRows) {
            hyCoords.forEach(function (y) {
                headerCells.forEach(function (cell) {
                    cell = clone(cell);
                    cell.top += y;
                    cell.bottom = cell.top + cell.height;
                    cells.push(cell);
                });
                yCoords.push(y);
            });
            yCoords.sort(orderCoords);
        }
        return {
            width: boxWidth,
            height: boxHeight,
            cells: cells.sort(orderCells),
            scale: scaleFactor,
            xCoords: xCoords,
            yCoords: yCoords,
            drawings: drawings
        };
    }
    function clone(hash, target) {
        if (!target) {
            target = {};
        }
        if (Object.assign) {
            return Object.assign(target, hash);
        }
        return Object.keys(hash).reduce(function (copy, key) {
            copy[key] = hash[key];
            return copy;
        }, target);
    }
    function sameBorder(a, b) {
        return a.size === b.size && a.color === b.color;
    }
    function sum(a, b) {
        return a + b;
    }
    function orlast(a, i) {
        return i < a.length ? a[i] : a[a.length - 1];
    }
    function shouldDrawCell(cell) {
        return cell.value != null || cell.merged || cell.background != null || cell.borderRight != null || cell.borderBottom != null || cell.validation != null && !cell.validation.value;
    }
    function orderCells(a, b) {
        if (a.top < b.top) {
            return -1;
        } else if (a.top == b.top) {
            if (a.left < b.left) {
                return -1;
            } else if (a.left == b.left) {
                return 0;
            } else {
                return 1;
            }
        } else {
            return 1;
        }
    }
    function orderCoords(a, b) {
        return a < b ? -1 : a > b ? 1 : 0;
    }
    function drawLayout(sheet, layout, group, options) {
        var ncols = Math.ceil(layout.width / options.pageWidth);
        var nrows = Math.ceil(layout.height / options.pageHeight);
        var pageWidth = Math.ceil(options.pageWidth / layout.scale);
        var pageHeight = Math.ceil(options.pageHeight / layout.scale);
        for (var j = 0; j < nrows; ++j) {
            for (var i = 0; i < ncols; ++i) {
                addPage(j, i);
            }
        }
        function addPage(row, col) {
            var left = col * pageWidth;
            var right = left + pageWidth;
            var top = row * pageHeight;
            var bottom = top + pageHeight;
            var endbottom = 0, endright = 0;
            function isInside(box) {
                if (box.right <= left || box.left >= right || box.bottom <= top || box.top >= bottom) {
                    return false;
                }
                endbottom = Math.max(box.bottom, endbottom);
                endright = Math.max(box.right, endright);
                return true;
            }
            var cells = layout.cells.filter(isInside);
            var drawings = layout.drawings.filter(function (d) {
                return isInside(d.box);
            });
            endbottom = Math.min(endbottom, bottom);
            endright = Math.min(endright, right);
            if (cells.length || drawings.length) {
                var page = new kdrw.Group();
                group.append(page);
                var content = new kdrw.Group();
                page.append(content);
                content.clip(kdrw.Path.fromRect(new geo.Rect([
                    left - 1,
                    top - 1
                ], [
                    endright + 1,
                    endbottom + 1
                ])));
                var matrix = geo.Matrix.scale(layout.scale, layout.scale).multiplyCopy(geo.Matrix.translate(-left, -top));
                if (options.hCenter || options.vCenter) {
                    matrix = matrix.multiplyCopy(geo.Matrix.translate(options.hCenter ? (right - endright) / 2 : 0, options.vCenter ? (bottom - endbottom) / 2 : 0));
                }
                content.transform(matrix);
                if (options.guidelines) {
                    var prev = null;
                    layout.xCoords.forEach(function (x) {
                        x = Math.min(x, endright);
                        if (x !== prev && x >= left && x <= right) {
                            prev = x;
                            content.append(new kdrw.Path().moveTo(x, top).lineTo(x, endbottom).close().stroke(options.guideColor, GUIDELINE_WIDTH));
                        }
                    });
                    var prev = null;
                    layout.yCoords.forEach(function (y) {
                        y = Math.min(y, endbottom);
                        if (y !== prev && y >= top && y <= bottom) {
                            prev = y;
                            content.append(new kdrw.Path().moveTo(left, y).lineTo(endright, y).close().stroke(options.guideColor, GUIDELINE_WIDTH));
                        }
                    });
                }
                var borders = Borders();
                cells.forEach(function (cell) {
                    drawCell(cell, content, options);
                    borders.add(cell, sheet);
                });
                var bordersGroup = new kdrw.Group();
                borders.vert.forEach(function (a) {
                    a.forEach(function (b) {
                        if (!b.rendered) {
                            b.rendered = true;
                            bordersGroup.append(new kdrw.Path().moveTo(b.x, b.top).lineTo(b.x, b.bottom).close().stroke(b.color, b.size));
                        }
                    });
                });
                borders.horiz.forEach(function (a) {
                    a.forEach(function (b) {
                        if (!b.rendered) {
                            b.rendered = true;
                            bordersGroup.append(new kdrw.Path().moveTo(b.left, b.y).lineTo(b.right, b.y).close().stroke(b.color, b.size));
                        }
                    });
                });
                content.append(bordersGroup);
                drawings.forEach(function (d) {
                    var drawing = d.drawing;
                    var image = drawing.image;
                    if (image != null) {
                        var box = d.box;
                        var url = sheet._workbook.imageUrl(image);
                        content.append(new kdrw.Image(url, new geo.Rect([
                            box.left,
                            box.top
                        ], [
                            box.width,
                            box.height
                        ])).opacity(drawing.opacity));
                    }
                });
            }
        }
    }
    function drawCell(cell, content, options) {
        var g = new kdrw.Group();
        content.append(g);
        var rect = new geo.Rect([
            cell.left,
            cell.top
        ], [
            cell.width,
            cell.height
        ]);
        if (cell.background || cell.merged) {
            var r2d2 = rect;
            if (options.guidelines) {
                r2d2 = rect.clone();
                r2d2.origin.x += GUIDELINE_WIDTH / 2 + 0.1;
                r2d2.origin.y += GUIDELINE_WIDTH / 2 + 0.1;
                r2d2.size.width -= GUIDELINE_WIDTH + 0.2;
                r2d2.size.height -= GUIDELINE_WIDTH + 0.2;
            }
            g.append(new kdrw.Rect(r2d2).fill(cell.background || '#fff').stroke(null));
        }
        var val = cell.value;
        if (val != null) {
            var type = typeof val == 'number' ? 'number' : null;
            var clip = new kdrw.Group();
            clip.clip(kdrw.Path.fromRect(rect));
            g.append(clip);
            var f, format = cell.format;
            if (!format && type == 'number' && val != Math.floor(val)) {
                format = '0.##############';
            }
            if (format) {
                f = formatting.textAndColor(val, format);
                val = f.text;
                if (f.type) {
                    type = f.type;
                }
            } else {
                val += '';
            }
            if (!cell.textAlign) {
                switch (type) {
                case 'number':
                case 'date':
                case 'percent':
                case 'currency':
                    cell.textAlign = 'right';
                    break;
                case 'boolean':
                    cell.textAlign = 'center';
                    break;
                }
            }
            drawText(val, f && f.color || cell.color || '#000', cell, clip);
        }
    }
    function applyIndent(cell, style) {
        if (cell.indent) {
            var indent = 1.4 * cell.indent;
            switch (style.textAlign) {
            case null:
            case 'left':
                style.paddingLeft = indent + 'ch';
                break;
            case 'right':
                style.paddingRight = indent + 'ch';
                break;
            case 'center':
                style.paddingLeft = indent / 2 + 'ch';
                style.paddingRight = indent / 2 + 'ch';
                break;
            }
        }
    }
    var CONT;
    function drawText(text, color, cell, group) {
        if (!CONT) {
            CONT = document.createElement('div');
            CONT.style.position = 'fixed';
            CONT.style.left = '0px';
            CONT.style.top = '0px';
            CONT.style.visibility = 'hidden';
            CONT.style.overflow = 'hidden';
            CONT.style.boxSizing = 'border-box';
            CONT.style.lineHeight = 'normal';
            document.body.appendChild(CONT);
        }
        if (CONT.firstChild) {
            CONT.removeChild(CONT.firstChild);
        }
        CONT.style.padding = '2px 4px';
        CONT.style.color = color;
        CONT.style.font = makeFontDef(cell);
        CONT.style.width = cell.width + 'px';
        CONT.style.textAlign = cell.textAlign || 'left';
        CONT.style.textDecoration = cell.underline ? 'underline' : 'none';
        applyIndent(cell, CONT.style);
        if (cell.wrap) {
            CONT.style.whiteSpace = 'pre-wrap';
            CONT.style.overflowWrap = CONT.style.wordWrap = 'break-word';
        } else {
            CONT.style.whiteSpace = 'pre';
            CONT.style.overflowWrap = CONT.style.wordWrap = 'normal';
        }
        CONT.appendChild(document.createTextNode(text));
        var vtrans = 0;
        switch (cell.verticalAlign) {
        case 'center':
            vtrans = cell.height - CONT.offsetHeight >> 1;
            break;
        case undefined:
        case null:
        case 'bottom':
            vtrans = cell.height - CONT.offsetHeight;
            break;
        }
        if (vtrans < 0) {
            vtrans = 0;
        }
        var text_group = kendo.drawing.drawDOM.drawText(CONT);
        text_group.transform(geo.Matrix.translate(cell.left, cell.top + vtrans));
        group.append(text_group);
    }
    function makeFontDef(cell) {
        var font = [];
        if (cell.italic) {
            font.push('italic');
        }
        if (cell.bold) {
            font.push('bold');
        }
        font.push((cell.fontSize || 12) + 'px');
        font.push(cell.fontFamily || 'Arial');
        return font.join(' ');
    }
    function draw(sheet, range, options, callback) {
        if (options == null && callback == null) {
            callback = range;
            options = {};
            range = spreadsheet.SHEETREF;
        }
        if (callback == null) {
            callback = options;
            if (range instanceof spreadsheet.Range || range instanceof spreadsheet.Ref || typeof range == 'string') {
                options = {};
            } else {
                options = range;
                range = spreadsheet.SHEETREF;
            }
        }
        options = kendo.jQuery.extend({
            paperSize: 'A4',
            landscape: true,
            margin: '1cm',
            guidelines: true,
            guideColor: '#aaa',
            emptyCells: true,
            fitWidth: false,
            center: false,
            headerRows: null,
            maxEmpty: 0.2,
            scale: 1
        }, options);
        var group = new kdrw.Group();
        var paper = kendo.pdf.getPaperOptions(options);
        group.options.set('pdf', {
            author: options.author,
            creator: options.creator,
            date: options.date,
            keywords: options.keywords,
            margin: paper.margin,
            multiPage: true,
            paperSize: paper.paperSize,
            subject: options.subject,
            title: options.title
        });
        var pageWidth = paper.paperSize[0];
        var pageHeight = paper.paperSize[1];
        if (paper.margin) {
            pageWidth -= paper.margin.left + paper.margin.right + 1;
            pageHeight -= paper.margin.top + paper.margin.bottom + 1;
        }
        options.pageWidth = pageWidth;
        options.pageHeight = pageHeight;
        var layout = doLayout(sheet, sheet._ref(range), options);
        drawLayout(sheet, layout, group, options);
        callback(group);
    }
    spreadsheet.Sheet.prototype.draw = function (range, options, callback) {
        var sheet = this;
        if (sheet._workbook) {
            sheet.recalc(sheet._workbook._context, function () {
                draw(sheet, range, options, callback);
            });
        } else {
            draw(sheet, range, options, callback);
        }
    };
    function Container() {
    }
    Container.prototype = {
        forEach: function (f) {
            Object.keys(this).forEach(function (key) {
                f(this[key], key, this);
            }, this);
        }
    };
    function Borders() {
        var horiz = new Container();
        var vert = new Container();
        function add(cell, sheet) {
            if (sheet) {
                var pb = sheet._properties;
                var grid = sheet._grid;
                cell.borderLeft = pb.get('vBorders', grid.index(cell.row, cell.col));
                cell.borderRight = pb.get('vBorders', grid.index(cell.row, cell.col + cell.colspan));
                cell.borderTop = pb.get('hBorders', grid.index(cell.row, cell.col));
                cell.borderBottom = pb.get('hBorders', grid.index(cell.row + cell.rowspan, cell.col));
            }
            if (cell.borderLeft) {
                addVert(cell.row, cell.col, cell.borderLeft, cell.left, cell.top, cell.bottom);
            }
            if (cell.borderRight) {
                addVert(cell.row, cell.col + cell.colspan, cell.borderRight, cell.right, cell.top, cell.bottom);
            }
            if (cell.borderTop) {
                addHoriz(cell.row, cell.col, cell.borderTop, cell.top, cell.left, cell.right);
            }
            if (cell.borderBottom) {
                addHoriz(cell.row + cell.rowspan, cell.col, cell.borderBottom, cell.bottom, cell.left, cell.right);
            }
        }
        function addVert(row, col, border, x, top, bottom) {
            var a = vert[col] || (vert[col] = new Container());
            var prev = row > 0 && a[row - 1];
            if (prev && sameBorder(prev, border)) {
                a[row] = prev;
                prev.bottom = bottom;
            } else {
                a[row] = {
                    size: border.size,
                    color: border.color,
                    x: x,
                    top: top,
                    bottom: bottom
                };
            }
        }
        function addHoriz(row, col, border, y, left, right) {
            var a = horiz[row] || (horiz[row] = new Container());
            var prev = col > 0 && a[col - 1];
            if (prev && sameBorder(prev, border)) {
                a[col] = prev;
                prev.right = right;
            } else {
                a[col] = {
                    size: border.size,
                    color: border.color,
                    y: y,
                    left: left,
                    right: right
                };
            }
        }
        return {
            add: add,
            horiz: horiz,
            vert: vert
        };
    }
    function drawTabularData(options) {
        var progress = new $.Deferred();
        var promise = progress.promise();
        options = clone(options, {
            dataSource: null,
            guidelines: true,
            guideColor: '#000',
            columns: null,
            headerBackground: '#999',
            headerColor: '#000',
            oddBackground: null,
            evenBackground: null,
            fontFamily: 'Arial',
            fontSize: 12,
            paperSize: 'A4',
            margin: '1cm',
            landscape: true,
            fitWidth: false,
            scale: 1,
            rowHeight: 20,
            maxEmpty: 1,
            useGridFormat: true
        });
        kendo.drawing.pdf.defineFont(kendo.drawing.drawDOM.getFontFaces(document));
        var charWidth = charWidthFunction(options.fontFamily, options.fontSize);
        function textWidth(value) {
            if (value != null) {
                var width = 12;
                for (var i = value.length; --i >= 0;) {
                    width += charWidth(value.charAt(i));
                }
                return width;
            }
            return 0;
        }
        var border = options.guidelines ? {
            size: 1,
            color: options.guideColor
        } : null;
        function mkCell(data) {
            if (!border) {
                return data;
            }
            return clone(data, {
                borderLeft: border,
                borderTop: border,
                borderRight: border,
                borderBottom: border
            });
        }
        options.dataSource.fetch(function () {
            var data = options.dataSource.data();
            if (!data.length) {
                return progress.reject('Empty dataset');
            }
            var columns = options.columns.map(function (col) {
                if (typeof col == 'string') {
                    return {
                        title: col,
                        field: col
                    };
                } else {
                    return col;
                }
            });
            var columnTitles = columns.map(function (col) {
                return col.title || col.field;
            });
            var columnWidths = columnTitles.map(textWidth);
            var rows = data.map(function (row, rowIndex) {
                return {
                    cells: columns.map(function (col, colIndex) {
                        var value = row[col.field];
                        if (options.useGridFormat) {
                            if (value != null) {
                                if (col.format) {
                                    value = kendo.format(col.format, value);
                                } else {
                                    value += '';
                                }
                            }
                            columnWidths[colIndex] = Math.max(textWidth(value), columnWidths[colIndex]);
                        }
                        return mkCell({
                            value: value,
                            format: options.useGridFormat ? null : col.format,
                            background: rowIndex % 2 ? options.evenBackground : options.oddBackground
                        });
                    })
                };
            });
            rows.unshift({
                cells: columnTitles.map(function (label) {
                    return mkCell({
                        value: label,
                        background: options.headerBackground,
                        color: options.headerColor
                    });
                })
            });
            var sheet = new kendo.spreadsheet.Sheet(rows.length + 1, columns.length + 1, options.rowHeight, 50, 20, 20, {
                fontFamily: options.fontFamily,
                fontSize: options.fontSize,
                verticalAlign: 'center'
            });
            sheet.fromJSON({
                name: 'Sheet1',
                rows: rows,
                columns: columnWidths.map(function (w, i) {
                    return {
                        index: i,
                        width: w
                    };
                })
            });
            sheet.draw({
                paperSize: options.paperSize,
                landscape: options.landscape,
                margin: options.margin,
                guidelines: false,
                scale: options.scale,
                fitWidth: options.fitWidth,
                maxEmpty: options.maxEmpty,
                headerRows: 1
            }, progress.resolve.bind(progress));
        });
        return promise;
    }
    var CACHE_CHAR_WIDTH = {};
    var charWidthFunction = function (fontFamily, fontSize) {
        var id = fontSize + ':' + fontFamily;
        var func = CACHE_CHAR_WIDTH[id];
        if (!func) {
            var span, div = document.createElement('div');
            div.style.position = 'fixed';
            div.style.left = '-10000px';
            div.style.top = '-10000px';
            div.style.fontFamily = fontFamily;
            div.style.fontSize = fontSize + 'px';
            div.style.whiteSpace = 'pre';
            for (var i = 32; i < 128; ++i) {
                span = document.createElement('span');
                span.appendChild(document.createTextNode(String.fromCharCode(i)));
                div.appendChild(span);
            }
            document.body.appendChild(div);
            var widths = {};
            for (i = 32, span = div.firstChild; i < 128 && span; ++i, span = span.nextSibling) {
                widths[i] = span.offsetWidth;
            }
            while (span = div.firstChild) {
                div.removeChild(span);
            }
            func = CACHE_CHAR_WIDTH[id] = function (ch) {
                var code = ch.charCodeAt(0);
                var width = widths[code];
                if (width == null) {
                    span = document.createElement('span');
                    span.appendChild(document.createTextNode(String.fromCharCode(code)));
                    div.appendChild(span);
                    width = widths[code] = span.offsetWidth;
                    div.removeChild(span);
                }
                return width;
            };
        }
        return func;
    };
    spreadsheet.draw = {
        Borders: Borders,
        doLayout: doLayout,
        applyIndent: applyIndent
    };
    spreadsheet.drawTabularData = drawTabularData;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.spreadsheet', [
        'util/undoredostack',
        'util/text-metrics',
        'util/parse-xml',
        'kendo.excel',
        'kendo.progressbar',
        'kendo.pdf',
        'spreadsheet/commands',
        'spreadsheet/formulabar',
        'spreadsheet/formulainput',
        'spreadsheet/eventlistener',
        'spreadsheet/rangelist',
        'spreadsheet/propertybag',
        'spreadsheet/references',
        'spreadsheet/navigator',
        'spreadsheet/axismanager',
        'spreadsheet/clipboard',
        'spreadsheet/range',
        'spreadsheet/sheet',
        'spreadsheet/sheetsbar',
        'spreadsheet/excel-reader',
        'spreadsheet/workbook',
        'spreadsheet/formulacontext',
        'spreadsheet/controller',
        'spreadsheet/view',
        'spreadsheet/customeditors',
        'spreadsheet/grid',
        'spreadsheet/axis',
        'spreadsheet/filter',
        'spreadsheet/sorter',
        'spreadsheet/runtime',
        'spreadsheet/calc',
        'spreadsheet/numformat',
        'spreadsheet/runtime.functions',
        'spreadsheet/runtime.functions.2',
        'spreadsheet/toolbar',
        'spreadsheet/dialogs',
        'spreadsheet/sheetbinder',
        'spreadsheet/filtermenu',
        'spreadsheet/editor',
        'spreadsheet/autofill',
        'spreadsheet/nameeditor',
        'spreadsheet/print'
    ], f);
}(function () {
    var __meta__ = {
        id: 'spreadsheet',
        name: 'Spreadsheet',
        category: 'web',
        description: 'Spreadsheet component',
        depends: [
            'core',
            'binder',
            'colorpicker',
            'combobox',
            'data',
            'dom',
            'dropdownlist',
            'menu',
            'ooxml',
            'popup',
            'sortable',
            'tabstrip',
            'toolbar',
            'treeview',
            'window',
            'validator',
            'excel',
            'pdf',
            'drawing'
        ]
    };
    (function (kendo, undefined) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var keys = $.extend({
            F10: 121,
            F11: 122,
            B: 66,
            I: 73,
            U: 85,
            N: 78,
            H: 72,
            A: 65,
            PAGEDOWN: 34,
            PAGEUP: 33,
            DELETE: 46,
            R: 82
        }, kendo.keys);
        var Widget = kendo.ui.Widget;
        var Workbook = kendo.spreadsheet.Workbook;
        var Controller = kendo.spreadsheet.Controller;
        var View = kendo.spreadsheet.View;
        var NS = '.kendoSpreadsheet';
        var ALL_REASONS = {
            recalc: true,
            selection: true,
            activeCell: true,
            layout: true,
            sheetSelection: true,
            resize: true,
            editorChange: false,
            editorClose: false
        };
        var classNames = { wrapper: 'k-widget k-spreadsheet' };
        var Spreadsheet = kendo.ui.Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.element.addClass(Spreadsheet.classNames.wrapper);
                this._view = new View(this.element, {
                    messages: this.options.messages.view,
                    toolbar: this.options.toolbar,
                    sheetsbar: this.options.sheetsbar
                });
                this._workbook = new Workbook(this.options, this._view);
                this._controller = new Controller(this._view, this._workbook);
                this._autoRefresh = true;
                this._bindWorkbookEvents();
                this._view.workbook(this._workbook);
                this._view.enableClipboard(false);
                this.refresh();
                this._view.enableClipboard(true);
                this._resizeHandler = function () {
                    this.resize();
                }.bind(this);
                $(window).on('resize' + NS, this._resizeHandler);
                this.element.on('keydown' + NS, this._keyDown.bind(this));
            },
            _keyDown: function (e) {
                var key = e.keyCode;
                var redoTool = $('.k-spreadsheet-quick-access-toolbar [title=Redo]');
                if (key === keys.F11 && e.shiftKey) {
                    this._view.sheetsbar._onAddSelect();
                    e.preventDefault();
                    return;
                } else if (e.altKey && key === keys.PAGEDOWN) {
                    this._view.sheetsbar.trigger('select', {
                        name: this._view.sheetsbar._sheets[this._view.sheetsbar._selectedIndex + 1].name(),
                        isAddButton: false
                    });
                } else if (e.altKey && key === keys.PAGEUP) {
                    this._view.sheetsbar.trigger('select', {
                        name: this._view.sheetsbar._sheets[this._view.sheetsbar._selectedIndex - 1].name(),
                        isAddButton: false
                    });
                } else if (e.altKey && key === keys.DELETE) {
                    var closeCallback = function (e) {
                        var dlg = e.sender;
                        if (dlg.isConfirmed()) {
                            this._view.sheetsbar.trigger('remove', {
                                name: this.activeSheet()._name(),
                                confirmation: true
                            });
                        }
                    }.bind(this);
                    this._view.sheetsbar._openDialog('confirmation', { close: closeCallback });
                    e.preventDefault();
                    return;
                } else if (e.altKey && key === keys.R) {
                    this._view.sheetsbar._createEditor();
                    e.preventDefault();
                    return;
                } else if (key === keys.F10 && this._view.tabstrip || key === keys.TAB && !e.shiftKey && $(document.activeElement).is(redoTool)) {
                    this._view.tabstrip.toolbars[this._view.tabstrip.element.find('li.k-state-active').text().toLowerCase()].element.find(':not(.k-overflow-anchor):kendoFocusable:first').focus();
                    this._view.tabstrip.toolbars[this._view.tabstrip.element.find('li.k-state-active').text().toLowerCase()].element.find('.k-toolbar-first-visible').addClass('k-state-focused');
                    e.preventDefault();
                    return;
                } else if (e.ctrlKey && key === keys.B) {
                    $('[data-tool=bold]')[0].click();
                } else if (e.ctrlKey && key === keys.I) {
                    $('[data-tool=italic]')[0].click();
                } else if (e.ctrlKey && key === keys.U) {
                    $('[data-tool=underline]')[0].click();
                } else if (e.altKey && key === keys.H) {
                    this._view.tabstrip.select(0);
                    e.preventDefault();
                    return;
                } else if (e.altKey && key === keys.N) {
                    this._view.tabstrip.select(1);
                    e.preventDefault();
                    return;
                } else if (e.altKey && key === keys.A) {
                    this._view.tabstrip.select(2);
                    e.preventDefault();
                    return;
                }
            },
            _resize: function () {
                this.refresh({ layout: true });
            },
            _workbookChanging: function (e) {
                if (this.trigger('changing', e)) {
                    e.preventDefault();
                }
            },
            _workbookChange: function (e) {
                if (this._autoRefresh) {
                    this.refresh(e);
                }
                if (e.recalc && e.ref) {
                    var range = e.range || new kendo.spreadsheet.Range(e.ref, this.activeSheet());
                    this.trigger('change', { range: range });
                }
            },
            _workbookCut: function (e) {
                this.trigger('cut', e);
            },
            _workbookCopy: function (e) {
                this.trigger('copy', e);
            },
            _workbookPaste: function (e) {
                this.trigger('paste', e);
            },
            activeSheet: function (sheet) {
                return this._workbook.activeSheet(sheet);
            },
            moveSheetToIndex: function (sheet, index) {
                return this._workbook.moveSheetToIndex(sheet, index);
            },
            insertSheet: function (options) {
                return this._workbook.insertSheet(options);
            },
            sheets: function () {
                return this._workbook.sheets();
            },
            removeSheet: function (sheet) {
                return this._workbook.removeSheet(sheet);
            },
            sheetByName: function (sheetName) {
                return this._workbook.sheetByName(sheetName);
            },
            sheetIndex: function (sheet) {
                return this._workbook.sheetIndex(sheet);
            },
            sheetByIndex: function (index) {
                return this._workbook.sheetByIndex(index);
            },
            renameSheet: function (sheet, newSheetName) {
                return this._workbook.renameSheet(sheet, newSheetName);
            },
            refresh: function (reason) {
                if (!reason) {
                    reason = ALL_REASONS;
                }
                if (!reason.editorClose) {
                    this._view.sheet(this._workbook.activeSheet());
                    this._controller.sheet(this._workbook.activeSheet());
                    this._workbook.refresh(reason);
                }
                if (!reason.editorChange) {
                    this._view.refresh(reason);
                    this._controller.refresh();
                    this._view.render(reason);
                    this.trigger('render');
                }
                return this;
            },
            openDialog: function (name, options) {
                return this._view.openDialog(name, options);
            },
            autoRefresh: function (value) {
                if (value !== undefined) {
                    this._autoRefresh = value;
                    if (value === true) {
                        this.refresh();
                    }
                    return this;
                }
                return this._autoRefresh;
            },
            toJSON: function () {
                return this._workbook.toJSON();
            },
            fromJSON: function (json) {
                if (json.sheets) {
                    this._workbook.destroy();
                    this._workbook = new Workbook($.extend({}, this.options, json));
                    this._bindWorkbookEvents();
                    this._view.workbook(this._workbook);
                    this._controller.workbook(this._workbook);
                    this.activeSheet(this.activeSheet());
                } else {
                    this.refresh();
                }
            },
            saveJSON: function () {
                return this._workbook.saveJSON();
            },
            fromFile: function (blob, name) {
                return this._workbook.fromFile(blob, name);
            },
            saveAsPDF: function (options) {
                this._workbook.saveAsPDF($.extend({}, this.options.pdf, options, { workbook: this._workbook }));
            },
            saveAsExcel: function (options) {
                this._workbook.saveAsExcel(options);
            },
            draw: function (options, callback) {
                this._workbook.draw(options, callback);
            },
            _workbookExcelExport: function (e) {
                if (this.trigger('excelExport', e)) {
                    e.preventDefault();
                }
            },
            _workbookExcelImport: function (e) {
                if (this.trigger('excelImport', e)) {
                    e.preventDefault();
                } else {
                    this._initProgress(e.promise);
                }
            },
            _initProgress: function (deferred) {
                var loading = $('<div class=\'k-loading-mask\' ' + 'style=\'width: 100%; height: 100%; top: 0;\'>' + '<div class=\'k-loading-color\'/>' + '</div>').appendTo(this.element);
                var pb = $('<div class=\'k-loading-progress\'>').appendTo(loading).kendoProgressBar({
                    type: 'chunk',
                    chunkCount: 10,
                    min: 0,
                    max: 1,
                    value: 0
                }).data('kendoProgressBar');
                deferred.progress(function (e) {
                    pb.value(e.progress);
                }).always(function () {
                    kendo.destroy(loading);
                    loading.remove();
                });
            },
            _workbookPdfExport: function (e) {
                if (this.trigger('pdfExport', e)) {
                    e.preventDefault();
                }
            },
            _workbookInsertSheet: function (e) {
                if (this.trigger('insertSheet', e)) {
                    e.preventDefault();
                }
            },
            _workbookRemoveSheet: function (e) {
                if (this.trigger('removeSheet', e)) {
                    e.preventDefault();
                }
            },
            _workbookSelectSheet: function (e) {
                if (this.trigger('selectSheet', e)) {
                    e.preventDefault();
                }
            },
            _workbookRenameSheet: function (e) {
                if (this.trigger('renameSheet', e)) {
                    e.preventDefault();
                }
            },
            _workbookInsertRow: function (e) {
                if (this.trigger('insertRow', e)) {
                    e.preventDefault();
                }
            },
            _workbookInsertColumn: function (e) {
                if (this.trigger('insertColumn', e)) {
                    e.preventDefault();
                }
            },
            _workbookDeleteRow: function (e) {
                if (this.trigger('deleteRow', e)) {
                    e.preventDefault();
                }
            },
            _workbookDeleteColumn: function (e) {
                if (this.trigger('deleteColumn', e)) {
                    e.preventDefault();
                }
            },
            _workbookHideRow: function (e) {
                if (this.trigger('hideRow', e)) {
                    e.preventDefault();
                }
            },
            _workbookHideColumn: function (e) {
                if (this.trigger('hideColumn', e)) {
                    e.preventDefault();
                }
            },
            _workbookUnhideRow: function (e) {
                if (this.trigger('unhideRow', e)) {
                    e.preventDefault();
                }
            },
            _workbookUnhideColumn: function (e) {
                if (this.trigger('unhideColumn', e)) {
                    e.preventDefault();
                }
            },
            _workbookSelect: function (e) {
                this.trigger('select', e);
            },
            _workbookChangeFormat: function (e) {
                this.trigger('changeFormat', e);
            },
            _workbookDataBinding: function (e) {
                if (this.trigger('dataBinding', e)) {
                    e.preventDefault();
                }
            },
            _workbookDataBound: function (e) {
                this.trigger('dataBound', e);
            },
            _bindWorkbookEvents: function () {
                this._workbook.bind('cut', this._workbookCut.bind(this));
                this._workbook.bind('copy', this._workbookCopy.bind(this));
                this._workbook.bind('paste', this._workbookPaste.bind(this));
                this._workbook.bind('changing', this._workbookChanging.bind(this));
                this._workbook.bind('change', this._workbookChange.bind(this));
                this._workbook.bind('excelExport', this._workbookExcelExport.bind(this));
                this._workbook.bind('excelImport', this._workbookExcelImport.bind(this));
                this._workbook.bind('pdfExport', this._workbookPdfExport.bind(this));
                this._workbook.bind('insertSheet', this._workbookInsertSheet.bind(this));
                this._workbook.bind('removeSheet', this._workbookRemoveSheet.bind(this));
                this._workbook.bind('selectSheet', this._workbookSelectSheet.bind(this));
                this._workbook.bind('renameSheet', this._workbookRenameSheet.bind(this));
                this._workbook.bind('insertRow', this._workbookInsertRow.bind(this));
                this._workbook.bind('insertColumn', this._workbookInsertColumn.bind(this));
                this._workbook.bind('deleteRow', this._workbookDeleteRow.bind(this));
                this._workbook.bind('deleteColumn', this._workbookDeleteColumn.bind(this));
                this._workbook.bind('hideRow', this._workbookHideRow.bind(this));
                this._workbook.bind('hideColumn', this._workbookHideColumn.bind(this));
                this._workbook.bind('unhideRow', this._workbookUnhideRow.bind(this));
                this._workbook.bind('unhideColumn', this._workbookUnhideColumn.bind(this));
                this._workbook.bind('select', this._workbookSelect.bind(this));
                this._workbook.bind('changeFormat', this._workbookChangeFormat.bind(this));
                this._workbook.bind('dataBinding', this._workbookDataBinding.bind(this));
                this._workbook.bind('dataBound', this._workbookDataBound.bind(this));
            },
            destroy: function () {
                kendo.ui.Widget.fn.destroy.call(this);
                this._workbook.destroy();
                this._controller.destroy();
                this._view.destroy();
                if (this._resizeHandler) {
                    $(window).off('resize' + NS, this._resizeHandler);
                }
            },
            options: {
                name: 'Spreadsheet',
                toolbar: true,
                sheetsbar: true,
                rows: 200,
                columns: 50,
                rowHeight: 20,
                columnWidth: 64,
                headerHeight: 20,
                headerWidth: 32,
                excel: {
                    proxyURL: '',
                    fileName: 'Workbook.xlsx'
                },
                messages: {},
                pdf: {
                    area: 'workbook',
                    fileName: 'Workbook.pdf',
                    proxyURL: '',
                    paperSize: 'a4',
                    landscape: true,
                    margin: null,
                    title: null,
                    author: null,
                    subject: null,
                    keywords: null,
                    creator: 'Kendo UI PDF Generator v.' + kendo.version,
                    date: null
                },
                defaultCellStyle: {
                    fontFamily: 'Arial',
                    fontSize: '12'
                },
                useCultureDecimals: false
            },
            defineName: function (name, value, hidden) {
                return this._workbook.defineName(name, value, hidden);
            },
            undefineName: function (name) {
                return this._workbook.undefineName(name);
            },
            nameValue: function (name) {
                return this._workbook.nameValue(name);
            },
            forEachName: function (func) {
                return this._workbook.forEachName(func);
            },
            cellContextMenu: function () {
                return this._view.cellContextMenu;
            },
            rowHeaderContextMenu: function () {
                return this._view.rowHeaderContextMenu;
            },
            colHeaderContextMenu: function () {
                return this._view.colHeaderContextMenu;
            },
            addImage: function (image) {
                return this._workbook.addImage(image);
            },
            cleanupImages: function () {
                return this._workbook.cleanupImages();
            },
            events: [
                'cut',
                'copy',
                'paste',
                'pdfExport',
                'excelExport',
                'excelImport',
                'changing',
                'change',
                'render',
                'removeSheet',
                'selectSheet',
                'renameSheet',
                'insertRow',
                'insertColumn',
                'deleteRow',
                'insertSheet',
                'deleteColumn',
                'hideRow',
                'hideColumn',
                'unhideRow',
                'unhideColumn',
                'select',
                'changeFormat',
                'dataBinding',
                'dataBound'
            ]
        });
        kendo.spreadsheet.ALL_REASONS = ALL_REASONS;
        kendo.ui.plugin(Spreadsheet);
        $.extend(true, Spreadsheet, { classNames: classNames });
    }(window.kendo));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pivot.configurator', ['kendo.dom'], f);
}(function () {
    var __meta__ = {
        id: 'pivot.configurator',
        name: 'PivotConfigurator',
        category: 'web',
        depends: [
            'dropdownlist',
            'treeview',
            'pivot.fieldmenu'
        ],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, ns = '.kendoPivotConfigurator', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, SETTING_CONTAINER_TEMPLATE = kendo.template('<p class="k-reset"><span class="k-icon #=icon#"></span>${name}</p>' + '<div class="k-list-container k-reset"/>');
        function addKPI(data) {
            var found;
            var idx = 0;
            var length = data.length;
            for (; idx < length; idx++) {
                if (data[idx].type == 2) {
                    found = true;
                    break;
                }
            }
            if (found) {
                data.splice(idx + 1, 0, {
                    caption: 'KPIs',
                    defaultHierarchy: '[KPIs]',
                    name: 'KPIs',
                    uniqueName: '[KPIs]'
                });
            }
        }
        function kpiNode(node) {
            return {
                name: node.uniqueName,
                type: node.type
            };
        }
        function normalizeKPIs(data) {
            for (var idx = 0, length = data.length; idx < length; idx++) {
                data[idx].uniqueName = data[idx].name;
                data[idx].type = 'kpi';
            }
            return data;
        }
        function settingTargetFromNode(node) {
            var target = $(node).closest('.k-pivot-setting');
            if (target.length) {
                return target.data('kendoPivotSettingTarget');
            }
            return null;
        }
        var PivotConfigurator = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.element.addClass('k-widget k-fieldselector k-alt k-edit-form-container');
                this._dataSource();
                this._layout();
                this.refresh();
                kendo.notify(this);
            },
            events: [],
            options: {
                name: 'PivotConfigurator',
                filterable: false,
                sortable: false,
                messages: {
                    measures: 'Drop Data Fields Here',
                    columns: 'Drop Column Fields Here',
                    rows: 'Drop Rows Fields Here',
                    measuresLabel: 'Measures',
                    columnsLabel: 'Columns',
                    rowsLabel: 'Rows',
                    fieldsLabel: 'Fields'
                }
            },
            _dataSource: function () {
                var that = this;
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind('change', that._refreshHandler).unbind('error', that._errorHandler).unbind('progress', that._progressHandler);
                } else {
                    that._errorHandler = $.proxy(that._error, that);
                    that._refreshHandler = $.proxy(that.refresh, that);
                    that._progressHandler = $.proxy(that._requestStart, that);
                }
                that.dataSource = kendo.data.PivotDataSource.create(that.options.dataSource);
                that.dataSource.bind('change', that._refreshHandler).bind('error', that._errorHandler).bind('progress', that._progressHandler);
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                if (this.measures) {
                    this.measures.setDataSource(dataSource);
                }
                if (this.rows) {
                    this.rows.setDataSource(dataSource);
                }
                if (this.columns) {
                    this.columns.setDataSource(dataSource);
                }
                this.refresh();
            },
            _treeViewDataSource: function () {
                var that = this;
                return kendo.data.HierarchicalDataSource.create({
                    schema: {
                        model: {
                            id: 'uniqueName',
                            hasChildren: function (item) {
                                return !('hierarchyUniqueName' in item) && !('aggregator' in item);
                            }
                        }
                    },
                    transport: {
                        read: function (options) {
                            var promise;
                            var node;
                            var kpi;
                            if ($.isEmptyObject(options.data)) {
                                promise = that.dataSource.schemaDimensions();
                                promise.done(function (data) {
                                    if (!that.dataSource.cubeBuilder) {
                                        addKPI(data);
                                    }
                                    options.success(data);
                                }).fail(options.error);
                            } else {
                                node = that.treeView.dataSource.get(options.data.uniqueName);
                                if (node.uniqueName === '[KPIs]') {
                                    kpi = true;
                                    promise = that.dataSource.schemaKPIs();
                                    promise.done(function (data) {
                                        options.success(normalizeKPIs(data));
                                    }).fail(options.error);
                                } else if (node.type == 'kpi') {
                                    kpi = true;
                                    options.success(buildKPImeasures(node));
                                }
                                if (!kpi) {
                                    if (node.type == 2) {
                                        promise = that.dataSource.schemaMeasures();
                                    } else if (node.dimensionUniqueName) {
                                        promise = that.dataSource.schemaLevels(options.data.uniqueName);
                                    } else {
                                        promise = that.dataSource.schemaHierarchies(options.data.uniqueName);
                                    }
                                    promise.done(options.success).fail(options.error);
                                }
                            }
                        }
                    }
                });
            },
            _progress: function (toggle) {
                kendo.ui.progress(this.element, toggle);
            },
            _error: function () {
                this._progress(false);
            },
            _requestStart: function () {
                this._progress(true);
            },
            _layout: function () {
                this.form = $('<div class="k-columns k-state-default k-floatwrap"/>').appendTo(this.element);
                this._fields();
                this._targets();
            },
            _fields: function () {
                var container = $('<div class="k-state-default"><p class="k-reset"><span class="k-icon k-i-group"></span>' + this.options.messages.fieldsLabel + '</p></div>').appendTo(this.form);
                var template = '# if (item.type == 2 || item.uniqueName == "[KPIs]") { #' + '<span class="k-icon k-i-#= (item.type == 2 ? "sum" : "kpi") #"></span>' + '# } else if (item.type && item.type !== "kpi") { #' + '<span class="k-icon k-i-arrows-dimensions"></span>' + '# } #' + '#: item.caption || item.name #';
                this.treeView = $('<div/>').appendTo(container).kendoTreeView({
                    template: template,
                    dataTextField: 'caption',
                    dragAndDrop: true,
                    autoBind: false,
                    dataSource: this._treeViewDataSource(),
                    dragstart: function (e) {
                        var dataItem = this.dataItem(e.sourceNode);
                        if (!dataItem.hasChildren && !dataItem.aggregator && !dataItem.measure || dataItem.type == 2 || dataItem.uniqueName === '[KPIs]') {
                            e.preventDefault();
                        }
                    },
                    drag: function (e) {
                        var status = 'k-i-cancel';
                        var setting = settingTargetFromNode(e.dropTarget);
                        if (setting && setting.validate(this.dataItem(e.sourceNode))) {
                            status = 'k-i-plus';
                        }
                        e.setStatusClass(status);
                    },
                    drop: function (e) {
                        e.preventDefault();
                        var setting = settingTargetFromNode(e.dropTarget);
                        var node = this.dataItem(e.sourceNode);
                        var idx, length, measures;
                        var name;
                        if (setting && setting.validate(node)) {
                            name = node.defaultHierarchy || node.uniqueName;
                            if (node.type === 'kpi') {
                                measures = buildKPImeasures(node);
                                length = measures.length;
                                name = [];
                                for (idx = 0; idx < length; idx++) {
                                    name.push(kpiNode(measures[idx]));
                                }
                            } else if (node.kpi) {
                                name = [kpiNode(node)];
                            }
                            setting.add(name);
                        }
                    }
                }).data('kendoTreeView');
            },
            _createTarget: function (element, options) {
                var template = '<li class="k-item k-header" data-' + kendo.ns + 'name="${data.name}">${data.name}';
                var sortable = options.sortable;
                var icons = '';
                if (sortable) {
                    icons += '#if (data.sortIcon) {#';
                    icons += '<span class="k-icon ${data.sortIcon}-sm"></span>';
                    icons += '#}#';
                }
                if (options.filterable || sortable) {
                    icons += '<span class="k-icon k-i-more-vertical k-setting-fieldmenu"></span>';
                }
                icons += '<span class="k-icon k-i-close k-setting-delete"></span>';
                template += '<span class="k-field-actions">' + icons + '</span></li>';
                return new kendo.ui.PivotSettingTarget(element, $.extend({
                    dataSource: this.dataSource,
                    hint: function (element) {
                        var wrapper = $('<div class="k-fieldselector"><ul class="k-list k-reset"></ul></div>');
                        wrapper.find('.k-list').append(element.clone());
                        return wrapper;
                    },
                    template: template,
                    emptyTemplate: '<li class="k-item k-empty">${data}</li>'
                }, options));
            },
            _targets: function () {
                var container = $('<div class="k-state-default"/>').appendTo(this.form);
                var columnsContainer = $(SETTING_CONTAINER_TEMPLATE({
                    name: this.options.messages.columnsLabel,
                    icon: 'k-i-columns'
                })).appendTo(container);
                var columns = $('<ul class="k-pivot-configurator-settings k-list k-reset" />').appendTo(columnsContainer.last());
                var rowsContainer = $(SETTING_CONTAINER_TEMPLATE({
                    name: this.options.messages.rowsLabel,
                    icon: 'k-i-rows'
                })).appendTo(container);
                var rows = $('<ul class="k-pivot-configurator-settings k-list k-reset" />').appendTo(rowsContainer.last());
                var measuresContainer = $(SETTING_CONTAINER_TEMPLATE({
                    name: this.options.messages.measuresLabel,
                    icon: 'k-i-sum'
                })).appendTo(container);
                var measures = $('<ul class="k-pivot-configurator-settings k-list k-reset" />').appendTo(measuresContainer.last());
                var options = this.options;
                this.columns = this._createTarget(columns, {
                    filterable: options.filterable,
                    sortable: options.sortable,
                    connectWith: rows,
                    messages: {
                        empty: options.messages.columns,
                        fieldMenu: options.messages.fieldMenu
                    }
                });
                this.rows = this._createTarget(rows, {
                    filterable: options.filterable,
                    sortable: options.sortable,
                    setting: 'rows',
                    connectWith: columns,
                    messages: {
                        empty: this.options.messages.rows,
                        fieldMenu: this.options.messages.fieldMenu
                    }
                });
                this.measures = this._createTarget(measures, {
                    setting: 'measures',
                    messages: { empty: options.messages.measures }
                });
                columns.add(rows).add(measures).on(HOVEREVENTS, '.k-item:not(.k-empty)', this._toggleHover);
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass('k-state-hover', e.type === 'mouseenter');
            },
            _resize: function () {
                var element = this.element;
                var height = this.options.height;
                var border, fields;
                var outerHeight = kendo._outerHeight;
                if (!height) {
                    return;
                }
                element.height(height);
                if (element.is(':visible')) {
                    fields = element.children('.k-columns').children('div.k-state-default');
                    height = element.innerHeight();
                    border = (outerHeight(element) - height) / 2;
                    height = height - (outerHeight(fields, true) - fields.height()) - border;
                    fields.height(height);
                }
            },
            refresh: function () {
                var dataSource = this.dataSource;
                if (dataSource.cubeBuilder || this._cube !== dataSource.cube() || this._catalog !== dataSource.catalog()) {
                    this.treeView.dataSource.fetch();
                }
                this._catalog = this.dataSource.catalog();
                this._cube = this.dataSource.cube();
                this._resize();
                this._progress(false);
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.dataSource.unbind('change', this._refreshHandler);
                this.form.find('.k-list').off(ns);
                this.rows.destroy();
                this.columns.destroy();
                this.measures.destroy();
                this.treeView.destroy();
                this.element = null;
                this._refreshHandler = null;
            }
        });
        function kpiMeasure(name, measure, type) {
            return {
                hierarchyUniqueName: name,
                uniqueName: measure,
                caption: measure,
                measure: measure,
                name: measure,
                type: type,
                kpi: true
            };
        }
        function buildKPImeasures(node) {
            var name = node.name;
            return [
                kpiMeasure(name, node.value, 'value'),
                kpiMeasure(name, node.goal, 'goal'),
                kpiMeasure(name, node.status, 'status'),
                kpiMeasure(name, node.trend, 'trend')
            ];
        }
        ui.plugin(PivotConfigurator);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/ripple', ['kendo.core'], f);
}(function () {
    (function () {
        this.kendo.util = this.kendo.util || {};
        window.kendo.util.ripple = window.kendo.util.ripple || {};
        var closest = function (element, selector) {
            if (element.closest) {
                return element.closest(selector);
            }
            var matches = Element.prototype.matches ? function (el, sel) {
                return el.matches(sel);
            } : function (el, sel) {
                return el.msMatchesSelector(sel);
            };
            var node = element;
            while (node) {
                if (matches(node, selector)) {
                    return node;
                }
                node = node.parentElement;
            }
        };
        var createRipple = function (doc) {
            var ripple = doc.createElement('div');
            ripple.className = 'k-ripple';
            var blob = doc.createElement('div');
            blob.className = 'k-ripple-blob';
            ripple.appendChild(blob);
            return [
                ripple,
                blob
            ];
        };
        var once = function (element, eventName, fn) {
            var listener = function () {
                fn();
                element.removeEventListener(eventName, listener, false);
            };
            var remove = function () {
                return element.addEventListener(eventName, listener, false);
            };
            remove();
            return { remove: remove };
        };
        var activate = function (containerSelector, options) {
            return function (e) {
                var target = e.target;
                var doc = target.document || target.ownerDocument;
                var container;
                if (options.container) {
                    container = options.container(target);
                } else {
                    container = closest(target, containerSelector);
                }
                if (!container) {
                    return;
                }
                var doubleFocus = /focus/i.test(e.type) && container.classList.contains('k-ripple-target');
                if (doubleFocus) {
                    return;
                }
                container.classList.add('k-ripple-target');
                var _a = createRipple(doc), ripple = _a[0], blob = _a[1];
                var state = {
                    animated: false,
                    released: false,
                    blob: blob,
                    container: container,
                    ripple: ripple
                };
                var eventType = {
                    'focusin': 'focusout',
                    'keydown': 'keyup',
                    'mousedown': 'mouseup',
                    'pointerdown': 'pointerup',
                    'touchdown': 'touchup'
                }[e.type];
                once(e.currentTarget, eventType, function () {
                    return release(state);
                });
                container.appendChild(ripple);
                window.getComputedStyle(ripple).getPropertyValue('opacity');
                var rect = container.getBoundingClientRect();
                var left = 0;
                var top = 0;
                if (/mouse|pointer|touch/.test(e.type)) {
                    left = e.clientX - rect.left;
                    top = e.clientY - rect.top;
                } else {
                    left = rect.width / 2;
                    top = rect.height / 2;
                }
                var xMax = left < rect.width / 2 ? rect.width : 0;
                var yMax = top < rect.height / 2 ? rect.height : 0;
                var dx = left - xMax;
                var dy = top - yMax;
                var size = 2 * Math.sqrt(dx * dx + dy * dy);
                var duration = 500;
                blob.style.width = blob.style.height = size + 'px';
                if (blob.offsetWidth < 0) {
                    throw new Error('Inconceivable!');
                }
                blob.style.cssText = '\n    width: ' + size + 'px;\n    height: ' + size + 'px;\n    transform: translate(-50%, -50%) scale(1);\n    left: ' + left + 'px;\n    top: ' + top + 'px;\n  ';
                setTimeout(function () {
                    return finishAnimation(state);
                }, duration);
            };
        };
        var finishAnimation = function (state) {
            state.animated = true;
            deactivate(state);
        };
        var release = function (state) {
            state.released = true;
            deactivate(state);
        };
        var deactivate = function (state) {
            if (!state.released || !state.animated) {
                return;
            }
            var blob = state.blob, ripple = state.ripple, container = state.container;
            if (container) {
                once(container, 'blur', function () {
                    return container.classList.remove('k-ripple-target');
                });
            }
            if (blob) {
                once(blob, 'transitionend', function () {
                    if (ripple && ripple.parentNode) {
                        ripple.parentNode.removeChild(ripple);
                    }
                });
                blob.style.transition = 'opacity 200ms linear';
                blob.style.opacity = '0';
            }
        };
        var register = function (root, elements) {
            var flatten = function (arr) {
                return [].concat.apply([], arr);
            };
            var handlers = flatten(elements.map(function (item) {
                var defaultOptions = {
                    events: [
                        'mousedown',
                        'touchdown'
                    ],
                    global: false
                };
                var selector = item.selector, _a = item.options, options = _a === void 0 ? defaultOptions : _a;
                var activator = activate(selector, options);
                var events = options.events || defaultOptions.events;
                var container = options.global ? document.body : root;
                events.forEach(function (evt) {
                    return container.addEventListener(evt, activator, false);
                });
                return {
                    events: events,
                    options: options,
                    activator: activator
                };
            }));
            return function () {
                if (!root) {
                    return;
                }
                var removeListener = function (_a) {
                    var events = _a.events, options = _a.options, activator = _a.activator;
                    var container = options.global ? document.body : root;
                    events.forEach(function (evt) {
                        return container.removeEventListener(evt, activator, false);
                    });
                };
                handlers.forEach(removeListener);
                root = null;
            };
        };
        kendo.deepExtend(kendo.util.ripple, { register: register });
    }());
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.ripple', ['util/ripple'], f);
}(function () {
    var __meta__ = {
        id: 'ripplecontainer',
        name: 'RippleContainer',
        category: 'web',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, extend = $.extend, ripple = kendo.util.ripple;
        var RippleContainer = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element);
                element = that.wrapper = that.element;
                that.options = extend({}, that.options, options);
                that.registerListeners();
            },
            options: {
                name: 'RippleContainer',
                elements: [
                    { selector: '.k-button:not(li)' },
                    {
                        selector: '.k-list > .k-item',
                        options: { global: true }
                    },
                    { selector: '.k-checkbox-label, .k-radio-label' },
                    {
                        selector: '.k-checkbox, .k-radio',
                        options: {
                            events: ['focusin'],
                            container: function (el) {
                                if (/\b(k-checkbox|k-radio)\b/.test(el.className)) {
                                    return el.nextElementSibling;
                                }
                            }
                        }
                    }
                ]
            },
            removeListeners: function () {
            },
            registerListeners: function () {
                var that = this;
                var root = that.element[0];
                var elements = that.options.elements;
                that.removeListeners();
                var callback = ripple.register(root, elements);
                that.removeListeners = callback;
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.removeListeners();
            }
        });
        ui.plugin(RippleContainer);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf-viewer/pdfjs', ['kendo.core'], f);
}(function () {
    (function ($, undefined) {
        var extend = $.extend;
        var isLoaded = function () {
            if (!window.pdfjsLib) {
                var console = window.console;
                if (console && console.error) {
                    console.error('PDF.JS required.');
                }
                return false;
            }
            kendo.pdfviewer.pdfjs.lib = window.pdfjsLib;
            return true;
        };
        extend(kendo, {
            pdfviewer: {
                pdfjs: {
                    lib: window.pdfjsLib,
                    isLoaded: isLoaded
                }
            }
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf-viewer/processors/pdfjs-processor', [
        'pdf-viewer/pdfjs',
        'kendo.core'
    ], f);
}(function () {
    var __meta__ = {
        id: 'pdfjs-processor',
        name: 'PDFJS-Processor',
        category: 'framework',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Class = kendo.Class, extend = $.extend, atob = window.atob, PDFJS;
        var PDFJSProcessor = Class.extend({
            init: function (options, viewer) {
                var that = this;
                if (kendo.pdfviewer.pdfjs.isLoaded()) {
                    PDFJS = kendo.pdfviewer.pdfjs.lib;
                }
                that.file = options.file;
                that.viewer = viewer;
            },
            fetchDocument: function () {
                var that = this, deferred = $.Deferred(), messages = that.viewer.options.messages.errorMessages;
                if (!that.file) {
                    return deferred.resolve();
                }
                if (that._isBase64Data() && atob) {
                    that.file.data = atob(that.file.data);
                }
                PDFJS.getDocument(this.file).promise.then(function (pdf) {
                    var pageSizes = [];
                    that.pdf = pdf;
                    that.pagePromises = [];
                    that._downloadData = $.Deferred();
                    pdf.getData().then(function (data) {
                        var blob = new Blob([data], { type: 'application/pdf' });
                        that._downloadData.resolve({ file: blob });
                    });
                    for (var i = 1; i <= pdf.numPages; i++) {
                        that.pagePromises.push(pdf.getPage(i));
                    }
                    Promise.all(that.pagePromises).then(function (pagePromises) {
                        pageSizes = pagePromises.map(function (pagePromise) {
                            var viewport = pagePromise.getViewport({ scale: 4 / 3 });
                            return {
                                width: viewport.width,
                                height: viewport.height
                            };
                        });
                        deferred.resolve({
                            total: pdf.numPages,
                            pages: pageSizes
                        });
                    }).catch(function (e) {
                        that.viewer._triggerError({
                            error: e.message,
                            message: messages.parseError
                        });
                    });
                }).catch(function (e) {
                    var notFoundError = e.name.includes('Missing');
                    var alertMessage = notFoundError ? messages.notFound : messages.parseError;
                    that.viewer._triggerError({
                        error: e.message,
                        message: alertMessage
                    });
                    if (notFoundError) {
                        that.viewer._renderBlankPage();
                    }
                });
                return deferred;
            },
            fetchPageData: function (number) {
                return this.pagePromises[number - 1];
            },
            downloadFile: function (fileName) {
                var that = this;
                kendo.ui.progress(that.viewer.pageContainer, true);
                that._downloadData.done(function (result) {
                    kendo.ui.progress(that.viewer.pageContainer, false);
                    kendo.saveAs({
                        dataURI: result.file,
                        fileName: fileName + '.pdf'
                    });
                });
            },
            _updateDocument: function (file) {
                this.file = file;
            },
            _isBase64Data: function () {
                var data = this.file.data, notBase64 = /[^A-Z0-9+\/=]/i, length = data && data.length, equalSign;
                if (!length || length % 4 !== 0 || notBase64.test(data)) {
                    return false;
                }
                equalSign = data.indexOf('=');
                return equalSign === -1 || equalSign === length - 1 || equalSign === length - 2 && data[length - 1] === '=';
            }
        });
        extend(kendo.pdfviewer.pdfjs, { processor: PDFJSProcessor });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf-viewer/processors/dpl-processor', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'dpl-processor',
        name: 'DPL-Processor',
        category: 'framework',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, Class = kendo.Class;
        var DPLProcessor = Class.extend({
            init: function (options, viewer) {
                var that = this;
                that.options = options;
                that.read = options.read;
                that.upload = options.upload;
                that.download = options.download;
                that.viewer = viewer;
            },
            fetchDocument: function () {
                var that = this, deferred = $.Deferred(), errorMessages = that.viewer.options.messages.errorMessages;
                if (!that.read) {
                    return deferred.resolve();
                }
                $.ajax({
                    type: that.read.type,
                    url: that.read.url,
                    dataType: that.read.dataType,
                    success: function (data) {
                        if (typeof data != 'string') {
                            data = kendo.stringify(data);
                        }
                        deferred.resolve(JSON.parse(data));
                    },
                    error: function (xhr) {
                        that.viewer._triggerError({
                            error: xhr.responseText,
                            message: errorMessages.parseError
                        });
                    }
                });
                return deferred;
            },
            fetchPageData: function (number) {
                var that = this;
                var deferred = $.Deferred();
                var page = that.viewer.document.pages[number - 1];
                var data = {};
                data[that.read.pageField] = number;
                if (!page.geometries.length) {
                    $.ajax({
                        type: that.read.type,
                        url: that.read.url,
                        data: data,
                        success: function (data) {
                            deferred.resolve(JSON.parse(data));
                        },
                        error: function (xhr) {
                            that.viewer._triggerError({
                                error: xhr.responseText,
                                message: that.viewer.options.messages.errorMessages.parseError
                            });
                        }
                    });
                } else {
                    deferred.resolve(page);
                }
                return deferred;
            },
            downloadFile: function (fileName) {
                window.location = this.download.url + '?file=' + fileName;
            },
            fromJSON: function (json) {
                var viewer = this.viewer;
                viewer._clearPages();
                viewer.document = json;
                viewer.document.total = viewer.document.pages.length;
                viewer._renderPages();
                viewer.resize(true);
                viewer.activatePage(1);
            }
        });
        extend(kendo.pdfviewer, { dpl: { processor: DPLProcessor } });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf-viewer/pager', ['kendo.core'], f);
}(function () {
    (function ($, undefined) {
        var NS = '.kendoPDFViewer', Widget = kendo.ui.Widget, CHANGE = 'change', KEYDOWN = 'keydown', CLICK = kendo.support.click, SHRINKWIDTH = 480, kendoAttr = kendo.attr, proxy = $.proxy, extend = $.extend, DOT = '.';
        var pagerStyles = {
            wrapperClass: 'k-pager-wrap',
            iconFirst: 'k-i-arrow-end-left',
            iconLast: 'k-i-arrow-end-right',
            iconPrev: 'k-i-arrow-60-left',
            iconNext: 'k-i-arrow-60-right',
            first: 'k-pager-first',
            last: 'k-pager-last',
            nav: 'k-pager-nav',
            disabled: 'k-state-disabled'
        };
        var Pager = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.linkTemplate = kendo.template(that.options.linkTemplate);
                that.element.addClass(pagerStyles.wrapperClass);
                that._renderLinks();
                that._toggleDisabledClass();
                that._attachEvents();
            },
            options: {
                linkTemplate: '<a href="\\#" aria-label="#=text#" title="#=text#" class="k-button k-button-icon k-flat k-pager-nav #= wrapClass #" data-page="#=pageIdx#"><span class="k-icon #= iconClass #"></span></a>',
                previousNext: true,
                input: true,
                page: 1,
                total: 1,
                messages: {}
            },
            events: [CHANGE],
            _pagerLink: function (iconClass, text, pageIdx, wrapClass) {
                return this.linkTemplate({
                    iconClass: iconClass,
                    text: text,
                    wrapClass: wrapClass || '',
                    pageIdx: pageIdx
                });
            },
            _renderLinks: function () {
                var that = this, options = that.options;
                if (options.previousNext) {
                    that.firstLink = $(that._pagerLink(pagerStyles.iconFirst, options.messages.first, 1, pagerStyles.first));
                    that.prevLink = $(that._pagerLink(pagerStyles.iconPrev, options.messages.previous, options.page - 1));
                    that.nextLink = $(that._pagerLink(pagerStyles.iconNext, options.messages.next, options.page + 1));
                    that.lastLink = $(that._pagerLink(pagerStyles.iconLast, options.messages.last, options.total, pagerStyles.last));
                }
                that.element.append(that.firstLink);
                that.element.append(that.prevLink);
                if (options.input) {
                    that._renderInput();
                }
                that.element.append(that.nextLink);
                that.element.append(that.lastLink);
            },
            _toggleDisabledClass: function () {
                var that = this, options = that.options, total = !options.total;
                if (that.nextLink && that.prevLink) {
                    that.prevLink.toggleClass(pagerStyles.disabled, total || options.page === 1);
                    that.nextLink.toggleClass(pagerStyles.disabled, total || options.page === options.total);
                    that.lastLink.toggleClass(pagerStyles.disabled, total || options.page === options.total);
                    that.firstLink.toggleClass(pagerStyles.disabled, total || options.page === 1);
                }
                if (that.input) {
                    that.input.toggleClass(pagerStyles.disabled, options.total <= 1);
                }
            },
            _attachEvents: function () {
                var that = this;
                that.element.on(CLICK + NS, DOT + pagerStyles.nav, proxy(that._click, that));
                that.element.on(KEYDOWN + NS, DOT + pagerStyles.nav, function (e) {
                    if (e.keyCode === kendo.keys.ENTER) {
                        that._click(e);
                        e.preventDefault();
                    }
                });
                if (that.input) {
                    that.input.on(KEYDOWN + NS, proxy(that._keydown, that));
                }
            },
            _click: function (e) {
                var target = $(e.currentTarget);
                var page = parseInt(target.attr(kendoAttr('page')), 10);
                if (e.isDefaultPrevented()) {
                    return;
                }
                this._change(page);
            },
            _keydown: function (e) {
                var key = e.keyCode, keys = kendo.keys, input = $(e.target), page = parseInt(input.val(), 10), upDown = key === keys.UP || key === keys.DOWN, allowedKeys = key === keys.RIGHT || key === keys.LEFT || key === keys.BACKSPACE || key === keys.DELETE, direction = upDown && key === keys.UP ? 1 : -1;
                if (upDown) {
                    page += direction;
                }
                if (key === keys.ENTER || upDown) {
                    if (isNaN(page) || page < 1 || page > this.options.total) {
                        page = this.options.page;
                        input.val(page);
                        return;
                    }
                    this._change(page);
                    e.preventDefault();
                } else if (!e.key.match(/^\d+$/) && !allowedKeys) {
                    e.preventDefault();
                }
            },
            _change: function (page) {
                var that = this;
                if (page >= 1 && page <= that.options.total) {
                    that.options.page = page;
                    if (that.input) {
                        that.input.val(page);
                    }
                    that.prevLink.attr(kendoAttr('page'), page - 1);
                    that.nextLink.attr(kendoAttr('page'), page + 1);
                    that._toggleDisabledClass();
                }
                that.trigger(CHANGE, { page: page });
            },
            setOptions: function (options) {
                var that = this, prevTotal = that.options.total;
                options = $.extend(that.options, options);
                Widget.fn.setOptions.call(that, options);
                if (options.input) {
                    if (prevTotal != options.total) {
                        that._renderInput();
                        that.input.on(KEYDOWN + NS, proxy(that._keydown, that));
                    } else {
                        that.input.val(options.total > 0 ? options.page : 1);
                    }
                }
                if (options.total > 1) {
                    that.prevLink.attr(kendoAttr('page'), options.page - 1);
                    that.nextLink.attr(kendoAttr('page'), options.page + 1);
                    that.lastLink.attr(kendoAttr('page'), options.total);
                }
                that._toggleDisabledClass();
            },
            _renderInput: function () {
                var that = this, totalMessage, options = that.options, shouldShrink = that.element.parent().width() <= SHRINKWIDTH, inputTemplate, pagerInputWrap = that.element.find('.k-pager-input');
                if (that.input) {
                    that.input.off(NS);
                }
                totalMessage = options.total > 0 ? kendo.format(options.messages.of, options.total) : '';
                if (!shouldShrink) {
                    totalMessage += options.total > 1 ? options.messages.pages : options.messages.page;
                }
                inputTemplate = '<input class="k-textbox" aria-label="' + options.page + totalMessage + '">' + totalMessage;
                if (pagerInputWrap.length) {
                    pagerInputWrap.html(inputTemplate);
                } else {
                    that.element.append('<span class="k-pager-input k-label">' + inputTemplate + '</span>');
                }
                that.input = that.element.find('input').val(options.total > 0 ? options.page : 1);
            },
            destroy: function () {
                this.element.off(NS);
                if (this.input) {
                    this.input.off(NS);
                }
                Widget.fn.destroy.call(this);
            }
        });
        extend(kendo.pdfviewer, { Pager: Pager });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf-viewer/toolbar', [
        'kendo.core',
        'kendo.toolbar',
        'pdf-viewer/pager'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, proxy = $.proxy, ACTION = 'action', FLATBUTTONCLASS = 'k-flat', KEYDOWN = 'keydown', Item = kendo.toolbar.Item, ToolBar = kendo.ui.ToolBar;
        var DefaultTools = {
            pager: {
                type: 'pager',
                overflow: 'never',
                command: 'PageChangeCommand'
            },
            spacer: { type: 'spacer' },
            open: {
                type: 'button',
                text: 'Open',
                showText: 'overflow',
                name: 'open',
                icon: 'folder-open',
                command: 'OpenCommand'
            },
            download: {
                type: 'button',
                text: 'Download',
                showText: 'overflow',
                name: 'download',
                icon: 'download',
                command: 'DownloadCommand'
            }
        };
        var AllTools = extend({}, DefaultTools, {
            exportAs: {
                type: 'button',
                text: 'Export',
                showText: 'overflow',
                name: 'exportAs',
                icon: 'image-export',
                command: 'ExportCommand'
            }
        });
        var ToolbarPager = Item.extend({
            init: function (options, toolbar) {
                var pagerElement = $('<div />');
                this.options = extend(true, options, toolbar.options.pager);
                this.toolbar = toolbar;
                this.toolbar.pager = new kendo.pdfviewer.Pager(pagerElement, extend({}, options, { change: proxy(this._change, this) }));
                this.element = pagerElement;
                this.element.on(KEYDOWN, proxy(this._keydown, this));
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
            },
            _change: function (e) {
                if (this.options.change && this.options.change(e.page)) {
                    return;
                }
                this.toolbar.action({
                    command: 'PageChangeCommand',
                    options: { value: e.page }
                });
            },
            _keydown: function (e) {
                var that = this, target = $(e.target), keyCode = e.keyCode, children = that.element.find(':kendoFocusable'), targetIndex = children.index(target), direction = e.shiftKey ? -1 : 1;
                if (keyCode === kendo.keys.TAB && children[targetIndex + direction]) {
                    children[targetIndex + direction].focus();
                    e.preventDefault();
                    e.stopPropagation();
                }
            }
        });
        kendo.toolbar.registerComponent('pager', ToolbarPager);
        var ViewerToolBar = ToolBar.extend({
            init: function (element, options) {
                var that = this;
                var items = options.items && options.items.length ? options.items : Object.keys(DefaultTools);
                that.options = options;
                options.items = that._updateItems(items);
                ToolBar.fn.init.call(that, element, options);
                that.bind({ click: that._click });
            },
            events: [ACTION],
            _updateItems: function (items) {
                var messages = this.options.messages;
                return items.map(function (tool) {
                    var toolOptions = $.isPlainObject(tool) ? tool : AllTools[tool];
                    var options;
                    var toolName = toolOptions.name;
                    if (toolOptions.type != 'pager') {
                        options = {
                            name: toolName,
                            attributes: {
                                'aria-label': messages[toolName],
                                'title': messages[toolName],
                                'data-command': toolOptions.command,
                                'class': FLATBUTTONCLASS
                            },
                            overflow: toolOptions.overflow
                        };
                    } else {
                        options = { overflow: 'never' };
                    }
                    kendo.deepExtend(toolOptions, options);
                    return toolOptions;
                });
            },
            _click: function (e) {
                var command = $(e.target).data('command');
                if (!command) {
                    return;
                }
                this.action({
                    command: command,
                    options: e.options
                });
            },
            action: function (args) {
                this.trigger(ACTION, args);
            },
            destroy: function () {
                if (this.pager) {
                    this.pager.destroy();
                }
                ToolBar.fn.destroy.call(this);
            }
        });
        extend(kendo.pdfviewer, {
            Toolbar: ViewerToolBar,
            DefaultTools: DefaultTools
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf-viewer/page', ['kendo.drawing'], f);
}(function () {
    (function ($, undefined) {
        var extend = $.extend, drawing = kendo.drawing, Group = drawing.Group, Surface = drawing.Surface, RENDER = 'render', Class = kendo.Class;
        var geometryTypes = {
            Path: 'path',
            MultiPath: 'multipath',
            Rect: 'rect',
            Image: 'image',
            Text: 'text'
        };
        var Page = Class.extend({
            init: function (options, viewer) {
                this.viewer = viewer;
                this.processor = options.processor;
                this.options = options;
                this.pageNumber = options.number;
                this.element = $('<div class=\'k-page\' />');
                this.element.attr(kendo.attr('number'), this.pageNumber);
                this._updatePageSize(options);
                this.width = options.width;
                this.height = options.height;
            },
            resize: function (ratio) {
                var pageElement = this.element;
                this._updatePageSize({
                    width: Math.min(pageElement.width() * ratio, this.width),
                    height: Math.min(pageElement.height() * ratio, this.height)
                });
            },
            _updatePageSize: function (size) {
                this.element.width(size.width).height(size.height);
            },
            destroy: function () {
                kendo.destroy(this.element);
            }
        });
        var DPLPage = Page.extend({
            draw: function () {
                var that = this, geometries = that.options.geometries;
                that.group = new Group();
                that.surface.draw(that.group);
                that._drawGeometries(geometries);
                that.viewer.trigger(RENDER, { page: this });
                kendo.ui.progress(that.element, false);
            },
            load: function () {
                var that = this;
                if (that.loaded || !that.processor) {
                    return;
                }
                that.processor.fetchPageData(that.pageNumber).then(function (data) {
                    that.options = data;
                    that._initSurface();
                    that.draw();
                });
                that.loaded = true;
            },
            _initSurface: function () {
                var size = {
                    width: this.element.width(),
                    height: this.element.height()
                };
                var surfaceOptions = extend({
                    width: this.width,
                    height: this.height
                }, this.viewer.options.view);
                this.surface = new Surface(this.element, surfaceOptions);
                this._updatePageSize(size);
            },
            _drawGeometries: function (geometries) {
                var that = this, kGeometry;
                if (!geometries) {
                    return;
                }
                for (var i = 0; i <= geometries.length; i++) {
                    var geometry = geometries[i];
                    if (!geometry) {
                        continue;
                    }
                    switch (geometry.type) {
                    case geometryTypes.Path:
                    case geometryTypes.MultiPath:
                        kGeometry = that._drawPath(geometry);
                        break;
                    case geometryTypes.Rect:
                        kGeometry = that._drawRect(geometry);
                        break;
                    case geometryTypes.Image:
                        kGeometry = that._drawImage(geometry);
                        break;
                    case geometryTypes.Text:
                        kGeometry = that._drawText(geometry);
                        break;
                    default:
                        kGeometry = null;
                        break;
                    }
                    if (kGeometry) {
                        that.group.append(kGeometry);
                    }
                }
            },
            _drawRect: function (geometry) {
                var rectGeo = new kendo.geometry.Rect(geometry.point, geometry.size);
                return new drawing.Rect(rectGeo, {
                    transform: this._getMatrix(geometry.transform),
                    fill: geometry.fillOptions,
                    stroke: geometry.strokeOptions
                });
            },
            _drawImage: function (geometry) {
                var imageRect = new kendo.geometry.Rect(geometry.point, geometry.size);
                return new drawing.Image(geometry.src, imageRect, { transform: this._getMatrix(geometry.transform) });
            },
            _drawText: function (geometry) {
                var options = {
                    transform: this._getMatrix(geometry.transform),
                    stroke: geometry.strokeOptions,
                    fill: geometry.fillOptions,
                    font: geometry.font
                };
                return new kendo.drawing.Text(geometry.content, geometry.point, options);
            },
            _drawPath: function (geometry) {
                var options = {
                    transform: this._getMatrix(geometry.transform),
                    stroke: geometry.strokeOptions,
                    fill: geometry.fillOptions
                };
                var path = new drawing.MultiPath(options);
                for (var i = 0; i < geometry.paths.length; i++) {
                    var subPath = geometry.paths[i];
                    if (!subPath.segments) {
                        return;
                    }
                    path.moveTo.apply(path, subPath.point);
                    for (var j = 0; j < subPath.segments.length; j++) {
                        var segment = subPath.segments[j];
                        var drawAction = segment.points.length === 1 ? path.lineTo : path.curveTo;
                        drawAction.apply(path, segment.points);
                    }
                    if (subPath.closed) {
                        path.close();
                    }
                }
                return path;
            },
            _getMatrix: function (transform) {
                var matrix = Object.create(kendo.geometry.Matrix.prototype);
                kendo.geometry.Matrix.apply(matrix, transform);
                return matrix;
            }
        });
        var PDFJSPage = Page.extend({
            init: function (options, viewer) {
                var that = this, canvas;
                canvas = $('<canvas style=\'width: 100%; height: 100%;\' />');
                that.canvas = canvas.get(0);
                Page.fn.init.call(that, options, viewer);
                that.canvas.width = that.width;
                that.canvas.height = that.height;
                that.element.append(canvas);
            },
            load: function () {
                var that = this;
                if (that.loaded) {
                    return;
                }
                if (that.processor) {
                    that.processor.fetchPageData(that.pageNumber).then(function (page) {
                        return page.render({
                            canvasContext: that.canvas.getContext('2d'),
                            viewport: page.getViewport({ scale: 4 / 3 })
                        }).promise.then(function () {
                            that.viewer.trigger(RENDER, { page: that });
                        });
                    });
                }
                that.loaded = true;
            }
        });
        extend(kendo.pdfviewer.dpl, {
            geometryTypes: geometryTypes,
            Page: DPLPage
        });
        extend(kendo.pdfviewer.pdfjs, { Page: PDFJSPage });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf-viewer/dialogs', ['kendo.core'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, Class = kendo.Class, EXTENSIONS = {
                svg: '.svg',
                png: '.png'
            };
        var ErrorDialog = Class.extend({
            init: function (options) {
                this.options = extend(options, { actions: [{ text: options.messages.dialogs.okText }] });
                this._dialog = $('<div />').kendoDialog(this.options).getKendoDialog();
            },
            open: function () {
                this._dialog.center().open();
            }
        });
        var ExportAsDialog = Class.extend({
            init: function (options) {
                this.options = extend(options, this.options, {
                    fileFormats: [
                        {
                            description: options.messages.dialogs.exportAsDialog.png,
                            extension: EXTENSIONS.png
                        },
                        {
                            description: options.messages.dialogs.exportAsDialog.svg,
                            extension: EXTENSIONS.svg
                        }
                    ],
                    title: options.messages.dialogs.exportAsDialog.title,
                    open: function () {
                        this.center();
                    }
                });
                this._initializeDialog();
                return this;
            },
            options: {
                extension: EXTENSIONS.png,
                autoFocus: true,
                resizable: false,
                modal: { preventScroll: true },
                width: '90%',
                maxWidth: 520,
                template: '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.fileName #:</label></div>' + '<div class=\'k-edit-field\'>' + '<input class=\'k-textbox\' data-bind=\'value: name\' />' + '</div>' + '<div>' + '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.saveAsType #:</label></div>' + '<div class=\'k-edit-field\'>' + '<select data-role=\'dropdownlist\' class=\'k-file-format\' ' + 'data-text-field=\'description\' ' + 'data-value-field=\'extension\' ' + 'data-bind=\'value: extension, source: fileFormats\' />' + '</div>' + '</div>' + '<div class=\'k-edit-label\'><label>#: messages.exportAsDialog.labels.page #:</label></div>' + '<div class=\'k-edit-field\'>' + '<input data-role=\'numerictextbox\' data-format=\'n0\' data-min=\'1\' data-max=\'#: total #\' data-bind=\'value: page\' />' + '</div>' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: apply\'>#: messages.save #</button>' + '<button class=\'k-button\' data-bind=\'click: close\'>#: messages.cancel #</button>' + '</div>'
            },
            _updateModel: function (options) {
                if (options.pagesCount) {
                    this.viewModel.set('pagesCount', options.pagesCount);
                }
                if (options.page) {
                    this.viewModel.set('page', options.page);
                }
            },
            _initializeDialog: function () {
                var that = this;
                var options = that.options;
                var dialogMessages = options.messages.dialogs;
                var dialog = $('<div class=\'k-pdf-viewer-window k-action-window k-popup-edit-form\' />').append(kendo.template(options.template)({
                    total: options.pagesCount,
                    messages: dialogMessages
                })).kendoWindow(options).getKendoWindow();
                that.viewModel = kendo.observable({
                    title: dialogMessages.exportAsDialog.title,
                    name: dialogMessages.exportAsDialog.defaultFileName,
                    extension: options.extension,
                    fileFormats: options.fileFormats,
                    pagesCount: options.pagesCount,
                    page: 1,
                    apply: that.apply.bind(this),
                    close: function () {
                        dialog.close();
                    }
                });
                that._dialog = dialog;
                kendo.bind(dialog.element, that.viewModel);
                return dialog;
            },
            open: function () {
                this._dialog.center().open();
            },
            apply: function () {
                this._dialog.close();
                this.options.apply({
                    fileName: this.viewModel.name + this.viewModel.extension,
                    extension: this.viewModel.extension,
                    page: this.viewModel.page
                });
            }
        });
        extend(kendo.pdfviewer, {
            dialogs: {
                ErrorDialog: ErrorDialog,
                ExportAsDialog: ExportAsDialog
            }
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf-viewer/commands', ['kendo.core'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, proxy = $.proxy, extend = $.extend, parseJSON = $.parseJSON, progress = kendo.ui.progress, Class = kendo.Class, OPEN = 'open';
        var Command = Class.extend({
            init: function (options) {
                this.options = options;
                this.viewer = options.viewer;
                this.errorMessages = this.viewer.options.messages.errorMessages;
            }
        });
        var OpenCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this.upload = this.viewer.processor.upload;
            },
            exec: function () {
                (this.viewer._upload || this._initUpload()).element.click();
            },
            _initUpload: function () {
                var uploadOptions = {
                    select: proxy(this._onSelect, this),
                    success: proxy(this._onSuccess, this),
                    error: proxy(this._onError, this),
                    complete: proxy(this._onComplete, this),
                    showFileList: false,
                    multiple: false,
                    validation: { allowedExtensions: ['.pdf'] }
                };
                if (this.upload) {
                    extend(uploadOptions, {
                        async: {
                            saveUrl: this.upload.url,
                            autoUpload: true,
                            saveField: this.upload.saveField
                        }
                    });
                }
                var upload = $('<input name="files" accept=".pdf" type="file" />').kendoUpload(uploadOptions).getKendoUpload();
                this.viewer._upload = upload;
                return upload;
            },
            _onComplete: function () {
                progress(this.viewer.pageContainer, false);
            },
            _onSuccess: function (e) {
                var json = parseJSON(e.response);
                if ($.isPlainObject(json)) {
                    this.viewer.processor.fromJSON(json);
                } else {
                    this.viewer._triggerError({
                        error: json,
                        message: this.errorMessages.parseError
                    });
                }
            },
            _onError: function (e) {
                this.viewer._triggerError({
                    error: e.XMLHttpRequest.responseText,
                    message: this.errorMessages.notSupported
                });
            },
            _onSelect: function (e) {
                var that = this;
                var fileToUpload = e.files[0];
                progress(that.viewer.pageContainer, true);
                if (that.viewer.trigger(OPEN, { file: fileToUpload }) || that.upload) {
                    return;
                } else if (fileToUpload.extension.toLowerCase() !== '.pdf') {
                    that.viewer._triggerError({
                        error: fileToUpload,
                        message: that.errorMessages.notSupported
                    });
                    return;
                }
                var reader = new FileReader();
                reader.onload = function (e) {
                    var document = e.target.result;
                    that.viewer.fromFile(document);
                };
                reader.onerror = function () {
                    that.viewer._triggerError({
                        error: fileToUpload,
                        message: that.errorMessages.parseError
                    });
                };
                reader.readAsArrayBuffer(fileToUpload.rawFile);
            }
        });
        var PageChangeCommand = Command.extend({
            exec: function () {
                var pageNumber = this.options.value;
                this.viewer.activatePage(pageNumber);
            }
        });
        var DownloadCommand = Command.extend({
            exec: function () {
                if (!this.viewer.document) {
                    this.viewer._triggerError({ message: this.errorMessages.notFound });
                    return;
                }
                var fileName = this.viewer.document.info && this.viewer.document.info.title || this.viewer.options.messages.defaultFileName;
                this.viewer.processor.downloadFile(fileName);
            }
        });
        var ExportCommand = Command.extend({
            init: function (options) {
                options = $.extend(options, this.options);
                Command.fn.init.call(this, options);
            },
            exec: function () {
                var dialog = this.viewer._saveDialog || this._initDialog();
                dialog._updateModel({
                    pagesCount: this.viewer.document && this.viewer.document.total || 1,
                    page: this.viewer.options.page
                });
                dialog.open();
            },
            apply: function (viewModel) {
                var extension = viewModel.extension;
                if (extension === '.png') {
                    this.viewer.exportImage(viewModel);
                } else if (extension === '.svg') {
                    this.viewer.exportSVG(viewModel);
                }
            },
            _initDialog: function () {
                this.viewer._saveDialog = new kendo.pdfviewer.dialogs.ExportAsDialog({
                    apply: this.apply.bind(this),
                    pagesCount: this.viewer.document && this.viewer.document.total || 1,
                    messages: this.viewer.options.messages
                });
                return this.viewer._saveDialog;
            }
        });
        extend(kendo.pdfviewer, {
            OpenCommand: OpenCommand,
            PageChangeCommand: PageChangeCommand,
            DownloadCommand: DownloadCommand,
            ExportCommand: ExportCommand
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pdfviewer', [
        'pdf-viewer/processors/pdfjs-processor',
        'pdf-viewer/processors/dpl-processor',
        'pdf-viewer/toolbar',
        'pdf-viewer/page',
        'pdf-viewer/dialogs',
        'pdf-viewer/commands'
    ], f);
}(function () {
    var __meta__ = {
        id: 'pdfviewer',
        name: 'PDFViewer',
        category: 'web',
        description: 'PDFViewer to display pdfs in the browser',
        depends: [
            'core',
            'window',
            'dialog',
            'toolbar'
        ]
    };
    (function ($, undefined) {
        var NS = '.kendoPDFViewer', kendo = window.kendo, ui = kendo.ui, proxy = $.proxy, extend = $.extend, drawing = kendo.drawing, Page, Widget = ui.Widget, progress = kendo.ui.progress, SCROLL = 'scroll', RENDER = 'render', OPEN = 'open', ERROR = 'error', FOCUS = 'focus', WHITECOLOR = '#ffffff', TABINDEX = 'tabindex', PROCESSORS = {
                pdfjs: 'pdfjs',
                dpl: 'dpl'
            }, styles = {
                viewer: 'k-pdf-viewer k-widget',
                scroller: 'k-canvas k-list-scroller'
            };
        var PDFViewer = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, kendo.deepExtend({}, this.options, options));
                that._wrapper();
                if (that.options.toolbar) {
                    that._renderToolbar();
                }
                that.wrapper.on(FOCUS, proxy(that._focus, that));
                that._initProcessor(options || {});
                that._renderPageContainer();
                that._loadDocument();
                that._tabindex();
                kendo.notify(that, kendo.ui);
            },
            events: [
                RENDER,
                OPEN,
                ERROR
            ],
            options: {
                name: 'PDFViewer',
                view: { type: 'canvas' },
                pdfjsProcessing: { file: null },
                dplProcessing: {
                    read: {
                        url: null,
                        type: 'GET',
                        dataType: 'json',
                        pageField: 'pageNumber'
                    },
                    upload: {
                        url: null,
                        saveField: 'file'
                    },
                    download: { url: null },
                    loadOnDemand: false
                },
                toolbar: { items: [] },
                width: 1000,
                height: 1200,
                page: 1,
                defaultPageSize: {
                    width: 794,
                    height: 1123
                },
                messages: {
                    defaultFileName: 'Document',
                    toolbar: {
                        open: 'Open',
                        exportAs: 'Export',
                        download: 'Download',
                        pager: {
                            first: 'Go to the first page',
                            previous: 'Go to the previous page',
                            next: 'Go to the next page',
                            last: 'Go to the last page',
                            of: ' of {0} ',
                            page: 'page',
                            pages: 'pages'
                        }
                    },
                    errorMessages: {
                        notSupported: 'Only pdf files allowed.',
                        parseError: 'PDF file fails to process.',
                        notFound: 'File is not found.'
                    },
                    dialogs: {
                        exportAsDialog: {
                            title: 'Export...',
                            defaultFileName: 'Document',
                            pdf: 'Portable Document Format (.pdf)',
                            png: 'Portable Network Graphics (.png)',
                            svg: 'Scalable Vector Graphics (.svg)',
                            labels: {
                                fileName: 'File name',
                                saveAsType: 'Save as',
                                page: 'Page'
                            }
                        },
                        okText: 'OK',
                        save: 'Save',
                        cancel: 'Cancel'
                    }
                }
            },
            _wrapper: function () {
                var that = this, options = that.options;
                that.wrapper = that.element;
                that.wrapper.width(options.width).height(options.height).addClass(styles.viewer);
                that._resizeHandler = kendo.onResize(function () {
                    that.resize();
                });
            },
            _focus: function (e) {
                if (this.toolbar) {
                    this.toolbar.wrapper.focus();
                } else {
                    this.pageContainer.focus();
                }
                e.preventDefault();
            },
            _initProcessor: function (options) {
                var that = this, processingOptions;
                processingOptions = options.dplProcessing ? that.options.dplProcessing : that.options.pdfjsProcessing;
                that.processingLib = options.dplProcessing ? PROCESSORS.dpl : PROCESSORS.pdfjs;
                that.processor = new kendo.pdfviewer[that.processingLib].processor(processingOptions, that);
                Page = kendo.pdfviewer[that.processingLib].Page;
            },
            _renderToolbar: function () {
                var that = this, options = that.options;
                var toolbarOptions = {
                    pager: { messages: options.messages.toolbar.pager },
                    resizable: true,
                    items: options.toolbar.items,
                    width: options.width,
                    action: that.execute.bind(that),
                    messages: options.messages.toolbar
                };
                var toolbarElement = $('<div />');
                toolbarElement.appendTo(that.element);
                that.toolbar = new kendo.pdfviewer.Toolbar(toolbarElement, toolbarOptions);
            },
            _initErrorDialog: function (options) {
                var that = this;
                if (!that._errorDialog) {
                    options = extend(options, { messages: that.options.messages });
                    var dialogInstance = new kendo.pdfviewer.dialogs.ErrorDialog(options);
                    that._errorDialog = dialogInstance._dialog;
                }
                return that._errorDialog;
            },
            _renderPageContainer: function () {
                var that = this;
                if (!that.pageContainer) {
                    that.pageContainer = $('<div />');
                    that.pageContainer.addClass(styles.scroller);
                    that.pageContainer.attr(TABINDEX, 0);
                    that.wrapper.append(that.pageContainer);
                }
            },
            _triggerError: function (options) {
                var dialog = this._initErrorDialog();
                extend(options, { dialog: dialog });
                if (this.pageContainer) {
                    progress(this.pageContainer, false);
                }
                if (this.trigger(ERROR, options)) {
                    return;
                }
                dialog.open().content(options.message);
            },
            _renderPages: function () {
                var that = this, document = that.document, pagesData;
                that.pages = [];
                if (!document || !document.total) {
                    that._renderBlankPage();
                    return;
                }
                pagesData = document.pages;
                for (var i = 1; i <= document.total; i++) {
                    var viewerPage, pageData = {
                            processor: that.processor,
                            number: i
                        };
                    if (pagesData && pagesData.length) {
                        pageData = extend(pageData, pagesData[i - 1]);
                    }
                    viewerPage = new Page(pageData, that);
                    that.pages.push(viewerPage);
                    that.pageContainer.append(viewerPage.element);
                }
                if (that.pages.length > 1) {
                    that.pageContainer.on(SCROLL + NS, proxy(that._scroll, that));
                }
            },
            _renderBlankPage: function () {
                this._blankPage = new Page(this.options.defaultPageSize, this);
                this.pageContainer.append(this._blankPage.element);
                this._updatePager(1, 1);
            },
            _updatePager: function (pageNumber, total) {
                if (!this.toolbar || !this.toolbar.pager) {
                    return;
                }
                this.toolbar.pager.setOptions({
                    page: pageNumber,
                    total: total
                });
            },
            _resize: function () {
                var that = this;
                var containerWidth;
                var containerHeight;
                var loadedPagesHeight = 0;
                var ratio;
                containerWidth = that.pageContainer[0].clientWidth;
                containerHeight = that.pageContainer[0].clientHeight;
                if (!that.pages || !that.pages.length) {
                    if (that._blankPage) {
                        ratio = containerWidth / that._blankPage.element.width();
                        that._blankPage.resize(ratio);
                    }
                    return;
                }
                if (that.toolbar) {
                    that.toolbar.resize(true);
                }
                that._visiblePagesCount = 1;
                that.pages.forEach(function (page) {
                    ratio = containerWidth / page.element.width();
                    page.resize(ratio);
                    loadedPagesHeight += page.element.height();
                    if (loadedPagesHeight < containerHeight && page.pageNumber > 1) {
                        that._visiblePagesCount++;
                    }
                });
            },
            _scroll: function () {
                var that = this, containerScrollHeight = that.pageContainer[0].scrollHeight, containerHeight = that.pageContainer.height(), containerScrollTop = that.pageContainer.scrollTop(), containerOffsetTop = that.pageContainer.offset().top, pageNum = that.options.page, pageIndex = pageNum - 1, total = that.pages.length, pageToLoad = pageNum, currentPage = that.pages[pageIndex], currentPageTop = currentPage.element.offset().top - containerOffsetTop, currentPageHeight = currentPage.element.height(), previousPage, prevPageTop, prevPageHeight, scrollDirection = containerScrollTop - that._prevScrollTop > 0 ? 1 : -1;
                if (that._preventScroll) {
                    that._preventScroll = false;
                    return;
                }
                if (scrollDirection == -1 && that.pages[pageIndex + scrollDirection]) {
                    previousPage = that.pages[pageIndex - that._visiblePagesCount] || that.pages[pageIndex + scrollDirection];
                    prevPageTop = previousPage.element.offset().top - containerOffsetTop;
                    prevPageHeight = previousPage.element.height();
                }
                if (Math.abs(containerScrollTop - (that._prevScrollTop || 0)) > containerHeight) {
                    pageToLoad = Math.floor(containerScrollTop * (1 / (containerScrollHeight / total))) + 1;
                } else if (currentPageTop < 0 && Math.abs(currentPageTop) >= currentPageHeight / 2 && scrollDirection === 1) {
                    pageToLoad++;
                } else if (previousPage && Math.abs(prevPageTop) <= prevPageHeight / 2) {
                    pageToLoad--;
                }
                if (pageNum !== pageToLoad && pageToLoad >= 1 && pageToLoad <= total) {
                    that.options.page = pageToLoad;
                    that._loadVisiblePages();
                    that._updatePager(pageToLoad, total);
                }
                that._prevScrollTop = containerScrollTop;
            },
            execute: function (options) {
                var commandOptions = extend({ viewer: this }, options.options);
                var command = new kendo.pdfviewer[options.command](commandOptions);
                command.exec();
            },
            _loadDocument: function () {
                var that = this;
                var page = that.options.page;
                progress(that.pageContainer, true);
                that.processor.fetchDocument().done(function (document) {
                    that._clearPages();
                    that.document = document;
                    that._renderPages();
                    that.resize(true);
                    if (document) {
                        page = page >= 1 && page <= document.total ? page : 1;
                        that.activatePage(page);
                    }
                    progress(that.pageContainer, false);
                });
            },
            loadPage: function (number) {
                var page = this.pages && this.pages[number - 1];
                if (page) {
                    page.load();
                }
            },
            activatePage: function (number) {
                var page = this.pages && this.pages[number - 1];
                var currentScrollTop = this.pageContainer.scrollTop();
                if (!page) {
                    return;
                }
                this.options.page = number;
                this._loadVisiblePages();
                this._preventScroll = true;
                this.pageContainer.scrollTop(currentScrollTop + page.element.position().top);
                this._updatePager(number, this.pages.length);
            },
            _loadVisiblePages: function () {
                var pagesCount = this.pages && this.pages.length;
                var minVisiblePageNum = this.options.page;
                var maxVisiblePageNum = Math.min(minVisiblePageNum + this._visiblePagesCount, pagesCount);
                for (var i = minVisiblePageNum; i <= maxVisiblePageNum; i++) {
                    this.loadPage(i);
                }
            },
            fromFile: function (file) {
                this.processor._updateDocument(file);
                this._loadDocument();
            },
            exportImage: function (options) {
                var that = this;
                var pageNumber = options.page;
                var page = that.pages[pageNumber - 1] || that._blankPage;
                var rootGroup = new drawing.Group();
                page.load();
                var background = kendo.drawing.Path.fromRect(new kendo.geometry.Rect([
                    0,
                    0
                ], [
                    page.width,
                    page.height
                ]), {
                    fill: { color: WHITECOLOR },
                    stroke: null
                });
                progress(that.pageContainer, true);
                rootGroup.append(background, page.group);
                drawing.exportImage(rootGroup).done(function (data) {
                    progress(that.pageContainer, false);
                    kendo.saveAs({
                        dataURI: data,
                        fileName: options.fileName,
                        proxyURL: options.proxyURL || '',
                        forceProxy: options.forceProxy,
                        proxyTarget: options.proxyTarget
                    });
                });
            },
            exportSVG: function (options) {
                var that = this;
                var pageNumber = options.page;
                var page = that.pages[pageNumber - 1] || that._blankPage;
                progress(that.pageContainer, true);
                page.load();
                drawing.exportSVG(page.group).done(function (data) {
                    progress(that.pageContainer, false);
                    kendo.saveAs({
                        dataURI: data,
                        fileName: options.fileName,
                        proxyURL: options.proxyURL || '',
                        forceProxy: options.forceProxy,
                        proxyTarget: options.proxyTarget
                    });
                });
            },
            setOptions: function (options) {
                var that = this;
                if (options.pdfjsProcessing || options.dplProcessing) {
                    that._initProcessor();
                }
                options = $.extend(that.options, options);
                Widget.fn.setOptions.call(that, options);
                if (options.page) {
                    that.activatePage(options.page);
                }
                if (options.width) {
                    that.element.width(options.width);
                }
                if (options.height) {
                    that.element.height(options.height);
                }
            },
            destroy: function () {
                kendo.unbindResize(this._resizeHandler);
                if (this._errorDialog) {
                    this._errorDialog.destroy();
                }
                if (this._saveDialog) {
                    this._saveDialog.destroy();
                }
                if (this._upload) {
                    this._upload.destroy();
                }
                if (this.toolbar) {
                    this.toolbar.unbind();
                    this.toolbar.destroy();
                    this.toolbar = null;
                }
                if (this.pages && this.pages.length) {
                    this.pages.forEach(function (page) {
                        page.destroy();
                    });
                    this.pages = [];
                }
                this.pageContainer.off(NS);
                Widget.fn.destroy.call(this);
            },
            _clearPages: function () {
                this.pages = [];
                this.document = null;
                this.options.page = 1;
                this.pageContainer.empty();
                this.pageContainer.off(SCROLL + NS);
                this.pageContainer.scrollTop(0);
            }
        });
        ui.plugin(PDFViewer);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.angular', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'angular',
        name: 'AngularJS Directives',
        category: 'framework',
        description: 'Adds Kendo UI for AngularJS directives',
        depends: ['core'],
        defer: true
    };
    (function ($, angular, undefined) {
        'use strict';
        if (!angular || !angular.injector) {
            return;
        }
        var module = angular.module('kendo.directives', []), $injector = angular.injector(['ng']), $parse = $injector.get('$parse'), $timeout = $injector.get('$timeout'), $defaultCompile, $log = $injector.get('$log');
        function withoutTimeout(f) {
            var save = $timeout;
            try {
                $timeout = function (f) {
                    return f();
                };
                return f();
            } finally {
                $timeout = save;
            }
        }
        var OPTIONS_NOW;
        var createDataSource = function () {
            var types = {
                TreeList: 'TreeListDataSource',
                TreeView: 'HierarchicalDataSource',
                Scheduler: 'SchedulerDataSource',
                PivotGrid: 'PivotDataSource',
                PivotConfigurator: 'PivotDataSource',
                PanelBar: 'HierarchicalDataSource',
                Menu: '$PLAIN',
                ContextMenu: '$PLAIN'
            };
            var toDataSource = function (dataSource, type) {
                if (type == '$PLAIN') {
                    return dataSource;
                }
                return kendo.data[type].create(dataSource);
            };
            return function (scope, element, role, source) {
                var type = types[role] || 'DataSource';
                var current = scope.$eval(source);
                var ds = toDataSource(current, type);
                scope.$watch(source, function (mew) {
                    var widget = kendoWidgetInstance(element);
                    if (widget && typeof widget.setDataSource == 'function') {
                        if (mew !== current && mew !== widget.dataSource) {
                            var ds = toDataSource(mew, type);
                            widget.setDataSource(ds);
                            current = mew;
                        }
                    }
                });
                return ds;
            };
        }();
        var ignoredAttributes = {
            kDataSource: true,
            kOptions: true,
            kRebind: true,
            kNgModel: true,
            kNgDelay: true
        };
        var ignoredOwnProperties = {
            name: true,
            title: true,
            style: true
        };
        function createWidget(scope, element, attrs, widget, origAttr, controllers) {
            if (!(element instanceof jQuery)) {
                throw new Error('The Kendo UI directives require jQuery to be available before AngularJS. Please include jquery before angular in the document.');
            }
            var kNgDelay = attrs.kNgDelay, delayValue = scope.$eval(kNgDelay);
            controllers = controllers || [];
            var ngModel = controllers[0], ngForm = controllers[1];
            var ctor = $(element)[widget];
            if (!ctor) {
                window.console.error('Could not find: ' + widget);
                return null;
            }
            var parsed = parseOptions(scope, element, attrs, widget, ctor);
            var options = parsed.options;
            if (parsed.unresolved.length) {
                var promises = [];
                for (var i = 0, len = parsed.unresolved.length; i < len; i++) {
                    var unresolved = parsed.unresolved[i];
                    var promise = $.Deferred(function (d) {
                        var unwatch = scope.$watch(unresolved.path, function (newValue) {
                            if (newValue !== undefined) {
                                unwatch();
                                d.resolve();
                            }
                        });
                    }).promise();
                    promises.push(promise);
                }
                $.when.apply(null, promises).then(createIt);
                return;
            }
            if (kNgDelay && !delayValue) {
                var root = scope.$root || scope;
                var register = function () {
                    var unregister = scope.$watch(kNgDelay, function (newValue) {
                        if (newValue !== undefined) {
                            unregister();
                            element.removeAttr(attrs.$attr.kNgDelay);
                            kNgDelay = null;
                            $timeout(createIt);
                        }
                    });
                };
                if (/^\$(digest|apply)$/.test(root.$$phase)) {
                    register();
                } else {
                    scope.$apply(register);
                }
                return;
            } else {
                return createIt();
            }
            function createIt() {
                var originalElement;
                if (attrs.kRebind) {
                    originalElement = $($(element)[0].cloneNode(true));
                }
                options = parseOptions(scope, element, attrs, widget, ctor).options;
                if (element.is('select')) {
                    (function (options) {
                        if (options.length > 0) {
                            var first = $(options[0]);
                            if (!/\S/.test(first.text()) && /^\?/.test(first.val())) {
                                first.remove();
                            }
                            for (var i = 0; i < options.length; i++) {
                                $(options[i]).off('$destroy');
                            }
                        }
                    }(element[0].options));
                }
                var object = ctor.call(element, OPTIONS_NOW = options).data(widget);
                exposeWidget(object, scope, attrs, widget, origAttr);
                scope.$emit('kendoWidgetCreated', object);
                var destroyRegister = destroyWidgetOnScopeDestroy(scope, object);
                if (attrs.kRebind) {
                    setupRebind(object, scope, element, originalElement, attrs.kRebind, destroyRegister, attrs);
                }
                if (attrs.kNgDisabled) {
                    var kNgDisabled = attrs.kNgDisabled;
                    var isDisabled = scope.$eval(kNgDisabled);
                    if (isDisabled) {
                        object.enable(!isDisabled);
                    }
                    bindToKNgDisabled(object, scope, element, kNgDisabled);
                }
                if (attrs.kNgReadonly) {
                    var kNgReadonly = attrs.kNgReadonly;
                    var isReadonly = scope.$eval(kNgReadonly);
                    if (isReadonly) {
                        object.readonly(isReadonly);
                    }
                    bindToKNgReadonly(object, scope, element, kNgReadonly);
                }
                if (attrs.kNgModel) {
                    bindToKNgModel(object, scope, attrs.kNgModel);
                }
                if (ngModel) {
                    bindToNgModel(object, scope, element, ngModel, ngForm);
                }
                if (object) {
                    propagateClassToWidgetWrapper(object, element);
                }
                return object;
            }
        }
        function parseOptions(scope, element, attrs, widget, ctor) {
            var role = widget.replace(/^kendo/, '');
            var unresolved = [];
            var optionsPath = attrs.kOptions || attrs.options;
            var optionsValue = scope.$eval(optionsPath);
            if (optionsPath && optionsValue === undefined) {
                unresolved.push({
                    option: 'options',
                    path: optionsPath
                });
            }
            var options = angular.extend({}, attrs.defaultOptions, optionsValue);
            function addOption(name, value) {
                var scopeValue = angular.copy(scope.$eval(value));
                if (scopeValue === undefined) {
                    unresolved.push({
                        option: name,
                        path: value
                    });
                } else {
                    options[name] = scopeValue;
                }
            }
            var widgetOptions = ctor.widget.prototype.options;
            var widgetEvents = ctor.widget.prototype.events;
            $.each(attrs, function (name, value) {
                if (name === 'source' || name === 'kDataSource' || name === 'kScopeField' || name === 'scopeField') {
                    return;
                }
                var dataName = 'data' + name.charAt(0).toUpperCase() + name.slice(1);
                if (name.indexOf('on') === 0) {
                    var eventKey = name.replace(/^on./, function (prefix) {
                        return prefix.charAt(2).toLowerCase();
                    });
                    if (widgetEvents.indexOf(eventKey) > -1) {
                        options[eventKey] = value;
                    }
                }
                if (widgetOptions.hasOwnProperty(dataName)) {
                    addOption(dataName, value);
                } else if (widgetOptions.hasOwnProperty(name) && !ignoredOwnProperties[name]) {
                    addOption(name, value);
                } else if (!ignoredAttributes[name]) {
                    var match = name.match(/^k(On)?([A-Z].*)/);
                    if (match) {
                        var optionName = match[2].charAt(0).toLowerCase() + match[2].slice(1);
                        if (match[1] && name != 'kOnLabel') {
                            options[optionName] = value;
                        } else {
                            if (name == 'kOnLabel') {
                                optionName = 'onLabel';
                            }
                            addOption(optionName, value);
                        }
                    }
                }
            });
            var dataSource = attrs.kDataSource || attrs.source;
            if (dataSource) {
                options.dataSource = createDataSource(scope, element, role, dataSource);
            }
            options.$angular = [scope];
            return {
                options: options,
                unresolved: unresolved
            };
        }
        function bindToKNgDisabled(widget, scope, element, kNgDisabled) {
            if (kendo.ui.PanelBar && widget instanceof kendo.ui.PanelBar || kendo.ui.Menu && widget instanceof kendo.ui.Menu) {
                $log.warn('k-ng-disabled specified on a widget that does not have the enable() method: ' + widget.options.name);
                return;
            }
            scope.$watch(kNgDisabled, function (newValue, oldValue) {
                if (newValue != oldValue) {
                    widget.enable(!newValue);
                }
            });
        }
        function bindToKNgReadonly(widget, scope, element, kNgReadonly) {
            if (typeof widget.readonly != 'function') {
                $log.warn('k-ng-readonly specified on a widget that does not have the readonly() method: ' + widget.options.name);
                return;
            }
            scope.$watch(kNgReadonly, function (newValue, oldValue) {
                if (newValue != oldValue) {
                    widget.readonly(newValue);
                }
            });
        }
        function exposeWidget(widget, scope, attrs, kendoWidget, origAttr) {
            if (attrs[origAttr]) {
                var set = $parse(attrs[origAttr]).assign;
                if (set) {
                    set(scope, widget);
                } else {
                    throw new Error(origAttr + ' attribute used but expression in it is not assignable: ' + attrs[kendoWidget]);
                }
            }
        }
        function formValue(element) {
            if (/checkbox|radio/i.test(element.attr('type'))) {
                return element.prop('checked');
            }
            return element.val();
        }
        var formRegExp = /^(input|select|textarea)$/i;
        function isForm(element) {
            return formRegExp.test(element[0].tagName);
        }
        function bindToNgModel(widget, scope, element, ngModel, ngForm) {
            if (!widget.value) {
                return;
            }
            var value;
            var haveChangeOnElement = false;
            if (isForm(element)) {
                value = function () {
                    return formValue(element);
                };
            } else {
                value = function () {
                    return widget.value();
                };
            }
            var viewRender = function () {
                var val = ngModel.$viewValue;
                if (val === undefined) {
                    val = ngModel.$modelValue;
                }
                if (val === undefined) {
                    val = null;
                }
                haveChangeOnElement = true;
                setTimeout(function () {
                    haveChangeOnElement = false;
                    if (widget) {
                        var kNgModel = scope[widget.element.attr('k-ng-model')];
                        if (kNgModel) {
                            val = kNgModel;
                        }
                        if (widget.options.autoBind === false && !widget.listView.bound()) {
                            if (val) {
                                widget.value(val);
                            }
                        } else {
                            widget.value(val);
                        }
                    }
                }, 0);
            };
            ngModel.$render = viewRender;
            setTimeout(function () {
                if (ngModel.$render !== viewRender) {
                    ngModel.$render = viewRender;
                    ngModel.$render();
                }
            });
            if (isForm(element)) {
                element.on('change', function () {
                    haveChangeOnElement = true;
                });
            }
            var onChange = function (pristine) {
                return function () {
                    var formPristine;
                    if (haveChangeOnElement && !element.is('select')) {
                        return;
                    }
                    if (pristine && ngForm) {
                        formPristine = ngForm.$pristine;
                    }
                    ngModel.$setViewValue(value());
                    if (pristine) {
                        ngModel.$setPristine();
                        if (formPristine) {
                            ngForm.$setPristine();
                        }
                    }
                    digest(scope);
                };
            };
            widget.first('change', onChange(false));
            widget.first('spin', onChange(false));
            if (!(kendo.ui.AutoComplete && widget instanceof kendo.ui.AutoComplete)) {
                widget.first('dataBound', onChange(true));
            }
            var currentVal = value();
            if (!isNaN(ngModel.$viewValue) && currentVal != ngModel.$viewValue) {
                if (!ngModel.$isEmpty(ngModel.$viewValue)) {
                    widget.value(ngModel.$viewValue);
                } else if (currentVal != null && currentVal !== '' && currentVal != ngModel.$viewValue) {
                    ngModel.$setViewValue(currentVal);
                }
            }
            ngModel.$setPristine();
        }
        function bindToKNgModel(widget, scope, kNgModel) {
            if (kendo.ui.DateRangePicker && widget instanceof kendo.ui.DateRangePicker) {
                var rangePickerModels = kNgModel.split(',');
                var rangePickerStartModel = rangePickerModels[0].trim();
                var rangePickerEndModel;
                bindToKNgModel(widget._startDateInput, scope, rangePickerStartModel);
                if (rangePickerModels[1]) {
                    rangePickerEndModel = rangePickerModels[1].trim();
                    bindToKNgModel(widget._endDateInput, scope, rangePickerEndModel);
                    widget.range({
                        start: scope[rangePickerStartModel],
                        end: scope[rangePickerEndModel]
                    });
                } else {
                    widget.range({
                        start: scope[rangePickerStartModel],
                        end: null
                    });
                }
                return;
            }
            if (typeof widget.value != 'function') {
                $log.warn('k-ng-model specified on a widget that does not have the value() method: ' + widget.options.name);
                return;
            }
            var form = $(widget.element).parents('ng-form, form').first();
            var ngForm = kendo.getter(form.attr('name'), true)(scope);
            var getter = $parse(kNgModel);
            var setter = getter.assign;
            var updating = false;
            var valueIsCollection = kendo.ui.MultiSelect && widget instanceof kendo.ui.MultiSelect || kendo.ui.RangeSlider && widget instanceof kendo.ui.RangeSlider;
            var length = function (value) {
                return value && valueIsCollection ? value.length : 0;
            };
            var currentValueLength = length(getter(scope));
            widget.$angular_setLogicValue(getter(scope));
            var watchHandler = function (newValue, oldValue) {
                if (newValue === undefined) {
                    newValue = null;
                }
                if (updating || newValue == oldValue && length(newValue) == currentValueLength) {
                    return;
                }
                currentValueLength = length(newValue);
                widget.$angular_setLogicValue(newValue);
            };
            if (valueIsCollection) {
                scope.$watchCollection(kNgModel, watchHandler);
            } else {
                scope.$watch(kNgModel, watchHandler);
            }
            var changeHandler = function () {
                updating = true;
                if (ngForm && ngForm.$pristine) {
                    ngForm.$setDirty();
                }
                digest(scope, function () {
                    setter(scope, widget.$angular_getLogicValue());
                    currentValueLength = length(getter(scope));
                });
                updating = false;
            };
            widget.first('change', changeHandler);
            widget.first('spin', changeHandler);
        }
        function destroyWidgetOnScopeDestroy(scope, widget) {
            var deregister = scope.$on('$destroy', function () {
                deregister();
                if (widget) {
                    kendo.destroy(widget.element);
                    widget = null;
                }
            });
            return deregister;
        }
        function propagateClassToWidgetWrapper(widget, element) {
            if (!(window.MutationObserver && widget.wrapper)) {
                return;
            }
            var prevClassList = [].slice.call($(element)[0].classList);
            var mo = new MutationObserver(function (changes) {
                suspend();
                if (!widget) {
                    return;
                }
                changes.forEach(function (chg) {
                    var w = $(widget.wrapper)[0];
                    switch (chg.attributeName) {
                    case 'class':
                        var currClassList = [].slice.call(chg.target.classList);
                        currClassList.forEach(function (cls) {
                            if (prevClassList.indexOf(cls) < 0) {
                                w.classList.add(cls);
                                if (kendo.ui.ComboBox && widget instanceof kendo.ui.ComboBox) {
                                    widget.input[0].classList.add(cls);
                                }
                            }
                        });
                        prevClassList.forEach(function (cls) {
                            if (currClassList.indexOf(cls) < 0) {
                                w.classList.remove(cls);
                                if (kendo.ui.ComboBox && widget instanceof kendo.ui.ComboBox) {
                                    widget.input[0].classList.remove(cls);
                                }
                            }
                        });
                        prevClassList = currClassList;
                        break;
                    case 'disabled':
                        if (typeof widget.enable == 'function' && !widget.element.attr('readonly')) {
                            widget.enable(!$(chg.target).attr('disabled'));
                        }
                        break;
                    case 'readonly':
                        if (typeof widget.readonly == 'function' && !widget.element.attr('disabled')) {
                            widget.readonly(!!$(chg.target).attr('readonly'));
                        }
                        break;
                    }
                });
                resume();
            });
            function suspend() {
                mo.disconnect();
            }
            function resume() {
                mo.observe($(element)[0], { attributes: true });
            }
            resume();
            widget.first('destroy', suspend);
        }
        function setupRebind(widget, scope, element, originalElement, rebindAttr, destroyRegister, attrs) {
            var unregister = scope.$watch(rebindAttr, function (newValue, oldValue) {
                if (!widget._muteRebind && newValue !== oldValue) {
                    unregister();
                    if (attrs._cleanUp) {
                        attrs._cleanUp();
                    }
                    var templateOptions = WIDGET_TEMPLATE_OPTIONS[widget.options.name];
                    if (templateOptions) {
                        templateOptions.forEach(function (name) {
                            var templateContents = scope.$eval(attrs['k' + name]);
                            if (templateContents) {
                                originalElement.append($(templateContents).attr(kendo.toHyphens('k' + name), ''));
                            }
                        });
                    }
                    var _wrapper = $(widget.wrapper)[0];
                    var _element = $(widget.element)[0];
                    var isUpload = widget.options.name === 'Upload';
                    if (isUpload) {
                        element = $(_element);
                    }
                    var compile = element.injector().get('$compile');
                    widget._destroy();
                    if (destroyRegister) {
                        destroyRegister();
                    }
                    widget = null;
                    if (_element) {
                        if (_wrapper) {
                            _wrapper.parentNode.replaceChild(_element, _wrapper);
                        }
                        $(element).replaceWith(originalElement);
                    }
                    compile(originalElement)(scope);
                }
            }, true);
            digest(scope);
        }
        function bind(f, obj) {
            return function (a, b) {
                return f.call(obj, a, b);
            };
        }
        function setTemplate(key, value) {
            this[key] = kendo.stringify(value);
        }
        module.factory('directiveFactory', [
            '$compile',
            function (compile) {
                var kendoRenderedTimeout;
                var RENDERED = false;
                $defaultCompile = compile;
                var create = function (role, origAttr) {
                    return {
                        restrict: 'AC',
                        require: [
                            '?ngModel',
                            '^?form'
                        ],
                        scope: false,
                        controller: [
                            '$scope',
                            '$attrs',
                            '$element',
                            function ($scope, $attrs) {
                                this.template = bind(setTemplate, $attrs);
                                $attrs._cleanUp = bind(function () {
                                    this.template = null;
                                    $attrs._cleanUp = null;
                                }, this);
                            }
                        ],
                        link: function (scope, element, attrs, controllers) {
                            var $element = $(element);
                            var roleattr = role.replace(/([A-Z])/g, '-$1');
                            $element.attr(roleattr, $element.attr('data-' + roleattr));
                            $element[0].removeAttribute('data-' + roleattr);
                            var widget = createWidget(scope, element, attrs, role, origAttr, controllers);
                            if (!widget) {
                                return;
                            }
                            if (kendoRenderedTimeout) {
                                clearTimeout(kendoRenderedTimeout);
                            }
                            kendoRenderedTimeout = setTimeout(function () {
                                scope.$emit('kendoRendered');
                                if (!RENDERED) {
                                    RENDERED = true;
                                    $('form').each(function () {
                                        var form = $(this).controller('form');
                                        if (form) {
                                            form.$setPristine();
                                        }
                                    });
                                }
                            });
                        }
                    };
                };
                return { create: create };
            }
        ]);
        var TAGNAMES = {
            Editor: 'textarea',
            NumericTextBox: 'input',
            DatePicker: 'input',
            DateTimePicker: 'input',
            TimePicker: 'input',
            AutoComplete: 'input',
            ColorPicker: 'input',
            MaskedTextBox: 'input',
            MultiSelect: 'input',
            Upload: 'input',
            Validator: 'form',
            Button: 'button',
            MobileButton: 'a',
            MobileBackButton: 'a',
            MobileDetailButton: 'a',
            ListView: 'ul',
            MobileListView: 'ul',
            ScrollView: 'div',
            PanelBar: 'ul',
            TreeView: 'ul',
            Menu: 'ul',
            ContextMenu: 'ul',
            ActionSheet: 'ul',
            Switch: 'input'
        };
        var SKIP_SHORTCUTS = [
            'MobileView',
            'MobileDrawer',
            'MobileLayout',
            'MobileSplitView',
            'MobilePane',
            'MobileModalView'
        ];
        var MANUAL_DIRECTIVES = [
            'MobileApplication',
            'MobileView',
            'MobileModalView',
            'MobileLayout',
            'MobileActionSheet',
            'MobileDrawer',
            'MobileSplitView',
            'MobilePane',
            'MobileScrollView',
            'MobilePopOver'
        ];
        angular.forEach([
            'MobileNavBar',
            'MobileButton',
            'MobileBackButton',
            'MobileDetailButton',
            'MobileTabStrip',
            'MobileScrollView',
            'MobileScroller'
        ], function (widget) {
            MANUAL_DIRECTIVES.push(widget);
            widget = 'kendo' + widget;
            module.directive(widget, function () {
                return {
                    restrict: 'A',
                    link: function (scope, element, attrs) {
                        createWidget(scope, element, attrs, widget, widget);
                    }
                };
            });
        });
        function createDirectives(klass, isMobile) {
            function make(directiveName, widgetName) {
                module.directive(directiveName, [
                    'directiveFactory',
                    function (directiveFactory) {
                        return directiveFactory.create(widgetName, directiveName);
                    }
                ]);
            }
            var name = isMobile ? 'Mobile' : '';
            name += klass.fn.options.name;
            var className = name;
            var shortcut = 'kendo' + name.charAt(0) + name.substr(1).toLowerCase();
            name = 'kendo' + name;
            var dashed = name.replace(/([A-Z])/g, '-$1');
            if (SKIP_SHORTCUTS.indexOf(name.replace('kendo', '')) == -1) {
                var names = name === shortcut ? [name] : [
                    name,
                    shortcut
                ];
                angular.forEach(names, function (directiveName) {
                    module.directive(directiveName, function () {
                        return {
                            restrict: 'E',
                            replace: true,
                            template: function (element, attributes) {
                                var tag = TAGNAMES[className] || 'div';
                                var scopeField = attributes.kScopeField || attributes.scopeField;
                                return '<' + tag + ' ' + dashed + (scopeField ? '="' + scopeField + '"' : '') + '>' + element.html() + '</' + tag + '>';
                            }
                        };
                    });
                });
            }
            if (MANUAL_DIRECTIVES.indexOf(name.replace('kendo', '')) > -1) {
                return;
            }
            make(name, name);
            if (shortcut != name) {
                make(shortcut, name);
            }
        }
        function kendoWidgetInstance(el) {
            el = $(el);
            return kendo.widgetInstance(el, kendo.ui) || kendo.widgetInstance(el, kendo.mobile.ui) || kendo.widgetInstance(el, kendo.dataviz.ui);
        }
        function digest(scope, func) {
            var root = scope.$root || scope;
            var isDigesting = /^\$(digest|apply)$/.test(root.$$phase);
            if (func) {
                if (isDigesting) {
                    func();
                } else {
                    root.$apply(func);
                }
            } else if (!isDigesting) {
                root.$digest();
            }
        }
        function destroyScope(scope, el) {
            scope.$destroy();
            if (el) {
                $(el).removeData('$scope').removeData('$$kendoScope').removeData('$isolateScope').removeData('$isolateScopeNoTemplate').removeClass('ng-scope');
            }
        }
        var encode = kendo.htmlEncode;
        var open = /{{/g;
        var close = /}}/g;
        var encOpen = '{&#8203;{';
        var encClose = '}&#8203;}';
        kendo.htmlEncode = function (str) {
            return encode(str).replace(open, encOpen).replace(close, encClose);
        };
        var pendingPatches = [];
        function defadvice(klass, methodName, func) {
            if ($.isArray(klass)) {
                return angular.forEach(klass, function (klass) {
                    defadvice(klass, methodName, func);
                });
            }
            if (typeof klass == 'string') {
                var a = klass.split('.');
                var x = kendo;
                while (x && a.length > 0) {
                    x = x[a.shift()];
                }
                if (!x) {
                    pendingPatches.push([
                        klass,
                        methodName,
                        func
                    ]);
                    return false;
                }
                klass = x.prototype;
            }
            var origMethod = klass[methodName];
            klass[methodName] = function () {
                var self = this, args = arguments;
                return func.apply({
                    self: self,
                    next: function () {
                        return origMethod.apply(self, arguments.length > 0 ? arguments : args);
                    }
                }, args);
            };
            return true;
        }
        kendo.onWidgetRegistered(function (entry) {
            pendingPatches = $.grep(pendingPatches, function (args) {
                return !defadvice.apply(null, args);
            });
            createDirectives(entry.widget, entry.prefix == 'Mobile');
        });
        defadvice([
            'ui.Widget',
            'mobile.ui.Widget'
        ], 'angular', function (cmd, arg) {
            var self = this.self;
            if (cmd == 'init') {
                if (!arg && OPTIONS_NOW) {
                    arg = OPTIONS_NOW;
                }
                OPTIONS_NOW = null;
                if (arg && arg.$angular) {
                    self.$angular_scope = arg.$angular[0];
                    self.$angular_init(self.element, arg);
                }
                return;
            }
            var scope = self.$angular_scope;
            if (scope) {
                withoutTimeout(function () {
                    var x = arg(), elements = x.elements, data = x.data;
                    if (elements.length > 0) {
                        switch (cmd) {
                        case 'cleanup':
                            angular.forEach(elements, function (el) {
                                var itemScope = $(el).data('$$kendoScope');
                                if (itemScope && itemScope !== scope && itemScope.$$kendoScope) {
                                    destroyScope(itemScope, el);
                                }
                            });
                            break;
                        case 'compile':
                            var injector = self.element.injector();
                            var compile = injector ? injector.get('$compile') : $defaultCompile;
                            angular.forEach(elements, function (el, i) {
                                var itemScope;
                                if (x.scopeFrom) {
                                    itemScope = x.scopeFrom;
                                } else {
                                    var vars = data && data[i];
                                    if (vars !== undefined) {
                                        itemScope = $.extend(scope.$new(), vars);
                                        itemScope.$$kendoScope = true;
                                    } else {
                                        itemScope = scope;
                                    }
                                }
                                $(el).data('$$kendoScope', itemScope);
                                compile(el)(itemScope);
                            });
                            digest(scope);
                            break;
                        }
                    }
                });
            }
        });
        defadvice('ui.Widget', '$angular_getLogicValue', function () {
            return this.self.value();
        });
        defadvice('ui.Widget', '$angular_setLogicValue', function (val) {
            this.self.value(val);
        });
        defadvice('ui.Select', '$angular_getLogicValue', function () {
            var item = this.self.dataItem(), valueField = this.self.options.dataValueField;
            if (item) {
                if (this.self.options.valuePrimitive) {
                    if (!!valueField) {
                        return item[valueField];
                    } else {
                        return item;
                    }
                } else {
                    return item.toJSON();
                }
            } else {
                return null;
            }
        });
        defadvice('ui.Select', '$angular_setLogicValue', function (val) {
            var self = this.self;
            var options = self.options;
            var valueField = options.dataValueField;
            var text = options.text || '';
            if (val === undefined) {
                val = '';
            }
            if (valueField && !options.valuePrimitive && val) {
                text = val[options.dataTextField] || '';
                val = val[valueField || options.dataTextField];
            }
            if (self.options.autoBind === false && !self.listView.bound()) {
                if (!text && val && options.valuePrimitive) {
                    self.value(val);
                } else {
                    self._preselect(val, text);
                }
            } else {
                self.value(val);
            }
        });
        defadvice('ui.MultiSelect', '$angular_getLogicValue', function () {
            var value = this.self.dataItems().slice(0);
            var valueField = this.self.options.dataValueField;
            if (valueField && this.self.options.valuePrimitive) {
                value = $.map(value, function (item) {
                    return item[valueField];
                });
            }
            return value;
        });
        defadvice('ui.MultiSelect', '$angular_setLogicValue', function (val) {
            if (val == null) {
                val = [];
            }
            var self = this.self;
            var options = self.options;
            var valueField = options.dataValueField;
            var data = val;
            if (valueField && !options.valuePrimitive) {
                val = $.map(val, function (item) {
                    return item[valueField];
                });
            }
            if (options.autoBind === false && !options.valuePrimitive && !self.listView.bound()) {
                self._preselect(data, val);
            } else {
                self.value(val);
            }
        });
        defadvice('ui.Widget', '$angular_init', function (element, options) {
            var self = this.self;
            if (options && !$.isArray(options)) {
                var scope = self.$angular_scope;
                for (var i = self.events.length; --i >= 0;) {
                    var event = self.events[i];
                    var handler = options[event];
                    if (handler && typeof handler == 'string') {
                        options[event] = self.$angular_makeEventHandler(event, scope, handler);
                    }
                }
            }
        });
        defadvice('ui.Widget', '$angular_makeEventHandler', function (event, scope, handler) {
            handler = $parse(handler);
            return function (e) {
                digest(scope, function () {
                    handler(scope, { kendoEvent: e });
                });
            };
        });
        defadvice([
            'ui.Grid',
            'ui.ListView',
            'ui.TreeView',
            'ui.PanelBar'
        ], '$angular_makeEventHandler', function (event, scope, handler) {
            if (event != 'change') {
                return this.next();
            }
            handler = $parse(handler);
            return function (ev) {
                var widget = ev.sender;
                var options = widget.options;
                var cell, multiple, locals = { kendoEvent: ev }, elems, items, columns, colIdx;
                if (angular.isString(options.selectable)) {
                    cell = options.selectable.indexOf('cell') !== -1;
                    multiple = options.selectable.indexOf('multiple') !== -1;
                }
                if (widget._checkBoxSelection) {
                    multiple = true;
                }
                elems = locals.selected = this.select();
                items = locals.data = [];
                columns = locals.columns = [];
                for (var i = 0; i < elems.length; i++) {
                    var item = cell ? elems[i].parentNode : elems[i];
                    var dataItem = widget.dataItem(item);
                    if (cell) {
                        if (angular.element.inArray(dataItem, items) < 0) {
                            items.push(dataItem);
                        }
                        colIdx = angular.element(elems[i]).index();
                        if (angular.element.inArray(colIdx, columns) < 0) {
                            columns.push(colIdx);
                        }
                    } else {
                        items.push(dataItem);
                    }
                }
                if (!multiple) {
                    locals.dataItem = locals.data = items[0];
                    locals.angularDataItem = kendo.proxyModelSetters(locals.dataItem);
                    locals.selected = elems[0];
                }
                digest(scope, function () {
                    handler(scope, locals);
                });
            };
        });
        defadvice('ui.Grid', '$angular_init', function (element, options) {
            this.next();
            if (options.columns) {
                var settings = $.extend({}, kendo.Template, options.templateSettings);
                angular.forEach(options.columns, function (col) {
                    if (col.field && !col.template && !col.format && !col.values && (col.encoded === undefined || col.encoded)) {
                        col.template = '<span ng-bind=\'' + kendo.expr(col.field, 'dataItem') + '\'>#: ' + kendo.expr(col.field, settings.paramName) + '#</span>';
                    }
                });
            }
        });
        {
            defadvice('mobile.ui.ButtonGroup', 'value', function (mew) {
                var self = this.self;
                if (mew != null) {
                    self.select(self.element.children('li.km-button').eq(mew));
                    self.trigger('change');
                    self.trigger('select', { index: self.selectedIndex });
                }
                return self.selectedIndex;
            });
            defadvice('mobile.ui.ButtonGroup', '_select', function () {
                this.next();
                this.self.trigger('change');
            });
        }
        module.directive('kendoMobileApplication', function () {
            return {
                terminal: true,
                link: function (scope, element, attrs) {
                    createWidget(scope, element, attrs, 'kendoMobileApplication', 'kendoMobileApplication');
                }
            };
        }).directive('kendoMobileView', function () {
            return {
                scope: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        attrs._instance = createWidget(scope, element, attrs, 'kendoMobileView', 'kendoMobileView');
                    },
                    post: function (scope, element, attrs) {
                        attrs._instance._layout();
                        attrs._instance._scroller();
                    }
                }
            };
        }).directive('kendoMobileDrawer', function () {
            return {
                scope: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        attrs._instance = createWidget(scope, element, attrs, 'kendoMobileDrawer', 'kendoMobileDrawer');
                    },
                    post: function (scope, element, attrs) {
                        attrs._instance._layout();
                        attrs._instance._scroller();
                    }
                }
            };
        }).directive('kendoMobileModalView', function () {
            return {
                scope: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        attrs._instance = createWidget(scope, element, attrs, 'kendoMobileModalView', 'kendoMobileModalView');
                    },
                    post: function (scope, element, attrs) {
                        attrs._instance._layout();
                        attrs._instance._scroller();
                    }
                }
            };
        }).directive('kendoMobileSplitView', function () {
            return {
                terminal: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        attrs._instance = createWidget(scope, element, attrs, 'kendoMobileSplitView', 'kendoMobileSplitView');
                    },
                    post: function (scope, element, attrs) {
                        attrs._instance._layout();
                    }
                }
            };
        }).directive('kendoMobilePane', function () {
            return {
                terminal: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        createWidget(scope, element, attrs, 'kendoMobilePane', 'kendoMobilePane');
                    }
                }
            };
        }).directive('kendoMobileLayout', function () {
            return {
                link: {
                    pre: function (scope, element, attrs) {
                        createWidget(scope, element, attrs, 'kendoMobileLayout', 'kendoMobileLayout');
                    }
                }
            };
        }).directive('kendoMobileActionSheet', function () {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    element.find('a[k-action]').each(function () {
                        $(this).attr('data-' + kendo.ns + 'action', $(this).attr('k-action'));
                    });
                    createWidget(scope, element, attrs, 'kendoMobileActionSheet', 'kendoMobileActionSheet');
                }
            };
        }).directive('kendoMobilePopOver', function () {
            return {
                terminal: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        createWidget(scope, element, attrs, 'kendoMobilePopOver', 'kendoMobilePopOver');
                    }
                }
            };
        }).directive('kendoViewTitle', function () {
            return {
                restrict: 'E',
                replace: true,
                template: function (element) {
                    return '<span data-' + kendo.ns + 'role=\'view-title\'>' + element.html() + '</span>';
                }
            };
        }).directive('kendoMobileHeader', function () {
            return {
                restrict: 'E',
                link: function (scope, element) {
                    element.addClass('km-header').attr('data-role', 'header');
                }
            };
        }).directive('kendoMobileFooter', function () {
            return {
                restrict: 'E',
                link: function (scope, element) {
                    element.addClass('km-footer').attr('data-role', 'footer');
                }
            };
        }).directive('kendoMobileScrollViewPage', function () {
            return {
                restrict: 'E',
                replace: true,
                template: function (element) {
                    return '<div data-' + kendo.ns + 'role=\'page\'>' + element.html() + '</div>';
                }
            };
        });
        angular.forEach([
            'align',
            'icon',
            'rel',
            'transition',
            'actionsheetContext'
        ], function (attr) {
            var kAttr = 'k' + attr.slice(0, 1).toUpperCase() + attr.slice(1);
            module.directive(kAttr, function () {
                return {
                    restrict: 'A',
                    priority: 2,
                    link: function (scope, element, attrs) {
                        element.attr(kendo.attr(kendo.toHyphens(attr)), scope.$eval(attrs[kAttr]));
                    }
                };
            });
        });
        var WIDGET_TEMPLATE_OPTIONS = {
            'TreeMap': ['Template'],
            'MobileListView': [
                'HeaderTemplate',
                'Template'
            ],
            'MobileScrollView': [
                'EmptyTemplate',
                'Template'
            ],
            'Grid': [
                'AltRowTemplate',
                'DetailTemplate',
                'RowTemplate'
            ],
            'ListView': [
                'EditTemplate',
                'Template',
                'AltTemplate'
            ],
            'Pager': [
                'SelectTemplate',
                'LinkTemplate'
            ],
            'PivotGrid': [
                'ColumnHeaderTemplate',
                'DataCellTemplate',
                'RowHeaderTemplate'
            ],
            'Scheduler': [
                'AllDayEventTemplate',
                'DateHeaderTemplate',
                'EventTemplate',
                'MajorTimeHeaderTemplate',
                'MinorTimeHeaderTemplate'
            ],
            'ScrollView': ['Template'],
            'PanelBar': ['Template'],
            'TreeView': ['Template'],
            'Validator': ['ErrorTemplate']
        };
        (function () {
            var templateDirectives = {};
            angular.forEach(WIDGET_TEMPLATE_OPTIONS, function (templates, widget) {
                angular.forEach(templates, function (template) {
                    if (!templateDirectives[template]) {
                        templateDirectives[template] = [];
                    }
                    templateDirectives[template].push('?^^kendo' + widget);
                });
            });
            angular.forEach(templateDirectives, function (parents, directive) {
                var templateName = 'k' + directive;
                var attrName = kendo.toHyphens(templateName);
                module.directive(templateName, function () {
                    return {
                        restrict: 'A',
                        require: parents,
                        terminal: true,
                        compile: function ($element, $attrs) {
                            if ($attrs[templateName] !== '') {
                                return;
                            }
                            $element.removeAttr(attrName);
                            var template = $element[0].outerHTML;
                            return function (scope, element, attrs, controllers) {
                                var controller;
                                while (!controller && controllers.length) {
                                    controller = controllers.shift();
                                }
                                if (!controller) {
                                    $log.warn(attrName + ' without a matching parent widget found. It can be one of the following: ' + parents.join(', '));
                                } else {
                                    controller.template(templateName, template);
                                    element.remove();
                                }
                            };
                        }
                    };
                });
            });
        }());
    }(window.kendo.jQuery, window.angular));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.web', [
        'kendo.core',
        'kendo.router',
        'kendo.view',
        'kendo.fx',
        'kendo.dom',
        'kendo.data.odata',
        'kendo.data.xml',
        'kendo.data',
        'kendo.ooxml',
        'kendo.excel',
        'kendo.data.signalr',
        'kendo.binder',
        'kendo.drawing',
        'kendo.validator',
        'kendo.userevents',
        'kendo.draganddrop',
        'kendo.mobile.scroller',
        'kendo.groupable',
        'kendo.reorderable',
        'kendo.resizable',
        'kendo.sortable',
        'kendo.selectable',
        'kendo.chat',
        'kendo.button',
        'kendo.buttongroup',
        'kendo.switch',
        'kendo.pager',
        'kendo.popup',
        'kendo.notification',
        'kendo.tooltip',
        'kendo.list',
        'kendo.calendar',
        'kendo.datepicker',
        'kendo.dateinput',
        'kendo.drawer',
        'kendo.multiviewcalendar',
        'kendo.autocomplete',
        'kendo.dropdownlist',
        'kendo.dropdowntree',
        'kendo.combobox',
        'kendo.multiselect',
        'kendo.multicolumncombobox',
        'kendo.colorpicker',
        'kendo.columnmenu',
        'kendo.columnsorter',
        'kendo.grid',
        'kendo.listview',
        'kendo.listbox',
        'kendo.filebrowser',
        'kendo.imagebrowser',
        'kendo.editor',
        'kendo.numerictextbox',
        'kendo.maskedtextbox',
        'kendo.mediaplayer',
        'kendo.menu',
        'kendo.editable',
        'kendo.pivot.fieldmenu',
        'kendo.filtercell',
        'kendo.panelbar',
        'kendo.progressbar',
        'kendo.responsivepanel',
        'kendo.tabstrip',
        'kendo.timepicker',
        'kendo.toolbar',
        'kendo.datetimepicker',
        'kendo.daterangepicker',
        'kendo.treeview.draganddrop',
        'kendo.treeview',
        'kendo.scrollview',
        'kendo.slider',
        'kendo.splitter',
        'kendo.upload',
        'kendo.dialog',
        'kendo.window',
        'kendo.virtuallist',
        'kendo.scheduler.view',
        'kendo.scheduler.dayview',
        'kendo.scheduler.agendaview',
        'kendo.scheduler.monthview',
        'kendo.scheduler.recurrence',
        'kendo.scheduler',
        'kendo.gantt.list',
        'kendo.gantt.timeline',
        'kendo.gantt',
        'kendo.treelist',
        'kendo.pivotgrid',
        'kendo.spreadsheet',
        'kendo.pivot.configurator',
        'kendo.ripple',
        'kendo.pdfviewer',
        'kendo.angular'
    ], f);
}(function () {
    'bundle all';
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.validator', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'validator',
        name: 'Validator',
        category: 'web',
        description: 'The Validator offers an easy way to do a client-side form validation.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo
            , Widget = kendo.ui.Widget
            , NS = '.kendoValidator'
            , INVALIDMSG = 'k-invalid-msg'
            , invalidMsgRegExp = new RegExp(INVALIDMSG, 'i')
            , INVALIDINPUT = 'k-invalid'
            , VALIDINPUT = 'k-valid'
            //, emailRegExp = /^[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])?)*$/i
            , emailRegExp = /^((([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  //Custom Change            
            , urlRegExp = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([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])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i
            //, INPUTSELECTOR = ':input:not(:button,[type=submit],[type=reset],[disabled],[readonly])'
            , INPUTSELECTOR = '[validationMessage],[validationField]'   //Custom Change : INPUTSELECTOR//
            , CHECKBOXSELECTOR = ':checkbox:not([disabled],[readonly])'
            , NUMBERINPUTSELECTOR = '[type=number],[type=range]'
            , BLUR = 'blur', NAME = 'name', FORM = 'form', NOVALIDATE = 'novalidate', VALIDATE = 'validate', CHANGE = 'change'
            , VALIDATE_INPUT = 'validateInput', proxy = $.proxy
            , patternMatcher = function (value, pattern) {
                if (typeof pattern === 'string') {
                    pattern = new RegExp('^(?:' + pattern + ')$');
                }
                return pattern.test(value);
            }, matcher = function (input, selector, pattern) {
                var value = input.val();
                if (input.filter(selector).length && value !== '') {
                    return patternMatcher(value, pattern);
                }
                return true;
            }, hasAttribute = function (input, name) {
                if (input.length) {
                    return input[0].attributes[name] != null;
                }
                return false;
            };
        if (!kendo.ui.validator) {
            kendo.ui.validator = {
                rules: {},
                messages: {}
            };
        }
        function resolveRules(element) {
            var resolvers = kendo.ui.validator.ruleResolvers || {}, rules = {}, name;
            for (name in resolvers) {
                $.extend(true, rules, resolvers[name].resolve(element));
            }
            return rules;
        }
        function decode(value) {
            return value.replace(/&amp/g, '&amp;').replace(/&quot;/g, '"').replace(/&#39;/g, '\'').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
        }
        function numberOfDecimalDigits(value) {
            value = (value + '').split('.');
            if (value.length > 1) {
                return value[1].length;
            }
            return 0;
        }
        function parseHtml(text) {
            if ($.parseHTML) {
                return $($.parseHTML(text));
            }
            return $(text);
        }
        function searchForMessageContainer(elements, fieldName) {
            var containers = $(), element, attr;
            for (var idx = 0, length = elements.length; idx < length; idx++) {
                element = elements[idx];
                if (invalidMsgRegExp.test(element.className)) {
                    attr = element.getAttribute(kendo.attr('for'));
                    if (attr === fieldName) {
                        containers = containers.add(element);
                    }
                }
            }
            return containers;
        }
        var Validator = Widget.extend({
            init: function (element, options) {
                var that = this, resolved = resolveRules(element), validateAttributeSelector = '[' + kendo.attr('validate') + '!=false]';
                options = options || {};
                options.rules = $.extend({}, kendo.ui.validator.rules, resolved.rules, options.rules);
                options.messages = $.extend({}, kendo.ui.validator.messages, resolved.messages, options.messages);
                Widget.fn.init.call(that, element, options);
                that._errorTemplate = kendo.template(that.options.errorTemplate);
                if (that.element.is(FORM)) {
                    that.element.attr(NOVALIDATE, NOVALIDATE);
                }
                that._inputSelector = INPUTSELECTOR + validateAttributeSelector;
                that._checkboxSelector = CHECKBOXSELECTOR + validateAttributeSelector;
                that._errors = {};
                that._attachEvents();
                that._isValidated = false;
            },
            events: [
                VALIDATE,
                CHANGE,
                VALIDATE_INPUT
            ],
            options: {
                name: 'Validator',
                errorTemplate: '<span class="k-widget k-tooltip k-tooltip-validation">' + '<span class="k-icon k-i-warning"> </span> #=message#</span>',
                messages: {
                    required: '{0} is required',
                    pattern: '{0} is not valid',
                    min: '{0} should be greater than or equal to {1}',
                    max: '{0} should be smaller than or equal to {1}',
                    step: '{0} is not valid',
                    email: '{0} is not valid email',
                    url: '{0} is not valid URL',
                    date: '{0} is not valid date',
                    dateCompare: 'End date should be greater than or equal to the start date'
                },
                rules: {
                    required: function (input) {
                        var checkbox = input.filter('[type=checkbox]').length && !input.is(':checked'), value = input.val();
                        //return !(hasAttribute(input, 'required') && (!value || value === '' || value.length === 0 || checkbox));
                        return !(hasAttribute(input, 'required') && (!value || value === '' || value.length === 0 || value == 0 || checkbox)); //Custom Change//
                    },
                    pattern: function (input) {
                        if (input.filter('[type=text],[type=email],[type=url],[type=tel],[type=search],[type=password]').filter('[pattern]').length && input.val() !== '') {
                            return patternMatcher(input.val(), input.attr('pattern'));
                        }
                        return true;
                    },
                    min: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[min]').length && input.val() !== '') {
                            var min = parseFloat(input.attr('min')) || 0, val = kendo.parseFloat(input.val());
                            return min <= val;
                        }
                        return true;
                    },
                    max: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[max]').length && input.val() !== '') {
                            var max = parseFloat(input.attr('max')) || 0, val = kendo.parseFloat(input.val());
                            return max >= val;
                        }
                        return true;
                    },
                    step: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[step]').length && input.val() !== '') {
                            var min = parseFloat(input.attr('min')) || 0, step = parseFloat(input.attr('step')) || 1, val = parseFloat(input.val()), decimals = numberOfDecimalDigits(step), raise;
                            if (decimals) {
                                raise = Math.pow(10, decimals);
                                return Math.floor((val - min) * raise) % (step * raise) / Math.pow(100, decimals) === 0;
                            }
                            return (val - min) % step === 0;
                        }
                        return true;
                    },
                    email: function (input) {
                        return matcher(input, '[type=email],[' + kendo.attr('type') + '=email]', emailRegExp);
                    },
                    url: function (input) {
                        return matcher(input, '[type=url],[' + kendo.attr('type') + '=url]', urlRegExp);
                    },
                    date: function (input) {
                        if (input.filter('[type^=date],[' + kendo.attr('type') + '=date]').length && input.val() !== '') {
                            return kendo.parseDate(input.val(), input.attr(kendo.attr('format'))) !== null;
                        }
                        return true;
                    }
                },
                validateOnBlur: true
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.element.off(NS);
            },
            value: function () {
                if (!this._isValidated) {
                    return false;
                }
                return this.errors().length === 0;
            },
            _submit: function (e) {
                if (!this.validate()) {
                    e.stopPropagation();
                    e.stopImmediatePropagation();
                    e.preventDefault();
                    return false;
                }
                return true;
            },
            _checkElement: function (element) {
                var state = this.value();
                this.validateInput(element);
                if (this.value() !== state) {
                    this.trigger(CHANGE);
                }
            },
            _attachEvents: function () {
                var that = this;
                if (that.element.is(FORM)) {
                    that.element.on('submit' + NS, proxy(that._submit, that));
                }
                if (that.options.validateOnBlur) {
                    if (!that.element.is(INPUTSELECTOR)) {
                        that.element.on(BLUR + NS, that._inputSelector, function () {
                            //if (!$(this).is("[ignorevalidationonblur]")) { //Custom Change -- added if condition//
                                that._checkElement($(this));
                            //}
                        });
                        that.element.on('click' + NS, that._checkboxSelector, function () {
                            that._checkElement($(this));
                        });
                    } else {
                        that.element.on(BLUR + NS, function () {
                            that._checkElement(that.element);
                        });
                        if (that.element.is(CHECKBOXSELECTOR)) {
                            that.element.on('click' + NS, function () {
                                that._checkElement(that.element);
                            });
                        }
                    }
                }
            },
            validate: function () {
                var inputs;
                var idx;
                var result = false;
                var length;
                var isValid = this.value();
                this._errors = {};
                if (!this.element.is(INPUTSELECTOR)) {
                    var invalid = false;

                    //inputs = this.element.find(this._inputSelector);
                    inputs = this.element.hasClass("k-grid-edit-row") ? this.element.find(":input") : this.element.find(this._inputSelector); //Custom Change//                    

                    for (idx = 0, length = inputs.length; idx < length; idx++) {
                        if (inputs.eq(idx).is(':visible') ||
                            ((inputs.eq(idx).filter("[data-role],[" + inputs.eq(idx).attr("data-role") + "=numerictextbox]").length) && ($(inputs.eq(idx)[0].parentElement).find(":input").first().is(':visible')))) { //Custom Change//
                            if (!this.validateInput(inputs.eq(idx))) {
                                invalid = true;
                            }
                        }
                    }
                    result = !invalid;
                } else {
                    result = this.validateInput(this.element);
                }
                this.trigger(VALIDATE, { valid: result });
                if (isValid !== result) {
                    this.trigger(CHANGE);
                }
                return result;
            },

            //Custom Change - START//
            clearValidation: function (input) {
                var that = this;

                that._errors = {};

                input.toggleClass(INVALIDINPUT, false);
                return that.element.toggleClass(INVALIDINPUT, false);
            },
            //Custom Change - END//

            validateInput: function (input) {
                input = $(input);
                this._isValidated = true;
                var that = this, template = that._errorTemplate, result = that._checkValidity(input), valid = result.valid, className = '.' + INVALIDMSG, fieldName = input.attr(NAME) || '', lbl = that._findMessageContainer(fieldName).add(input.next(className).filter(function () {
                    var element = $(this);
                    if (element.filter('[' + kendo.attr('for') + ']').length) {
                        return element.attr(kendo.attr('for')) === fieldName;
                    }
                    return true;
                })).hide(), messageText, wasValid = !input.attr('aria-invalid');
                input.removeAttr('aria-invalid');
                if (!valid) {
                    messageText = that._extractMessage(input, result.key);
                    that._errors[fieldName] = messageText;
                    var messageLabel = parseHtml(template({ message: decode(messageText) }));
                    var lblId = lbl.attr('id');
                    that._decorateMessageContainer(messageLabel, fieldName);
                    if (lblId) {
                        messageLabel.attr('id', lblId);
                    }
                    if (!lbl.replaceWith(messageLabel).length) {
                        messageLabel.insertAfter(input);
                    }
                    messageLabel.show();
                    input.attr('aria-invalid', true);
                } else {
                    delete that._errors[fieldName];
                }
                if (wasValid !== valid) {
                    this.trigger(VALIDATE_INPUT, {
                        valid: valid,
                        input: input
                    });
                }

                ////Custom Change - start//
                //if (input.filter("[data-role],[" + input.attr("data-role") + "=numerictextbox]").length) {
                //    input.parent().toggleClass(INVALIDINPUT, !valid);
                //    input.parent().toggleClass(VALIDINPUT, valid);
                //}
                //else {
                //    input.toggleClass(INVALIDINPUT, !valid);
                //    input.toggleClass(VALIDINPUT, valid);
                //}   
                ////Custom Change - end//
                
                input.toggleClass(INVALIDINPUT, !valid); 
                input.toggleClass(VALIDINPUT, valid); 

                if (kendo.widgetInstance(input)) {
                    var inputWrap = kendo.widgetInstance(input)._inputWrapper;
                    if (inputWrap) {
                        inputWrap.toggleClass(INVALIDINPUT, !valid);
                        inputWrap.toggleClass(INVALIDINPUT, !valid);
                    }
                }

                //Custom Change//
                that.elementValidated(input, result);

                return valid;
            },

            //Custom Change//
            elementValidated: function (element, result) {
            },

            hideMessages: function () {
                var that = this, className = '.' + INVALIDMSG, element = that.element;
                if (!element.is(INPUTSELECTOR)) {
                    element.find(className).hide();
                } else {
                    element.next(className).hide();
                }
            },
            _findMessageContainer: function (fieldName) {
                var locators = kendo.ui.validator.messageLocators, name, containers = $();
                for (var idx = 0, length = this.element.length; idx < length; idx++) {
                    containers = containers.add(searchForMessageContainer(this.element[idx].getElementsByTagName('*'), fieldName));
                }
                for (name in locators) {
                    containers = containers.add(locators[name].locate(this.element, fieldName));
                }
                return containers;
            },
            _decorateMessageContainer: function (container, fieldName) {
                var locators = kendo.ui.validator.messageLocators, name;
                container.addClass(INVALIDMSG).attr(kendo.attr('for'), fieldName || '');
                for (name in locators) {
                    locators[name].decorate(container, fieldName);
                }
                container.attr('role', 'alert');
            },
            _extractMessage: function (input, ruleKey) {
                var that = this, customMessage = that.options.messages[ruleKey]
                    //, fieldName = input.attr(NAME), nonDefaultMessage;  //this is the original line without custom change//
                    , fieldName = input.attr("validationField") ? input.attr("validationField") : input.attr(NAME)  //Custom Change//
                    , nonDefaultMessage;
                if (!kendo.ui.Validator.prototype.options.messages[ruleKey]) {
                    nonDefaultMessage = kendo.isFunction(customMessage) ? customMessage(input) : customMessage;
                }
                customMessage = kendo.isFunction(customMessage) ? customMessage(input) : customMessage;
                return kendo.format(input.attr(kendo.attr(ruleKey + '-msg')) || input.attr('validationMessage') || nonDefaultMessage || input.attr('title') || customMessage || '', fieldName, input.attr(ruleKey) || input.attr(kendo.attr(ruleKey)));
            },
            _checkValidity: function (input) {
                var rules = this.options.rules, rule;
                for (rule in rules) {
                    if (!rules[rule].call(this, input)) {
                        return {
                            valid: false,
                            key: rule
                        };
                    }
                }
                return { valid: true };
            },
            errors: function () {
                var results = [], errors = this._errors, error;
                for (error in errors) {
                    results.push(errors[error]);
                }
                return results;
            }
        });
        kendo.ui.plugin(Validator);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
/** 
 * Kendo UI v2019.2.619 (http://www.telerik.com/kendo-ui)                                                                                                                                               
 * Copyright 2019 Progress Software Corporation and/or one of its subsidiaries or affiliates. All rights reserved.                                                                                      
 *                                                                                                                                                                                                      
 * Kendo UI commercial licenses may be obtained at                                                                                                                                                      
 * http://www.telerik.com/purchase/license-agreement/kendo-ui-complete                                                                                                                                  
 * If you do not own a commercial license, this file shall be governed by the trial license terms.                                                                                                      
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       

*/

(function(f){
    if (typeof define === 'function' && define.amd) {
        define(["kendo.core"], f);
    } else {
        f();
    }
}(function(){
(function( window, undefined ) {
    kendo.cultures["en-GB"] = {
        name: "en-GB",
        numberFormat: {
            pattern: ["-n"],
            decimals: 2,
            ",": ",",
            ".": ".",
            groupSize: [3],
            percent: {
                pattern: ["-n%","n%"],
                decimals: 2,
                ",": ",",
                ".": ".",
                groupSize: [3],
                symbol: "%"
            },
            currency: {
                name: "British Pound",
                abbr: "GBP",
                pattern: ["-$n","$n"],
                decimals: 2,
                ",": ",",
                ".": ".",
                groupSize: [3],
                symbol: "£"
            }
        },
        calendars: {
            standard: {
                days: {
                    names: ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
                    namesAbbr: ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],
                    namesShort: ["Su","Mo","Tu","We","Th","Fr","Sa"]
                },
                months: {
                    names: ["January","February","March","April","May","June","July","August","September","October","November","December"],
                    namesAbbr: ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
                },
                AM: ["AM","am","AM"],
                PM: ["PM","pm","PM"],
                patterns: {
                    d: "dd/MM/yyyy",
                    D: "dd MMMM yyyy",
                    F: "dd MMMM yyyy HH:mm:ss",
                    g: "dd/MM/yyyy HH:mm",
                    G: "dd/MM/yyyy HH:mm:ss",
                    m: "d MMMM",
                    M: "d MMMM",
                    s: "yyyy'-'MM'-'dd'T'HH':'mm':'ss",
                    t: "HH:mm",
                    T: "HH:mm:ss",
                    u: "yyyy'-'MM'-'dd HH':'mm':'ss'Z'",
                    y: "MMMM yyyy",
                    Y: "MMMM yyyy"
                },
                "/": "/",
                ":": ":",
                firstDay: 1
            }
        }
    }
})(this);
}));
