/** 
 * Kendo UI v2016.3.1118 (http://www.telerik.com/kendo-ui)                                                                                                                                              
 * Copyright 2016 Telerik AD. 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.color', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'color',
        name: 'Color utils',
        category: 'framework',
        advanced: true,
        description: 'Color utilities used across components',
        depends: ['core']
    };
    (function ($, parseFloat, parseInt) {
        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 = {
            toHex: function () {
                var color = this, pad = color.padDigit, r = color.r.toString(16), g = color.g.toString(16), b = color.b.toString(16);
                return '#' + pad(r) + pad(g) + pad(b);
            },
            resolveColor: function (value) {
                value = value || 'black';
                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;
            },
            padDigit: function (value) {
                return value.length === 1 ? '0' + value : value;
            },
            brightness: function (value) {
                var color = this, round = Math.round;
                color.r = round(color.normalizeByte(color.r * value));
                color.g = round(color.normalizeByte(color.g * value));
                color.b = round(color.normalizeByte(color.b * value));
                return color;
            },
            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);
            }
        };
        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 = {
            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 namedColorRegexp = ['transparent'];
        for (var i in Color.namedColors) {
            if (Color.namedColors.hasOwnProperty(i)) {
                namedColorRegexp.push(i);
            }
        }
        namedColorRegexp = new RegExp('^(' + namedColorRegexp.join('|') + ')(\\W|$)', 'i');
        function parseColor(color, nothrow) {
            var m, ret;
            if (color == null || color == 'none') {
                return null;
            }
            if (color instanceof _Color) {
                return color;
            }
            color = color.toLowerCase();
            if (m = namedColorRegexp.exec(color)) {
                if (m[1] == 'transparent') {
                    color = new _RGB(1, 1, 1, 0);
                } else {
                    color = parseColor(Color.namedColors[m[1]], nothrow);
                }
                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 (!nothrow) {
                throw new Error('Cannot parse color: ' + color);
            }
            return ret;
        }
        function hex(n, width, pad) {
            if (!pad) {
                pad = '0';
            }
            n = n.toString(16);
            while (width > n.length) {
                n = '0' + n;
            }
            return n;
        }
        function hue2rgb(p, q, t) {
            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;
        }
        var _Color = kendo.Class.extend({
            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((+this.a).toFixed(3)) + ')';
            },
            toDisplay: function () {
                if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
                    return this.toCss();
                }
                return this.toCssRgba();
            },
            equals: function (c) {
                return c === this || c !== null && this.toCssRgba() == parseColor(c).toCssRgba();
            },
            diff: function (c2) {
                if (c2 == null) {
                    return NaN;
                }
                var c1 = this.toBytes();
                c2 = c2.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 = _Color.extend({
            init: function (r, g, b, a) {
                this.r = r;
                this.g = g;
                this.b = b;
                this.a = a;
            },
            toHSV: function () {
                var min, max, delta, h, s, v;
                var r = this.r, g = this.g, b = this.b;
                min = Math.min(r, g, b);
                max = Math.max(r, g, b);
                v = max;
                delta = max - min;
                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 r = this.r, g = this.g, b = this.b;
                var max = Math.max(r, g, b), 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;
                    }
                    h *= 60;
                    s *= 100;
                    l *= 100;
                }
                return new _HSL(h, s, l, 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) {
                this.r = Math.round(r);
                this.g = Math.round(g);
                this.b = Math.round(b);
                this.a = 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;
            }
        });
        var _HSV = _Color.extend({
            init: function (h, s, v, a) {
                this.h = h;
                this.s = s;
                this.v = v;
                this.a = a;
            },
            toRGB: function () {
                var h = this.h, s = this.s, v = this.v;
                var i, r, g, b, f, p, q, t;
                if (s === 0) {
                    r = g = b = v;
                } else {
                    h /= 60;
                    i = Math.floor(h);
                    f = h - i;
                    p = v * (1 - s);
                    q = v * (1 - s * f);
                    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 = _Color.extend({
            init: function (h, s, l, a) {
                this.h = h;
                this.s = s;
                this.l = l;
                this.a = a;
            },
            toRGB: function () {
                var h = this.h, s = this.s, l = this.l;
                var r, g, b;
                if (s === 0) {
                    r = g = b = l;
                } else {
                    h /= 360;
                    s /= 100;
                    l /= 100;
                    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();
            }
        });
        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);
        };
        kendo.Color = Color;
        kendo.parseColor = parseColor;
    }(window.kendo.jQuery, parseFloat, parseInt));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
/** 
 * Kendo UI v2016.3.1118 (http://www.telerik.com/kendo-ui)                                                                                                                                              
 * Copyright 2016 Telerik AD. 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.colorpicker', [
        'kendo.core',
        'kendo.color',
        'kendo.popup',
        'kendo.slider',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'colorpicker',
        name: 'Color tools',
        category: 'web',
        description: 'Color selection widgets',
        depends: [
            'core',
            'color',
            'popup',
            'slider',
            'userevents'
        ]
    };
    (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', APPLY_CANCEL = {
                apply: 'Apply',
                cancel: 'Cancel'
            }, 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 () {
                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;
                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 () {
                    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,
                autoupdate: true,
                messages: APPLY_CANCEL
            },
            _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;
                function hueChange(e) {
                    that._updateUI(that._getHSV(e.value, null, null, null));
                }
                that._hueSlider = element.find('.k-hue-slider').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));
                }
                that._opacitySlider = element.find('.k-transparency-slider').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.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"><input class="k-color-value" #= !data.input ? \'style="visibility: hidden;"\' : "" #></div></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 k-header">' + '<span class="k-picker-wrap k-state-default">' + '# if (toolIcon) { #' + '<span class="k-tool-icon #= toolIcon #">' + '<span class="k-selected-color"></span>' + '</span>' + '# } else { #' + '<span class="k-selected-color"></span>' + '# } #' + '<span class="k-select" unselectable="on" aria-label="select">' + '<span class="k-icon k-i-arrow-s"></span>' + '</span>' + '</span>' + '</span>'),
            options: {
                name: 'ColorPicker',
                palette: null,
                columns: 10,
                toolIcon: null,
                value: null,
                messages: APPLY_CANCEL,
                opacity: false,
                buttons: true,
                preview: true,
                ARIATemplate: 'Current selected color is #=data || ""#'
            },
            events: [
                'activate',
                'change',
                'select',
                'open',
                'close'
            ],
            open: function () {
                if (!this.element.prop('disabled')) {
                    this._getPopup().open();
                }
            },
            close: function () {
                this._getPopup().close();
            },
            toggle: function () {
                if (!this.element.prop('disabled')) {
                    this._getPopup().toggle();
                }
            },
            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() : 'transparent');
            },
            _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.bind({
                        select: function (ev) {
                            that._updateUI(parseColor(ev.value));
                        },
                        change: function () {
                            that._select(selector.color());
                            that.close();
                        },
                        cancel: function () {
                            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();
                            if (!color) {
                                setTimeout(function () {
                                    if (that.wrapper) {
                                        that.wrapper.focus();
                                    }
                                });
                                that._updateUI(that.color());
                            } else {
                                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)();
}));
/** 
 * Kendo UI v2016.3.1118 (http://www.telerik.com/kendo-ui)                                                                                                                                              
 * Copyright 2016 Telerik AD. 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.ooxml', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'ooxml',
        name: 'XLSX generation',
        category: 'framework',
        advanced: true,
        depends: ['core']
    };
    (function ($, kendo) {
        var RELS = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n' + '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' + '<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>' + '<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>' + '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>' + '</Relationships>';
        var CORE = kendo.template('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n' + '<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" ' + 'xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" ' + 'xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + '<dc:creator>${creator}</dc:creator>' + '<cp:lastModifiedBy>${lastModifiedBy}</cp:lastModifiedBy>' + '<dcterms:created xsi:type="dcterms:W3CDTF">${created}</dcterms:created>' + '<dcterms:modified xsi:type="dcterms:W3CDTF">${modified}</dcterms:modified>' + '</cp:coreProperties>');
        var APP = kendo.template('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n' + '<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">' + '<Application>Microsoft Excel</Application>' + '<DocSecurity>0</DocSecurity>' + '<ScaleCrop>false</ScaleCrop>' + '<HeadingPairs>' + '<vt:vector size="2" baseType="variant">' + '<vt:variant>' + '<vt:lpstr>Worksheets</vt:lpstr>' + '</vt:variant>' + '<vt:variant>' + '<vt:i4>${sheets.length}</vt:i4>' + '</vt:variant>' + '</vt:vector>' + '</HeadingPairs>' + '<TitlesOfParts>' + '<vt:vector size="${sheets.length}" baseType="lpstr">' + '# for (var idx = 0; idx < sheets.length; idx++) { #' + '# if (sheets[idx].options.title) { #' + '<vt:lpstr>${sheets[idx].options.title}</vt:lpstr>' + '# } else { #' + '<vt:lpstr>Sheet${idx+1}</vt:lpstr>' + '# } #' + '# } #' + '</vt:vector>' + '</TitlesOfParts>' + '<LinksUpToDate>false</LinksUpToDate>' + '<SharedDoc>false</SharedDoc>' + '<HyperlinksChanged>false</HyperlinksChanged>' + '<AppVersion>14.0300</AppVersion>' + '</Properties>');
        var CONTENT_TYPES = kendo.template('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n' + '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">' + '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />' + '<Default Extension="xml" ContentType="application/xml" />' + '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" />' + '<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>' + '<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>' + '# for (var idx = 1; idx <= count; idx++) { #' + '<Override PartName="/xl/worksheets/sheet${idx}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" />' + '# } #' + '<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml" />' + '<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" />' + '</Types>');
        var WORKBOOK = kendo.template('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n' + '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">' + '<fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="9303" />' + '<workbookPr defaultThemeVersion="124226" />' + '<bookViews>' + '<workbookView xWindow="240" yWindow="45" windowWidth="18195" windowHeight="7995" />' + '</bookViews>' + '<sheets>' + '# for (var idx = 0; idx < sheets.length; idx++) { #' + '# var options = sheets[idx].options; #' + '# var name = options.name || options.title #' + '# if (name) { #' + '<sheet name="${name}" sheetId="${idx+1}" r:id="rId${idx+1}" />' + '# } else { #' + '<sheet name="Sheet${idx+1}" sheetId="${idx+1}" r:id="rId${idx+1}" />' + '# } #' + '# } #' + '</sheets>' + '# if (filterNames.length || userNames.length) { #' + '<definedNames>' + ' # for (var di = 0; di < filterNames.length; di++) { #' + '<definedName name="_xlnm._FilterDatabase" hidden="1" localSheetId="${filterNames[di].localSheetId}">' + '${filterNames[di].name}!$${filterNames[di].from}:$${filterNames[di].to}' + '</definedName>' + ' # } #' + ' # for (var i = 0; i < userNames.length; ++i) { #' + '<definedName name="${userNames[i].name}" hidden="${userNames[i].hidden ? 1 : 0}"' + ' # if (userNames[i].localSheetId != null) { # localSheetId="${userNames[i].localSheetId}" # } #' + '>${userNames[i].value}</definedName>' + ' # } #' + '</definedNames>' + '# } #' + '<calcPr fullCalcOnLoad="1" calcId="145621" />' + '</workbook>');
        var WORKSHEET = kendo.template('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\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">' + '<dimension ref="A1" />' + '<sheetViews>' + '<sheetView #if(index==0) {# tabSelected="1" #}# workbookViewId="0" #if (showGridLines === false) {# showGridLines="0" #}#>' + '# if (frozenRows || frozenColumns) { #' + '<pane state="frozen"' + '# if (frozenColumns) { #' + ' xSplit="${frozenColumns}"' + '# } #' + '# if (frozenRows) { #' + ' ySplit="${frozenRows}"' + '# } #' + ' topLeftCell="${String.fromCharCode(65 + (frozenColumns || 0))}${(frozenRows || 0)+1}"' + '/>' + '# } #' + '</sheetView>' + '</sheetViews>' + '<sheetFormatPr x14ac:dyDescent="0.25" defaultRowHeight="#= defaults.rowHeight ? defaults.rowHeight * 0.75 : 15 #" ' + '# if (defaults.columnWidth) { # defaultColWidth="#= kendo.ooxml.toWidth(defaults.columnWidth) #" # } #' + ' />' + '# if (columns && columns.length > 0) { #' + '<cols>' + '# for (var ci = 0; ci < columns.length; ci++) { #' + '# var column = columns[ci]; #' + '# var columnIndex = typeof column.index === "number" ? column.index + 1 : (ci + 1); #' + '# if (column.width === 0) { #' + '<col min="${columnIndex}" max="${columnIndex}" hidden="1" customWidth="1" />' + '# } else if (column.width) { #' + '<col min="${columnIndex}" max="${columnIndex}" customWidth="1"' + '# if (column.autoWidth) { #' + ' width="${((column.width*7+5)/7*256)/256}" bestFit="1"' + '# } else { #' + ' width="#= kendo.ooxml.toWidth(column.width) #" ' + '# } #' + '/>' + '# } #' + '# } #' + '</cols>' + '# } #' + '<sheetData>' + '# for (var ri = 0; ri < data.length; ri++) { #' + '# var row = data[ri]; #' + '# var rowIndex = typeof row.index === "number" ? row.index + 1 : (ri + 1); #' + '<row r="${rowIndex}" x14ac:dyDescent="0.25" ' + '# if (row.height) { # ht="#= kendo.ooxml.toHeight(row.height) #" customHeight="1" # } #' + ' >' + '# for (var ci = 0; ci < row.data.length; ci++) { #' + '# var cell = row.data[ci];#' + '<c r="#=cell.ref#"# if (cell.style) { # s="#=cell.style#" # } ## if (cell.type) { # t="#=cell.type#"# } #>' + '# if (cell.formula != null) { #' + '<f>${cell.formula}</f>' + '# } #' + '# if (cell.value != null) { #' + '<v>${cell.value}</v>' + '# } #' + '</c>' + '# } #' + '</row>' + '# } #' + '</sheetData>' + '# if (hyperlinks.length) { #' + '<hyperlinks>' + '# for (var hi = 0; hi < hyperlinks.length; hi++) { #' + '<hyperlink ref="${hyperlinks[hi].ref}" r:id="rId${hi}"/>' + '# } #' + '</hyperlinks>' + '# } #' + '# if (filter) { #' + '<autoFilter ref="${filter.from}:${filter.to}"/>' + '# } #' + '# if (mergeCells.length) { #' + '<mergeCells count="${mergeCells.length}">' + '# for (var ci = 0; ci < mergeCells.length; ci++) { #' + '<mergeCell ref="${mergeCells[ci]}"/>' + '# } #' + '</mergeCells>' + '# } #' + '<pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3" />' + '</worksheet>');
        var WORKBOOK_RELS = kendo.template('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n' + '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' + '# for (var idx = 1; idx <= count; idx++) { #' + '<Relationship Id="rId${idx}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet${idx}.xml" />' + '# } #' + '<Relationship Id="rId${count+1}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml" />' + '<Relationship Id="rId${count+2}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml" />' + '</Relationships>');
        var WORKSHEET_RELS = kendo.template('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n' + '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">' + '# for (var i = 0; i < hyperlinks.length; i++) { #' + '<Relationship Id="rId${i}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="${hyperlinks[i].target}" TargetMode="External" />' + '# } #' + '</Relationships>');
        var SHARED_STRINGS = kendo.template('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n' + '<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="${count}" uniqueCount="${uniqueCount}">' + '# for (var index in indexes) { #' + '<si><t>${index.substring(1)}</t></si>' + '# } #' + '</sst>');
        var STYLES = kendo.template('<?xml version="1.0" encoding="UTF-8"?>' + '<styleSheet' + ' xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"' + ' xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"' + ' mc:Ignorable="x14ac"' + ' xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">' + '<numFmts count="${formats.length}">' + '# for (var fi = 0; fi < formats.length; fi++) { #' + '# var format = formats[fi]; #' + '<numFmt formatCode="${format.format}" numFmtId="${165+fi}" />' + '# } #' + '</numFmts>' + '<fonts count="${fonts.length+1}" x14ac:knownFonts="1">' + '<font>' + '<sz val="11" />' + '<color theme="1" />' + '<name val="Calibri" />' + '<family val="2" />' + '<scheme val="minor" />' + '</font>' + '# for (var fi = 0; fi < fonts.length; fi++) { #' + '# var font = fonts[fi]; #' + '<font>' + '# if (font.fontSize) { #' + '<sz val="${font.fontSize}" />' + '# } else { #' + '<sz val="11" />' + '# } #' + '# if (font.bold) { #' + '<b/>' + '# } #' + '# if (font.italic) { #' + '<i/>' + '# } #' + '# if (font.underline) { #' + '<u/>' + '# } #' + '# if (font.color) { #' + '<color rgb="${font.color}" />' + '# } else { #' + '<color theme="1" />' + '# } #' + '# if (font.fontFamily) { #' + '<name val="${font.fontFamily}" />' + '<family val="2" />' + '# } else { #' + '<name val="Calibri" />' + '<family val="2" />' + '<scheme val="minor" />' + '# } #' + '</font>' + '# } #' + '</fonts>' + '<fills count="${fills.length+2}">' + '<fill><patternFill patternType="none"/></fill>' + '<fill><patternFill patternType="gray125"/></fill>' + '# for (var fi = 0; fi < fills.length; fi++) { #' + '# var fill = fills[fi]; #' + '# if (fill.background) { #' + '<fill>' + '<patternFill patternType="solid">' + '<fgColor rgb="${fill.background}"/>' + '</patternFill>' + '</fill>' + '# } #' + '# } #' + '</fills>' + '<borders count="${borders.length+1}">' + '<border><left/><right/><top/><bottom/><diagonal/></border>' + '# for (var bi = 0; bi < borders.length; bi++) { #' + '#= kendo.ooxml.borderTemplate(borders[bi]) #' + '# } #' + '</borders>' + '<cellStyleXfs count="1">' + '<xf borderId="0" fillId="0" fontId="0" />' + '</cellStyleXfs>' + '<cellXfs count="${styles.length+1}">' + '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/>' + '# for (var si = 0; si < styles.length; si++) { #' + '# var style = styles[si]; #' + '<xf xfId="0"' + '# if (style.fontId) { #' + ' fontId="${style.fontId}" applyFont="1"' + '# } #' + '# if (style.fillId) { #' + ' fillId="${style.fillId}" applyFill="1"' + '# } #' + '# if (style.numFmtId) { #' + ' numFmtId="${style.numFmtId}" applyNumberFormat="1"' + '# } #' + '# if (style.textAlign || style.verticalAlign || style.wrap) { #' + ' applyAlignment="1"' + '# } #' + '# if (style.borderId) { #' + ' borderId="${style.borderId}" applyBorder="1"' + '# } #' + '>' + '# if (style.textAlign || style.verticalAlign || style.wrap) { #' + '<alignment' + '# if (style.textAlign) { #' + ' horizontal="${style.textAlign}"' + '# } #' + '# if (style.verticalAlign) { #' + ' vertical="${style.verticalAlign}"' + '# } #' + '# if (style.wrap) { #' + ' wrapText="1"' + '# } #' + '/>' + '# } #' + '</xf>' + '# } #' + '</cellXfs>' + '<cellStyles count="1">' + '<cellStyle name="Normal" xfId="0" builtinId="0"/>' + '</cellStyles>' + '<dxfs count="0" />' + '<tableStyles count="0" defaultTableStyle="TableStyleMedium2" defaultPivotStyle="PivotStyleMedium9" />' + '</styleSheet>');
        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) {
            return (px / 7 * 100 + 0.5) / 100;
        }
        function toHeight(px) {
            return px * 0.75;
        }
        function stripFunnyChars(value) {
            return (value + '').replace(/[\x00-\x08]/g, '').replace(/\n/g, '\r\n');
        }
        var DATE_EPOCH = new Date(1900, 0, 0);
        var Worksheet = kendo.Class.extend({
            init: function (options, sharedStrings, styles, borders) {
                this.options = options;
                this._strings = sharedStrings;
                this._styles = styles;
                this._borders = borders;
            },
            relsToXML: function () {
                var hyperlinks = this.options.hyperlinks || [];
                if (!hyperlinks.length) {
                    return '';
                }
                return WORKSHEET_RELS({ hyperlinks: hyperlinks });
            },
            toXML: function (index) {
                var mergeCells = this.options.mergedCells || [];
                var rows = this.options.rows || [];
                var data = inflate(rows, mergeCells);
                this._readCells(data);
                var filter = this.options.filter;
                if (filter && typeof filter.from === 'number' && typeof filter.to === 'number') {
                    filter = {
                        from: ref(filterRowIndex(this.options), filter.from),
                        to: ref(filterRowIndex(this.options), filter.to)
                    };
                }
                var freezePane = this.options.freezePane || {};
                return WORKSHEET({
                    frozenColumns: this.options.frozenColumns || freezePane.colSplit,
                    frozenRows: this.options.frozenRows || freezePane.rowSplit,
                    columns: this.options.columns,
                    defaults: this.options.defaults || {},
                    data: data,
                    index: index,
                    mergeCells: mergeCells,
                    filter: filter,
                    showGridLines: this.options.showGridLines,
                    hyperlinks: this.options.hyperlinks || []
                });
            },
            _lookupString: function (value) {
                var key = '$' + value;
                var index = this._strings.indexes[key];
                if (index !== undefined) {
                    value = index;
                } else {
                    value = this._strings.indexes[key] = this._strings.uniqueCount;
                    this._strings.uniqueCount++;
                }
                this._strings.count++;
                return value;
            },
            _lookupStyle: function (style) {
                var json = kendo.stringify(style);
                if (json == '{}') {
                    return 0;
                }
                var index = $.inArray(json, this._styles);
                if (index < 0) {
                    index = this._styles.push(json) - 1;
                }
                return index + 1;
            },
            _lookupBorder: function (border) {
                var json = kendo.stringify(border);
                if (json == '{}') {
                    return;
                }
                var index = $.inArray(json, this._borders);
                if (index < 0) {
                    index = this._borders.push(json) - 1;
                }
                return index + 1;
            },
            _readCells: function (rowData) {
                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._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 style = {
                    bold: data.bold,
                    color: data.color,
                    background: data.background,
                    italic: data.italic,
                    underline: data.underline,
                    fontFamily: data.fontFamily || data.fontName,
                    fontSize: data.fontSize,
                    format: data.format,
                    textAlign: data.textAlign || data.hAlign,
                    verticalAlign: data.verticalAlign || data.vAlign,
                    wrap: data.wrap,
                    borderId: border
                };
                var columns = this.options.columns || [];
                var column = columns[cellIndex];
                var type = typeof value;
                if (column && column.autoWidth) {
                    var displayValue = value;
                    if (type === 'number') {
                        displayValue = kendo.toString(value, data.format);
                    }
                    column.width = Math.max(column.width || 0, (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 = +value;
                } else if (value && value.getTime) {
                    type = null;
                    var offset = (value.getTimezoneOffset() - DATE_EPOCH.getTimezoneOffset()) * kendo.date.MS_PER_MINUTE;
                    value = (value - DATE_EPOCH - offset) / kendo.date.MS_PER_DAY + 1;
                    if (!style.format) {
                        style.format = 'mm-dd-yy';
                    }
                } else {
                    type = null;
                    value = null;
                }
                style = this._lookupStyle(style);
                return {
                    value: value,
                    formula: data.formula,
                    type: type,
                    style: style,
                    ref: ref(rowIndex, cellIndex)
                };
            }
        });
        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(color) {
            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) {
                this.options = options || {};
                this._strings = {
                    indexes: {},
                    count: 0,
                    uniqueCount: 0
                };
                this._styles = [];
                this._borders = [];
                this._sheets = $.map(this.options.sheets || [], $.proxy(function (options) {
                    options.defaults = this.options;
                    return new Worksheet(options, this._strings, this._styles, this._borders);
                }, this));
            },
            toDataURL: 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.');
                }
                var zip = new JSZip();
                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 }));
                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 && 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 sheetRels = worksheets.folder('_rels');
                for (var idx = 0; idx < sheetCount; idx++) {
                    var sheet = this._sheets[idx];
                    var sheetName = kendo.format('sheet{0}.xml', idx + 1);
                    var relsXml = sheet.relsToXML();
                    if (relsXml) {
                        sheetRels.file(sheetName + '.rels', relsXml);
                    }
                    worksheets.file(sheetName, sheet.toXML(idx));
                }
                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 fonts = $.map(styles, function (style) {
                    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 = $.inArray(style, fonts) + 1;
                        }
                        if (style.background) {
                            result.fillId = $.inArray(style, fills) + 2;
                        }
                        result.textAlign = style.textAlign;
                        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 + $.inArray(style, formats);
                            }
                        }
                        return result;
                    })
                }));
                xl.file('sharedStrings.xml', SHARED_STRINGS(this._strings));
                zip.file('[Content_Types].xml', CONTENT_TYPES({ count: sheetCount }));
                return 'data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,' + zip.generate({ compression: 'DEFLATE' });
            }
        });
        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,
                    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 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);
                spanCell(cell, cellData, cellIndex, colSpan);
                if (rowSpan > 1 || colSpan > 1) {
                    ctx.mergedCells.push(ref(rowIndex, cellIndex) + ':' + 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);
            }
        }
        kendo.ooxml = {
            Workbook: Workbook,
            Worksheet: Worksheet,
            toWidth: toWidth,
            toHeight: toHeight,
            borderTemplate: borderTemplate
        };
    }(kendo.jQuery, kendo));
    return kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
/** 
 * Kendo UI v2016.3.1118 (http://www.telerik.com/kendo-ui)                                                                                                                                              
 * Copyright 2016 Telerik AD. 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.excel', [
        'kendo.core',
        'kendo.data',
        'kendo.ooxml'
    ], f);
}(function () {
    var __meta__ = {
        id: 'excel',
        name: 'Excel export',
        category: 'framework',
        advanced: true,
        mixin: true,
        depends: [
            'data',
            'ooxml'
        ]
    };
    (function ($, kendo) {
        kendo.ExcelExporter = kendo.Class.extend({
            init: function (options) {
                options.columns = this._trimColumns(options.columns || []);
                this.allColumns = $.map(this._leafColumns(options.columns || []), this._prepareColumn);
                this.columns = $.grep(this.allColumns, function (column) {
                    return !column.hidden;
                });
                this.options = options;
                var dataSource = options.dataSource;
                if (dataSource instanceof kendo.data.DataSource) {
                    this.dataSource = new dataSource.constructor($.extend({}, dataSource.options, {
                        page: options.allPages ? 0 : dataSource.page(),
                        filter: dataSource.filter(),
                        pageSize: options.allPages ? dataSource.total() : dataSource.pageSize(),
                        sort: dataSource.sort(),
                        group: dataSource.group(),
                        aggregate: dataSource.aggregate()
                    }));
                    var data = dataSource.data();
                    if (data.length > 0) {
                        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);
                }
            },
            _trimColumns: function (columns) {
                var that = this;
                return $.grep(columns, function (column) {
                    var result = !!column.field;
                    if (!result && column.columns) {
                        result = that._trimColumns(column.columns).length > 0;
                    }
                    return result;
                });
            },
            _leafColumns: function (columns) {
                var result = [];
                for (var idx = 0; idx < columns.length; idx++) {
                    if (!columns[idx].columns) {
                        result.push(columns[idx]);
                        continue;
                    }
                    result = result.concat(this._leafColumns(columns[idx].columns));
                }
                return result;
            },
            workbook: function () {
                return $.Deferred($.proxy(function (d) {
                    this.dataSource.fetch().then($.proxy(function () {
                        var workbook = {
                            sheets: [{
                                    columns: this._columns(),
                                    rows: this._rows(),
                                    freezePane: this._freezePane(),
                                    filter: this._filter()
                                }]
                        };
                        d.resolve(workbook, this.dataSource.view());
                    }, this));
                }, this)).promise();
            },
            _prepareColumn: function (column) {
                if (!column.field) {
                    return;
                }
                var value = function (dataItem) {
                    return dataItem.get(column.field);
                };
                var values = null;
                if (column.values) {
                    values = {};
                    $.each(column.values, function () {
                        values[this.value] = this.text;
                    });
                    value = function (dataItem) {
                        return values[dataItem.get(column.field)];
                    };
                }
                return $.extend({}, column, {
                    value: value,
                    values: values,
                    groupHeaderTemplate: kendo.template(column.groupHeaderTemplate || '#= title #: #= value #'),
                    groupFooterTemplate: column.groupFooterTemplate ? kendo.template(column.groupFooterTemplate) : null,
                    footerTemplate: column.footerTemplate ? kendo.template(column.footerTemplate) : null
                });
            },
            _filter: function () {
                if (!this.options.filterable) {
                    return null;
                }
                var depth = this._depth();
                return {
                    from: depth,
                    to: depth + this.columns.length - 1
                };
            },
            _dataRow: function (dataItem, level, depth) {
                if (this._hierarchical()) {
                    level = this.dataSource.level(dataItem) + 1;
                }
                var cells = [];
                for (var li = 0; li < level; li++) {
                    cells[li] = {
                        background: '#dfdfdf',
                        color: '#333'
                    };
                }
                if (depth && dataItem.items) {
                    var column = $.grep(this.allColumns, function (column) {
                        return column.field == dataItem.field;
                    })[0];
                    var title = column && column.title ? column.title : dataItem.field;
                    var template = column ? column.groupHeaderTemplate : null;
                    var value = title + ': ' + dataItem.value;
                    var group = $.extend({
                        title: title,
                        field: dataItem.field,
                        value: column && column.values ? column.values[dataItem.value] : dataItem.value,
                        aggregates: dataItem.aggregates
                    }, dataItem.aggregates[dataItem.field]);
                    if (template) {
                        value = template(group);
                    }
                    cells.push({
                        value: value,
                        background: '#dfdfdf',
                        color: '#333',
                        colSpan: this.columns.length + depth - level
                    });
                    var rows = this._dataRows(dataItem.items, level + 1);
                    rows.unshift({
                        type: 'group-header',
                        cells: cells
                    });
                    return rows.concat(this._footer(dataItem));
                } else {
                    var dataCells = [];
                    for (var ci = 0; ci < this.columns.length; ci++) {
                        dataCells[ci] = this._cell(dataItem, this.columns[ci]);
                    }
                    if (this._hierarchical()) {
                        dataCells[0].colSpan = depth - level + 1;
                    }
                    return [{
                            type: 'data',
                            cells: cells.concat(dataCells)
                        }];
                }
            },
            _dataRows: function (dataItems, level) {
                var depth = this._depth();
                var rows = [];
                for (var i = 0; i < dataItems.length; i++) {
                    rows.push.apply(rows, this._dataRow(dataItems[i], level, depth));
                }
                return rows;
            },
            _footer: function (dataItem) {
                var rows = [];
                var footer = false;
                var cells = $.map(this.columns, $.proxy(function (column) {
                    if (column.groupFooterTemplate) {
                        footer = true;
                        return {
                            background: '#dfdfdf',
                            color: '#333',
                            value: column.groupFooterTemplate($.extend({}, this.dataSource.aggregates(), dataItem.aggregates, dataItem.aggregates[column.field]))
                        };
                    } else {
                        return {
                            background: '#dfdfdf',
                            color: '#333'
                        };
                    }
                }, this));
                if (footer) {
                    rows.push({
                        type: 'group-footer',
                        cells: $.map(new Array(this.dataSource.group().length), function () {
                            return {
                                background: '#dfdfdf',
                                color: '#333'
                            };
                        }).concat(cells)
                    });
                }
                return rows;
            },
            _isColumnVisible: function (column) {
                return this._visibleColumns([column]).length > 0 && (column.field || column.columns);
            },
            _visibleColumns: function (columns) {
                var that = this;
                return $.grep(columns, function (column) {
                    var result = !column.hidden;
                    if (result && column.columns) {
                        result = that._visibleColumns(column.columns).length > 0;
                    }
                    return result;
                });
            },
            _headerRow: function (row, groups) {
                var headers = $.map(row.cells, function (cell) {
                    return {
                        background: '#7a7a7a',
                        color: '#fff',
                        value: cell.title,
                        colSpan: cell.colSpan > 1 ? cell.colSpan : 1,
                        rowSpan: row.rowSpan > 1 && !cell.colSpan ? row.rowSpan : 1
                    };
                });
                if (this._hierarchical()) {
                    headers[0].colSpan = this._depth() + 1;
                }
                return {
                    type: 'header',
                    cells: $.map(new Array(groups.length), function () {
                        return {
                            background: '#7a7a7a',
                            color: '#fff'
                        };
                    }).concat(headers)
                };
            },
            _prependHeaderRows: function (rows) {
                var groups = this.dataSource.group();
                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._headerRow(headerRows[idx], groups));
                }
            },
            _prepareHeaderRows: function (rows, columns, parentCell, parentRow) {
                var row = parentRow || rows[rows.length - 1];
                var childRow = rows[row.index + 1];
                var totalColSpan = 0;
                var column;
                var cell;
                for (var idx = 0; idx < columns.length; idx++) {
                    column = columns[idx];
                    if (this._isColumnVisible(column)) {
                        cell = {
                            title: column.title || column.field,
                            colSpan: 0
                        };
                        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._trimColumns(this._visibleColumns(column.columns)).length;
                            this._prepareHeaderRows(rows, column.columns, cell, childRow);
                            totalColSpan += cell.colSpan - 1;
                            row.rowSpan = rows.length - row.index;
                        }
                    }
                }
                if (parentCell) {
                    parentCell.colSpan += totalColSpan;
                }
            },
            _rows: function () {
                var groups = this.dataSource.group();
                var rows = this._dataRows(this.dataSource.view(), 0);
                if (this.columns.length) {
                    this._prependHeaderRows(rows);
                    var footer = false;
                    var cells = $.map(this.columns, $.proxy(function (column) {
                        if (column.footerTemplate) {
                            footer = true;
                            var aggregates = this.dataSource.aggregates();
                            return {
                                background: '#dfdfdf',
                                color: '#333',
                                value: column.footerTemplate($.extend({}, aggregates, aggregates[column.field]))
                            };
                        } else {
                            return {
                                background: '#dfdfdf',
                                color: '#333'
                            };
                        }
                    }, this));
                    if (footer) {
                        rows.push({
                            type: 'footer',
                            cells: $.map(new Array(groups.length), function () {
                                return {
                                    background: '#dfdfdf',
                                    color: '#333'
                                };
                            }).concat(cells)
                        });
                    }
                }
                return rows;
            },
            _headerDepth: function (columns) {
                var result = 1;
                var max = 0;
                for (var idx = 0; idx < columns.length; idx++) {
                    if (columns[idx].columns) {
                        var temp = this._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($.grep(columns, function (column) {
                    return column.locked;
                })))).length;
                return {
                    rowSplit: this._headerDepth(columns),
                    colSplit: colSplit ? colSplit + this.dataSource.group().length : 0
                };
            },
            _cell: function (dataItem, column) {
                return { value: column.value(dataItem) };
            },
            _hierarchical: function () {
                return this.options.hierarchy && this.dataSource.level;
            },
            _depth: function () {
                var dataSource = this.dataSource;
                var depth = 0;
                var view, i, level;
                if (this._hierarchical()) {
                    view = dataSource.view();
                    for (i = 0; i < view.length; i++) {
                        level = dataSource.level(view[i]);
                        if (level > depth) {
                            depth = level;
                        }
                    }
                    depth++;
                } else {
                    depth = dataSource.group().length;
                }
                return depth;
            },
            _columns: function () {
                var depth = this._depth();
                var columns = $.map(new Array(depth), function () {
                    return { width: 20 };
                });
                return columns.concat($.map(this.columns, function (column) {
                    return {
                        width: parseInt(column.width, 10),
                        autoWidth: column.width ? false : true
                    };
                }));
            }
        });
        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'
            },
            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
                });
                exporter.workbook().then($.proxy(function (book, data) {
                    if (!this.trigger('excelExport', {
                            workbook: book,
                            data: data
                        })) {
                        var workbook = new kendo.ooxml.Workbook(book);
                        kendo.saveAs({
                            dataURI: workbook.toDataURL(),
                            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)();
}));
/** 
 * Kendo UI v2016.3.1118 (http://www.telerik.com/kendo-ui)                                                                                                                                              
 * Copyright 2016 Telerik AD. 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('util/main', ['kendo.core'], f);
}(function () {
    (function () {
        var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend;
        var DEG_TO_RAD = math.PI / 180, MAX_NUM = Number.MAX_VALUE, MIN_NUM = -Number.MAX_VALUE, UNDEFINED = 'undefined';
        function defined(value) {
            return typeof value !== UNDEFINED;
        }
        function round(value, precision) {
            var power = pow(precision);
            return math.round(value * power) / power;
        }
        function pow(p) {
            if (p) {
                return math.pow(10, p);
            } else {
                return 1;
            }
        }
        function limitValue(value, min, max) {
            return math.max(math.min(value, max), min);
        }
        function rad(degrees) {
            return degrees * DEG_TO_RAD;
        }
        function deg(radians) {
            return radians / DEG_TO_RAD;
        }
        function isNumber(val) {
            return typeof val === 'number' && !isNaN(val);
        }
        function valueOrDefault(value, defaultValue) {
            return defined(value) ? value : defaultValue;
        }
        function sqr(value) {
            return value * value;
        }
        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 hashObject(object) {
            return hashKey(objectKey(object));
        }
        var now = Date.now;
        if (!now) {
            now = function () {
                return new Date().getTime();
            };
        }
        function arrayLimits(arr) {
            var length = arr.length, i, min = MAX_NUM, max = MIN_NUM;
            for (i = 0; i < length; i++) {
                max = math.max(max, arr[i]);
                min = math.min(min, arr[i]);
            }
            return {
                min: min,
                max: max
            };
        }
        function arrayMin(arr) {
            return arrayLimits(arr).min;
        }
        function arrayMax(arr) {
            return arrayLimits(arr).max;
        }
        function sparseArrayMin(arr) {
            return sparseArrayLimits(arr).min;
        }
        function sparseArrayMax(arr) {
            return sparseArrayLimits(arr).max;
        }
        function sparseArrayLimits(arr) {
            var min = MAX_NUM, max = MIN_NUM;
            for (var i = 0, length = arr.length; i < length; i++) {
                var n = arr[i];
                if (n !== null && isFinite(n)) {
                    min = math.min(min, n);
                    max = math.max(max, n);
                }
            }
            return {
                min: min === MAX_NUM ? undefined : min,
                max: max === MIN_NUM ? undefined : max
            };
        }
        function last(array) {
            if (array) {
                return array[array.length - 1];
            }
        }
        function append(first, second) {
            first.push.apply(first, second);
            return first;
        }
        function renderTemplate(text) {
            return kendo.template(text, {
                useWithBlock: false,
                paramName: 'd'
            });
        }
        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;
            }
        }
        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 isTransparent(color) {
            return color === '' || color === null || color === 'none' || color === 'transparent' || !defined(color);
        }
        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 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 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);
        }
        deepExtend(kendo, {
            util: {
                MAX_NUM: MAX_NUM,
                MIN_NUM: MIN_NUM,
                append: append,
                arrayLimits: arrayLimits,
                arrayMin: arrayMin,
                arrayMax: arrayMax,
                defined: defined,
                deg: deg,
                hashKey: hashKey,
                hashObject: hashObject,
                isNumber: isNumber,
                isTransparent: isTransparent,
                last: last,
                limitValue: limitValue,
                now: now,
                objectKey: objectKey,
                round: round,
                rad: rad,
                renderAttr: renderAttr,
                renderAllAttr: renderAllAttr,
                renderPos: renderPos,
                renderSize: renderSize,
                renderStyle: renderStyle,
                renderTemplate: renderTemplate,
                sparseArrayLimits: sparseArrayLimits,
                sparseArrayMin: sparseArrayMin,
                sparseArrayMax: sparseArrayMax,
                sqr: sqr,
                valueOrDefault: valueOrDefault,
                romanToArabic: romanToArabic,
                arabicToRoman: arabicToRoman,
                memoize: memoize,
                ucs2encode: ucs2encode,
                ucs2decode: ucs2decode,
                mergeSort: mergeSort
            }
        });
        kendo.drawing.util = kendo.util;
        kendo.dataviz.util = kendo.util;
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/text-metrics', [
        'kendo.core',
        'util/main'
    ], f);
}(function () {
    (function ($) {
        var doc = document, kendo = window.kendo, Class = kendo.Class, util = kendo.util, defined = util.defined;
        var LRUCache = Class.extend({
            init: function (size) {
                this._size = size;
                this._length = 0;
                this._map = {};
            },
            put: function (key, value) {
                var lru = this, map = lru._map, entry = {
                        key: key,
                        value: value
                    };
                map[key] = entry;
                if (!lru._head) {
                    lru._head = lru._tail = entry;
                } else {
                    lru._tail.newer = entry;
                    entry.older = lru._tail;
                    lru._tail = entry;
                }
                if (lru._length >= lru._size) {
                    map[lru._head.key] = null;
                    lru._head = lru._head.newer;
                    lru._head.older = null;
                } else {
                    lru._length++;
                }
            },
            get: function (key) {
                var lru = this, entry = lru._map[key];
                if (entry) {
                    if (entry === lru._head && entry !== lru._tail) {
                        lru._head = entry.newer;
                        lru._head.older = null;
                    }
                    if (entry !== lru._tail) {
                        if (entry.older) {
                            entry.older.newer = entry.newer;
                            entry.newer.older = entry.older;
                        }
                        entry.older = lru._tail;
                        entry.newer = null;
                        lru._tail.newer = entry;
                        lru._tail = entry;
                    }
                    return entry.value;
                }
            }
        });
        var defaultMeasureBox = $('<div style=\'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: nowrap!important;\' />')[0];
        function zeroSize() {
            return {
                width: 0,
                height: 0,
                baseline: 0
            };
        }
        var TextMetrics = Class.extend({
            init: function (options) {
                this._cache = new LRUCache(1000);
                this._initOptions(options);
            },
            options: { baselineMarkerSize: 1 },
            measure: function (text, style, box) {
                if (!text) {
                    return zeroSize();
                }
                var styleKey = util.objectKey(style), cacheKey = util.hashKey(text + styleKey), cachedResult = this._cache.get(cacheKey);
                if (cachedResult) {
                    return cachedResult;
                }
                var size = zeroSize();
                var measureBox = box ? box : defaultMeasureBox;
                var baselineMarker = this._baselineMarker().cloneNode(false);
                for (var key in style) {
                    var value = style[key];
                    if (defined(value)) {
                        measureBox.style[key] = value;
                    }
                }
                $(measureBox).text(text);
                measureBox.appendChild(baselineMarker);
                doc.body.appendChild(measureBox);
                if ((text + '').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 () {
                return $('<div class=\'k-baseline-marker\' ' + 'style=\'display: inline-block; vertical-align: baseline;' + 'width: ' + this.options.baselineMarkerSize + 'px; height: ' + this.options.baselineMarkerSize + 'px;' + 'overflow: hidden;\' />')[0];
            }
        });
        TextMetrics.current = new TextMetrics();
        function measureText(text, style, measureBox) {
            return TextMetrics.current.measure(text, style, measureBox);
        }
        function loadFonts(fonts, callback) {
            var promises = [];
            if (fonts.length > 0 && document.fonts) {
                try {
                    promises = fonts.map(function (font) {
                        return document.fonts.load(font);
                    });
                } catch (e) {
                    kendo.logToConsole(e);
                }
                Promise.all(promises).then(callback, callback);
            } else {
                callback();
            }
        }
        kendo.util.TextMetrics = TextMetrics;
        kendo.util.LRUCache = LRUCache;
        kendo.util.loadFonts = loadFonts;
        kendo.util.measureText = measureText;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/base64', ['util/main'], f);
}(function () {
    (function () {
        var kendo = window.kendo, deepExtend = kendo.deepExtend, fromCharCode = String.fromCharCode;
        var KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        function encodeBase64(input) {
            var output = '';
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;
            input = encodeUTF8(input);
            while (i < input.length) {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);
                enc1 = chr1 >> 2;
                enc2 = (chr1 & 3) << 4 | chr2 >> 4;
                enc3 = (chr2 & 15) << 2 | chr3 >> 6;
                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 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;
        }
        deepExtend(kendo.util, {
            encodeBase64: encodeBase64,
            encodeUTF8: encodeUTF8
        });
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('mixins/observers', ['kendo.core'], f);
}(function () {
    (function ($) {
        var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend, inArray = $.inArray;
        var ObserversMixin = {
            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 = inArray(element, observers);
                if (index != -1) {
                    observers.splice(index, 1);
                }
                return this;
            },
            trigger: function (methodName, event) {
                var observers = this._observers;
                var observer;
                var idx;
                if (observers && !this._suspended) {
                    for (idx = 0; idx < observers.length; idx++) {
                        observer = observers[idx];
                        if (observer[methodName]) {
                            observer[methodName](event);
                        }
                    }
                }
                return this;
            },
            optionsChange: function (e) {
                e = 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);
            }
        };
        deepExtend(kendo, { mixins: { ObserversMixin: ObserversMixin } });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/geometry', [
        'util/main',
        'mixins/observers'
    ], f);
}(function () {
    (function () {
        var math = Math, pow = math.pow, kendo = window.kendo, Class = kendo.Class, deepExtend = kendo.deepExtend, ObserversMixin = kendo.mixins.ObserversMixin, util = kendo.util, defined = util.defined, rad = util.rad, deg = util.deg, round = util.round;
        var PI_DIV_2 = math.PI / 2, MIN_NUM = util.MIN_NUM, MAX_NUM = util.MAX_NUM, PRECISION = 10;
        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) {
                return this.transform(transform().rotate(angle, origin));
            },
            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 (!defined(scaleY)) {
                    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 mx = toMatrix(transformation), x = this.x, y = this.y;
                this.x = mx.a * x + mx.c * y + mx.e;
                this.y = mx.b * x + mx.d * y + mx.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
                ];
            }
        });
        defineAccessors(Point.fn, [
            'x',
            'y'
        ]);
        deepExtend(Point.fn, ObserversMixin);
        Point.fn.toString = function (digits, separator) {
            var x = this.x, y = this.y;
            if (defined(digits)) {
                x = round(x, digits);
                y = round(y, digits);
            }
            separator = separator || ' ';
            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]);
                } else {
                    return new Point(arg0, arg1);
                }
            }
        };
        Point.min = function () {
            var minX = util.MAX_NUM;
            var minY = util.MAX_NUM;
            for (var i = 0; i < arguments.length; i++) {
                var pt = arguments[i];
                minX = math.min(pt.x, minX);
                minY = math.min(pt.y, minY);
            }
            return new Point(minX, minY);
        };
        Point.max = function () {
            var maxX = util.MIN_NUM;
            var maxY = util.MIN_NUM;
            for (var i = 0; i < arguments.length; i++) {
                var pt = arguments[i];
                maxX = math.max(pt.x, maxX);
                maxY = math.max(pt.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);
        };
        Point.ZERO = new Point(0, 0);
        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
                ];
            }
        });
        defineAccessors(Size.fn, [
            'width',
            'height'
        ]);
        deepExtend(Size.fn, ObserversMixin);
        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]);
                } else {
                    return new Size(arg0, arg1);
                }
            }
        };
        Size.ZERO = new Size(0, 0);
        var Rect = Class.extend({
            init: function (origin, size) {
                this.setOrigin(origin || new Point());
                this.setSize(size || new 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 (!defined(y)) {
                    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);
            }
        });
        deepExtend(Rect.fn, ObserversMixin);
        Rect.fromPoints = function () {
            var topLeft = Point.min.apply(this, arguments);
            var bottomRight = Point.max.apply(this, 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) {
            a = {
                left: a.topLeft().x,
                top: a.topLeft().y,
                right: a.bottomRight().x,
                bottom: a.bottomRight().y
            };
            b = {
                left: b.topLeft().x,
                top: b.topLeft().y,
                right: b.bottomRight().x,
                bottom: b.bottomRight().y
            };
            if (a.left <= b.right && b.left <= a.right && a.top <= b.bottom && b.top <= a.bottom) {
                return Rect.fromPoints(new Point(math.max(a.left, b.left), math.max(a.top, b.top)), new Point(math.min(a.right, b.right), math.min(a.bottom, b.bottom)));
            }
        };
        var Circle = Class.extend({
            init: function (center, radius) {
                this.setCenter(center || new Point());
                this.setRadius(radius || 0);
            },
            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(this.center.clone(), this.radius);
            },
            pointAt: function (angle) {
                return this._pointAt(rad(angle));
            },
            bbox: function (matrix) {
                var minPoint = Point.maxPoint();
                var maxPoint = Point.minPoint();
                var extremeAngles = ellipseExtremeAngles(this.center, this.radius, this.radius, matrix);
                for (var i = 0; i < 4; i++) {
                    var currentPointX = this._pointAt(extremeAngles.x + i * PI_DIV_2).transformCopy(matrix);
                    var currentPointY = this._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 c = this.center;
                var r = this.radius;
                return new Point(c.x - r * math.cos(angle), c.y - r * math.sin(angle));
            },
            containsPoint: function (point) {
                var center = this.center;
                var inCircle = math.pow(point.x - center.x, 2) + math.pow(point.y - center.y, 2) <= math.pow(this.radius, 2);
                return inCircle;
            },
            _isOnPath: function (point, width) {
                var center = this.center;
                var radius = this.radius;
                var pointDistance = center.distanceTo(point);
                return radius - width <= pointDistance && pointDistance <= radius + width;
            }
        });
        defineAccessors(Circle.fn, ['radius']);
        deepExtend(Circle.fn, ObserversMixin);
        var Arc = Class.extend({
            init: function (center, options) {
                this.setCenter(center || new Point());
                options = options || {};
                this.radiusX = options.radiusX;
                this.radiusY = options.radiusY || options.radiusX;
                this.startAngle = options.startAngle;
                this.endAngle = options.endAngle;
                this.anticlockwise = options.anticlockwise || false;
            },
            clone: function () {
                return new Arc(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;
            },
            MAX_INTERVAL: 45,
            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 startAngle = this.startAngle;
                var dir = this.anticlockwise ? -1 : 1;
                var curvePoints = [this.pointAt(startAngle)];
                var currentAngle = startAngle;
                var interval = this._arcInterval();
                var intervalAngle = interval.endAngle - interval.startAngle;
                var subIntervalsCount = math.ceil(intervalAngle / this.MAX_INTERVAL);
                var subIntervalAngle = intervalAngle / subIntervalsCount;
                for (var i = 1; i <= subIntervalsCount; i++) {
                    var nextAngle = currentAngle + dir * subIntervalAngle;
                    var points = this._intervalCurvePoints(currentAngle, nextAngle);
                    curvePoints.push(points.cp1, points.cp2, points.p2);
                    currentAngle = nextAngle;
                }
                return curvePoints;
            },
            bbox: function (matrix) {
                var arc = this;
                var interval = arc._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 currentPoint = arc.pointAt(startAngle).transformCopy(matrix);
                var endPoint = arc.pointAt(endAngle).transformCopy(matrix);
                var minPoint = Point.min(currentPoint, endPoint);
                var maxPoint = Point.max(currentPoint, endPoint);
                var currentAngleX = bboxStartAngle(extremeX, startAngle);
                var currentAngleY = bboxStartAngle(extremeY, startAngle);
                while (currentAngleX < endAngle || currentAngleY < endAngle) {
                    var currentPointX;
                    if (currentAngleX < endAngle) {
                        currentPointX = arc.pointAt(currentAngleX).transformCopy(matrix);
                        currentAngleX += 90;
                    }
                    var currentPointY;
                    if (currentAngleY < endAngle) {
                        currentPointY = arc.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 startAngle = this.startAngle;
                var endAngle = this.endAngle;
                var anticlockwise = this.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) {
                var arc = this;
                var p1 = arc.pointAt(startAngle);
                var p2 = arc.pointAt(endAngle);
                var p1Derivative = arc._derivativeAt(startAngle);
                var p2Derivative = arc._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);
                return {
                    p1: p1,
                    cp1: cp1,
                    cp2: cp2,
                    p2: p2
                };
            },
            _derivativeAt: function (angle) {
                var arc = this;
                var radian = rad(angle);
                return new Point(-arc.radiusX * math.sin(radian), arc.radiusY * math.cos(radian));
            },
            containsPoint: function (point) {
                var interval = this._arcInterval();
                var intervalAngle = interval.endAngle - interval.startAngle;
                var center = this.center;
                var distance = center.distanceTo(point);
                var angleRad = math.atan2(point.y - center.y, point.x - center.x);
                var pointRadius = this.radiusX * this.radiusY / math.sqrt(math.pow(this.radiusX, 2) * math.pow(math.sin(angleRad), 2) + math.pow(this.radiusY, 2) * math.pow(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, this.radiusX, this.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;
            }
        });
        defineAccessors(Arc.fn, [
            'radiusX',
            'radiusY',
            'startAngle',
            'endAngle',
            'anticlockwise'
        ]);
        deepExtend(Arc.fn, ObserversMixin);
        Arc.fromPoints = function (start, end, rx, ry, largeArc, swipe) {
            var arcParameters = normalizeArcParameters(start.x, start.y, end.x, end.y, rx, ry, largeArc, swipe);
            return new Arc(arcParameters.center, {
                startAngle: arcParameters.startAngle,
                endAngle: arcParameters.endAngle,
                radiusX: rx,
                radiusY: ry,
                anticlockwise: swipe === 0
            });
        };
        var Matrix = Class.extend({
            init: function (a, b, c, d, e, f) {
                this.a = a || 0;
                this.b = b || 0;
                this.c = c || 0;
                this.d = d || 0;
                this.e = e || 0;
                this.f = f || 0;
            },
            multiplyCopy: function (m) {
                return new Matrix(this.a * m.a + this.c * m.b, this.b * m.a + this.d * m.b, this.a * m.c + this.c * m.d, this.b * m.c + this.d * m.d, this.a * m.e + this.c * m.f + this.e, this.b * m.e + this.d * m.f + this.f);
            },
            invert: function () {
                var a = this.a, b = this.b;
                var d = this.c, e = this.d;
                var g = this.e, h = this.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 arr = [
                    this.a,
                    this.b,
                    this.c,
                    this.d,
                    this.e,
                    this.f
                ];
                if (defined(precision)) {
                    for (var i = 0; i < arr.length; i++) {
                        arr[i] = round(arr[i], precision);
                    }
                }
                return arr;
            }
        });
        Matrix.fn.toString = function (precision, 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 m = new Matrix();
            m.a = math.cos(rad(angle));
            m.b = math.sin(rad(angle));
            m.c = -m.b;
            m.d = m.a;
            m.e = x - x * m.a + y * m.b || 0;
            m.f = y - y * m.a - x * m.b || 0;
            return m;
        };
        Matrix.scale = function (scaleX, scaleY) {
            return new Matrix(scaleX, 0, 0, scaleY, 0, 0);
        };
        Matrix.IDENTITY = Matrix.unit();
        var Transformation = Class.extend({
            init: function (matrix) {
                this._matrix = matrix || Matrix.unit();
            },
            clone: function () {
                return new Transformation(this._matrix.clone());
            },
            equals: function (other) {
                return other && other._matrix.equals(this._matrix);
            },
            _optionsChange: function () {
                this.optionsChange({
                    field: 'transform',
                    value: this
                });
            },
            translate: function (x, y) {
                this._matrix = this._matrix.multiplyCopy(Matrix.translate(x, y));
                this._optionsChange();
                return this;
            },
            scale: function (scaleX, scaleY, origin) {
                if (!defined(scaleY)) {
                    scaleY = scaleX;
                }
                if (origin) {
                    origin = Point.create(origin);
                    this._matrix = this._matrix.multiplyCopy(Matrix.translate(origin.x, origin.y));
                }
                this._matrix = this._matrix.multiplyCopy(Matrix.scale(scaleX, scaleY));
                if (origin) {
                    this._matrix = this._matrix.multiplyCopy(Matrix.translate(-origin.x, -origin.y));
                }
                this._optionsChange();
                return this;
            },
            rotate: function (angle, origin) {
                origin = Point.create(origin) || Point.ZERO;
                this._matrix = this._matrix.multiplyCopy(Matrix.rotate(angle, origin.x, origin.y));
                this._optionsChange();
                return this;
            },
            multiply: function (transformation) {
                var matrix = toMatrix(transformation);
                this._matrix = this._matrix.multiplyCopy(matrix);
                this._optionsChange();
                return this;
            },
            matrix: function (matrix) {
                if (matrix) {
                    this._matrix = matrix;
                    this._optionsChange();
                    return this;
                } else {
                    return this._matrix;
                }
            }
        });
        deepExtend(Transformation.fn, ObserversMixin);
        function transform(matrix) {
            if (matrix === null) {
                return null;
            }
            if (matrix instanceof Transformation) {
                return matrix;
            }
            return new Transformation(matrix);
        }
        function toMatrix(value) {
            if (value && kendo.isFunction(value.matrix)) {
                return value.matrix();
            }
            return value;
        }
        function ellipseExtremeAngles(center, rx, ry, matrix) {
            var extremeX = 0, 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
            };
        }
        function bboxStartAngle(angle, start) {
            while (angle < start) {
                angle += 90;
            }
            return angle;
        }
        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);
            }
        }
        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 elipseAngle(start, end, swipe) {
            if (start > end) {
                end += 360;
            }
            var alpha = math.abs(end - start);
            if (!swipe) {
                alpha = 360 - alpha;
            }
            return alpha;
        }
        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(x1, y1, x2, y2, rx, ry, largeArc, swipe) {
            var cx, cy;
            var cx1, cy1;
            var a, b, c, sqrt;
            if (y1 !== y2) {
                var x21 = x2 - x1;
                var y21 = y2 - y1;
                var rx2 = pow(rx, 2), ry2 = pow(ry, 2);
                var k = (ry2 * x21 * (x1 + x2) + rx2 * y21 * (y1 + y2)) / (2 * rx2 * y21);
                var yk2 = k - y2;
                var l = -(x21 * ry2) / (rx2 * y21);
                a = 1 / rx2 + pow(l, 2) / ry2;
                b = 2 * (l * yk2 / ry2 - x2 / rx2);
                c = pow(x2, 2) / rx2 + pow(yk2, 2) / ry2 - 1;
                sqrt = math.sqrt(pow(b, 2) - 4 * a * c);
                cx = (-b - sqrt) / (2 * a);
                cy = k + l * cx;
                cx1 = (-b + sqrt) / (2 * a);
                cy1 = k + l * cx1;
            } else if (x1 !== x2) {
                b = -2 * y2;
                c = pow((x2 - x1) * ry / (2 * rx), 2) + pow(y2, 2) - pow(ry, 2);
                sqrt = math.sqrt(pow(b, 2) - 4 * c);
                cx = cx1 = (x1 + x2) / 2;
                cy = (-b - sqrt) / 2;
                cy1 = (-b + sqrt) / 2;
            } else {
                return false;
            }
            var start = calculateAngle(cx, cy, rx, ry, x1, y1);
            var end = calculateAngle(cx, cy, rx, ry, x2, y2);
            var alpha = elipseAngle(start, end, swipe);
            if (largeArc && alpha <= 180 || !largeArc && alpha > 180) {
                cx = cx1;
                cy = cy1;
                start = calculateAngle(cx, cy, rx, ry, x1, y1);
                end = calculateAngle(cx, cy, rx, ry, x2, y2);
            }
            return {
                center: new Point(cx, cy),
                startAngle: start,
                endAngle: end
            };
        }
        var ComplexNumber = function (real, img) {
            this.real = real || 0;
            this.img = img || 0;
        };
        ComplexNumber.fn = ComplexNumber.prototype = {
            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 = math.atan2(this.img, this.real), r = math.sqrt(math.pow(this.img, 2) + math.pow(this.real, 2)), nthR = math.pow(r, 1 / n);
                return new ComplexNumber(nthR * math.cos(rad / n), nthR * math.sin(rad / n));
            },
            equals: function (cNumber) {
                return this.real === cNumber.real && this.img === cNumber.img;
            },
            isReal: function () {
                return this.img === 0;
            }
        };
        function solveCubic(a, b, c, d) {
            if (a === 0) {
                return solveQuadratic(b, c, d);
            }
            var p = (3 * a * c - math.pow(b, 2)) / (3 * math.pow(a, 2)), q = (2 * math.pow(b, 3) - 9 * a * b * c + 27 * math.pow(a, 2) * d) / (27 * math.pow(a, 3)), Q = math.pow(p / 3, 3) + math.pow(q / 2, 2), i = new ComplexNumber(0, 1), b3a = -b / (3 * a), x1, x2, y1, y2, y3, result = [], 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));
            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 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]
            ];
        }
        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 curveIntersectionsCount(points, point, bbox) {
            var polynomial = toCubicPolynomial(points, 'x');
            var roots = solveCubic(polynomial[0], polynomial[1], polynomial[2], polynomial[3] - point.x);
            var count = 0;
            var rayIntersection;
            var intersectsRay;
            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), maxX = math.max(a.x, b.x), minY = math.min(a.y, b.y), maxY = math.max(a.y, b.y), 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;
        }
        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);
            }
        }
        function close(a, b, tolerance) {
            return round(math.abs(a - b), tolerance || PRECISION) === 0;
        }
        function closeOrLess(a, b, tolerance) {
            return a < b || close(a, b, tolerance);
        }
        function numberSign(x) {
            return x < 0 ? -1 : 1;
        }
        function isOutOfEndPoint(endPoint, controlPoint, point) {
            var angle = util.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 hasRootsInRange(points, point, field, rootField, range) {
            var polynomial = toCubicPolynomial(points, rootField);
            var roots = solveCubic(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 solveQuadratic(a, b, c) {
            var squareRoot = math.sqrt(math.pow(b, 2) - 4 * a * c);
            return [
                (-b + squareRoot) / (2 * a),
                (-b - squareRoot) / (2 * a)
            ];
        }
        deepExtend(kendo, {
            geometry: {
                Arc: Arc,
                Circle: Circle,
                curveIntersectionsCount: curveIntersectionsCount,
                lineIntersectionsCount: lineIntersectionsCount,
                Matrix: Matrix,
                Point: Point,
                Rect: Rect,
                Size: Size,
                Transformation: Transformation,
                transform: transform,
                toMatrix: toMatrix,
                isOutOfEndPoint: isOutOfEndPoint,
                hasRootsInRange: hasRootsInRange
            }
        });
        kendo.dataviz.geometry = kendo.geometry;
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/core', [
        'drawing/geometry',
        'kendo.popup'
    ], f);
}(function () {
    (function ($) {
        var noop = $.noop, toString = Object.prototype.toString, kendo = window.kendo, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, Class = kendo.Class, Widget = kendo.ui.Widget, deepExtend = kendo.deepExtend, util = kendo.util, defined = util.defined, limitValue = util.limitValue, g = kendo.geometry, proxy = $.proxy, NS = '.kendo', TOOLTIP_TEMPLATE = '<div class="k-tooltip">' + '<div class="k-tooltip-content"></div>' + '</div>', TOOLTIP_CLOSE_TEMPLATE = '<div class="k-tooltip-button"><a href="\\#" class="k-icon k-i-close">close</a></div>';
        var Surface = Widget.extend({
            init: function (element, options) {
                this.options = deepExtend({}, this.options, options);
                Widget.fn.init.call(this, element, this.options);
                this._click = this._handler('click');
                this._mouseenter = this._handler('mouseenter');
                this._mouseleave = this._handler('mouseleave');
                this._mousemove = this._handler('mousemove');
                this._visual = new kendo.drawing.Group();
                if (this.options.width) {
                    this.element.css('width', this.options.width);
                }
                if (this.options.height) {
                    this.element.css('height', this.options.height);
                }
                this._enableTracking();
            },
            options: {
                name: 'Surface',
                tooltip: {}
            },
            events: [
                'click',
                'mouseenter',
                'mouseleave',
                'mousemove',
                'resize',
                'tooltipOpen',
                'tooltipClose'
            ],
            draw: function (element) {
                this._visual.children.push(element);
            },
            clear: function () {
                this._visual.children = [];
                this.hideTooltip();
            },
            destroy: function () {
                this._visual = null;
                if (this._tooltip) {
                    this._tooltip.destroy();
                    delete this._tooltip;
                }
                Widget.fn.destroy.call(this);
            },
            exportVisual: function () {
                return this._visual;
            },
            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._resize();
            },
            eventTarget: function (e) {
                var domNode = $(e.touch ? e.touch.initialTouch : e.target);
                var node;
                while (!node && domNode.length > 0) {
                    node = domNode[0]._kendoNode;
                    if (domNode.is(this.element) || domNode.length === 0) {
                        break;
                    }
                    domNode = domNode.parent();
                }
                if (node) {
                    return node.srcElement;
                }
            },
            showTooltip: function (shape, options) {
                if (this._tooltip) {
                    this._tooltip.show(shape, options);
                }
            },
            hideTooltip: function () {
                if (this._tooltip) {
                    this._tooltip.hide();
                }
            },
            suspendTracking: function () {
                this._suspendedTracking = true;
                this.hideTooltip();
            },
            resumeTracking: function () {
                this._suspendedTracking = false;
            },
            _resize: noop,
            _handler: function (event) {
                var surface = this;
                return function (e) {
                    var node = surface.eventTarget(e);
                    if (node && !surface._suspendedTracking) {
                        surface.trigger(event, {
                            element: node,
                            originalEvent: e,
                            type: event
                        });
                    }
                };
            },
            _enableTracking: function () {
                if (kendo.ui.Popup) {
                    this._tooltip = new SurfaceTooltip(this, this.options.tooltip || {});
                }
            },
            _elementOffset: function () {
                var element = this.element;
                var offset = element.offset();
                var paddingLeft = parseInt(element.css('paddingLeft'), 10);
                var paddingTop = parseInt(element.css('paddingTop'), 10);
                return {
                    left: offset.left + paddingLeft,
                    top: offset.top + paddingTop
                };
            },
            _surfacePoint: function (event) {
                var offset = this._elementOffset();
                var coord = eventCoordinates(event);
                var x = coord.x - offset.left;
                var y = coord.y - offset.top;
                return new g.Point(x, y);
            }
        });
        kendo.ui.plugin(Surface);
        Surface.create = function (element, options) {
            return SurfaceFactory.current.create(element, options);
        };
        var BaseNode = Class.extend({
            init: function (srcElement) {
                this.childNodes = [];
                this.parent = null;
                if (srcElement) {
                    this.srcElement = srcElement;
                    this.observe();
                }
            },
            destroy: function () {
                if (this.srcElement) {
                    this.srcElement.removeObserver(this);
                }
                var children = this.childNodes;
                for (var i = 0; i < children.length; i++) {
                    this.childNodes[i].destroy();
                }
                this.parent = null;
            },
            load: noop,
            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 end = index + count;
                for (var i = index; i < end; i++) {
                    this.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();
            }
        });
        var OptionsStore = Class.extend({
            init: function (options, prefix) {
                var field, member;
                this.prefix = prefix || '';
                for (field in options) {
                    member = options[field];
                    member = this._wrap(member, field);
                    this[field] = member;
                }
            },
            get: function (field) {
                return kendo.getter(field, true)(this);
            },
            set: function (field, value) {
                var current = kendo.getter(field, true)(this);
                if (current !== value) {
                    var composite = this._set(field, this._wrap(value, field));
                    if (!composite) {
                        this.optionsChange({
                            field: this.prefix + field,
                            value: value
                        });
                    }
                }
            },
            _set: function (field, value) {
                var composite = field.indexOf('.') >= 0;
                if (composite) {
                    var parts = field.split('.'), path = '', obj;
                    while (parts.length > 1) {
                        path += parts.shift();
                        obj = kendo.getter(path, true)(this);
                        if (!obj) {
                            obj = new OptionsStore({}, path + '.');
                            obj.addObserver(this);
                            this[path] = obj;
                        }
                        if (obj instanceof OptionsStore) {
                            obj.set(parts.join('.'), value);
                            return composite;
                        }
                        path += '.';
                    }
                }
                this._clear(field);
                kendo.setter(field)(this, value);
                return composite;
            },
            _clear: function (field) {
                var current = kendo.getter(field, true)(this);
                if (current && current.removeObserver) {
                    current.removeObserver(this);
                }
            },
            _wrap: function (object, field) {
                var type = toString.call(object);
                if (object !== null && defined(object) && type === '[object Object]') {
                    if (!(object instanceof OptionsStore) && !(object instanceof Class)) {
                        object = new OptionsStore(object, this.prefix + field + '.');
                    }
                    object.addObserver(this);
                }
                return object;
            }
        });
        deepExtend(OptionsStore.fn, kendo.mixins.ObserversMixin);
        var SurfaceFactory = function () {
            this._items = [];
        };
        SurfaceFactory.prototype = {
            register: function (name, type, order) {
                var items = this._items, first = items[0], 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, 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, VML and Canvas. User agent: ' + navigator.userAgent + '\n' + '- The Kendo UI scripts are not fully loaded');
            }
        };
        SurfaceFactory.current = new SurfaceFactory();
        var SurfaceTooltip = 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.popup = new kendo.ui.Popup(this.element, {
                    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));
            },
            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);
                if (popup) {
                    popup.destroy();
                    delete this.popup;
                }
                clearTimeout(this._timeout);
                delete this.popup;
                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._elementOffset();
                var size = surface.getSize();
                var surfaceOffset = surface._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 current = this._current;
                delete this._current;
                clearTimeout(this._showTimeout);
                if (this.popup.visible() && current && !this.surface.trigger('tooltipClose', {
                        element: current.shape,
                        target: current.target,
                        popup: this.popup
                    })) {
                    this.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);
                if (!this.surface.trigger('tooltipOpen', {
                        element: shape,
                        target: target,
                        popup: this.popup
                    }) && this._updateContent(target, shape, options)) {
                    this._autoHide(options);
                    var elementSize = this._measure(options);
                    var popup = this.popup;
                    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.popup.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 width, height;
                this.element.css({
                    width: 'auto',
                    height: 'auto'
                });
                var visible = this.popup.visible();
                if (!visible) {
                    this.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) {
                    this.popup.wrapper.hide();
                }
                return {
                    width: width,
                    height: height
                };
            },
            _mouseleave: function (e) {
                if (!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.popup.wrapper.css({
                            left: position.left,
                            top: position.top
                        });
                    }
                }
            },
            _surfaceLeave: function (e) {
                if (!this._popupRelatedTarget(e)) {
                    clearTimeout(this._showTimeout);
                    this.hide();
                }
            },
            _popupRelatedTarget: function (e) {
                return e.relatedTarget && $(e.relatedTarget).closest(this.popup.wrapper).length;
            }
        });
        function eventCoordinates(event) {
            var x, y;
            if (event.touch) {
                x = event.x.location;
                y = event.y.location;
            } else {
                x = event.pageX || event.clientX || 0;
                y = event.pageY || event.clientY || 0;
            }
            return {
                x: x,
                y: y
            };
        }
        deepExtend(kendo, {
            drawing: {
                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
                    ]
                },
                Color: kendo.Color,
                BaseNode: BaseNode,
                OptionsStore: OptionsStore,
                Surface: Surface,
                SurfaceFactory: SurfaceFactory,
                SurfaceTooltip: SurfaceTooltip
            }
        });
        kendo.dataviz.drawing = kendo.drawing;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/mixins', ['drawing/core'], f);
}(function () {
    (function () {
        var kendo = window.kendo, deepExtend = kendo.deepExtend, defined = kendo.util.defined, g = kendo.geometry;
        var GRADIENT = 'gradient';
        var IDENTITY_MATRIX_HASH = g.Matrix.IDENTITY.toString();
        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;
                } else {
                    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;
                } else {
                    return this.options.get('stroke');
                }
            }
        };
        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 Measurable = {
            extend: function (proto) {
                proto.bbox = this.bbox;
                proto.geometryChange = this.geometryChange;
            },
            bbox: function (transformation) {
                var combinedMatrix = g.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 });
            }
        };
        deepExtend(kendo.drawing, {
            mixins: {
                Paintable: Paintable,
                Traversable: Traversable,
                Measurable: Measurable
            }
        });
    }());
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/shapes', [
        'drawing/core',
        'drawing/mixins',
        'util/text-metrics',
        'mixins/observers'
    ], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, deepExtend = kendo.deepExtend, g = kendo.geometry, Point = g.Point, Size = g.Size, Matrix = g.Matrix, toMatrix = g.toMatrix, drawing = kendo.drawing, OptionsStore = drawing.OptionsStore, math = Math, pow = math.pow, util = kendo.util, append = util.append, arrayLimits = util.arrayLimits, defined = util.defined, last = util.last, valueOrDefault = util.valueOrDefault, ObserversMixin = kendo.mixins.ObserversMixin, inArray = $.inArray, push = [].push, pop = [].pop, splice = [].splice, shift = [].shift, slice = [].slice, unshift = [].unshift, defId = 1, START = 'start', END = 'end', HORIZONTAL = 'horizontal';
        var Element = Class.extend({
            nodeType: 'Element',
            init: function (options) {
                this._initOptions(options);
            },
            _initOptions: function (options) {
                options = options || {};
                var transform = options.transform;
                var clip = options.clip;
                if (transform) {
                    options.transform = g.transform(transform);
                }
                if (clip && !clip.id) {
                    clip.id = generateDefinitionId();
                }
                this.options = new OptionsStore(options);
                this.options.addObserver(this);
            },
            transform: function (transform) {
                if (defined(transform)) {
                    this.options.set('transform', g.transform(transform));
                } else {
                    return this.options.get('transform');
                }
            },
            parentTransform: function () {
                var element = this, transformation, parentMatrix;
                while (element.parent) {
                    element = element.parent;
                    transformation = element.transform();
                    if (transformation) {
                        parentMatrix = transformation.matrix().multiplyCopy(parentMatrix || Matrix.unit());
                    }
                }
                if (parentMatrix) {
                    return g.transform(parentMatrix);
                }
            },
            currentTransform: function (parentTransform) {
                var elementTransform = this.transform(), elementMatrix = toMatrix(elementTransform), parentMatrix, combinedMatrix;
                if (!defined(parentTransform)) {
                    parentTransform = this.parentTransform();
                }
                parentMatrix = toMatrix(parentTransform);
                if (elementMatrix && parentMatrix) {
                    combinedMatrix = parentMatrix.multiplyCopy(elementMatrix);
                } else {
                    combinedMatrix = elementMatrix || parentMatrix;
                }
                if (combinedMatrix) {
                    return g.transform(combinedMatrix);
                }
            },
            visible: function (visible) {
                if (defined(visible)) {
                    this.options.set('visible', visible);
                    return this;
                } else {
                    return this.options.get('visible') !== false;
                }
            },
            clip: function (clip) {
                var options = this.options;
                if (defined(clip)) {
                    if (clip && !clip.id) {
                        clip.id = generateDefinitionId();
                    }
                    options.set('clip', clip);
                    return this;
                } else {
                    return options.get('clip');
                }
            },
            opacity: function (value) {
                if (defined(value)) {
                    this.options.set('opacity', value);
                    return this;
                } else {
                    return valueOrDefault(this.options.get('opacity'), 1);
                }
            },
            clippedBBox: function (transformation) {
                var box = this._clippedBBox(transformation);
                if (box) {
                    var clip = this.clip();
                    return clip ? g.Rect.intersect(box, clip.bbox(transformation)) : box;
                }
            },
            containsPoint: function (point, parentTransform) {
                if (this.visible()) {
                    var transform = this.currentTransform(parentTransform);
                    if (transform) {
                        point = point.transformCopy(transform.matrix().invert());
                    }
                    return this._hasFill() && this._containsPoint(point) || this._isOnPath && this._hasStroke() && this._isOnPath(point);
                }
                return false;
            },
            _hasFill: function () {
                var fill = this.options.fill;
                return fill && !util.isTransparent(fill.color);
            },
            _hasStroke: function () {
                var stroke = this.options.stroke;
                return stroke && stroke.width > 0 && !util.isTransparent(stroke.color);
            },
            _clippedBBox: function (transformation) {
                return this.bbox(transformation);
            }
        });
        deepExtend(Element.fn, ObserversMixin);
        var ElementsArray = Class.extend({
            init: function (array) {
                array = array || [];
                this.length = 0;
                this._splice(0, array.length, array);
            },
            elements: function (elements) {
                if (elements) {
                    this._splice(0, this.length, elements);
                    this._change();
                    return this;
                } else {
                    return this.slice(0);
                }
            },
            push: function () {
                var elements = arguments;
                var result = push.apply(this, elements);
                this._add(elements);
                return result;
            },
            slice: slice,
            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 that = this;
                var idx;
                var length;
                for (idx = 0, length = that.length; idx < length; idx++) {
                    if (that[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) {
                for (var idx = 0; idx < elements.length; idx++) {
                    elements[idx].addObserver(this);
                }
            },
            _clearObserver: function (elements) {
                for (var idx = 0; idx < elements.length; idx++) {
                    elements[idx].removeObserver(this);
                }
            },
            _change: function () {
            }
        });
        deepExtend(ElementsArray.fn, ObserversMixin);
        var Group = Element.extend({
            nodeType: 'Group',
            init: function (options) {
                Element.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 = inArray(element, this.children);
                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.fn.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) {
                for (var i = 0; i < elements.length; i++) {
                    var child = elements[i];
                    var parent = child.parent;
                    if (parent && parent != this && parent.remove) {
                        parent.remove(child);
                    }
                    child.parent = newParent;
                }
            }
        });
        drawing.mixins.Traversable.extend(Group.fn, 'children');
        var Text = Element.extend({
            nodeType: 'Text',
            init: function (content, position, options) {
                Element.fn.init.call(this, options);
                this.content(content);
                this.position(position || new g.Point());
                if (!this.options.font) {
                    this.options.font = '12px sans-serif';
                }
                if (!defined(this.options.fill)) {
                    this.fill('#000');
                }
            },
            content: function (value) {
                if (defined(value)) {
                    this.options.set('content', value);
                    return this;
                } else {
                    return this.options.get('content');
                }
            },
            measure: function () {
                var metrics = util.measureText(this.content(), { font: this.options.get('font') });
                return metrics;
            },
            rect: function () {
                var size = this.measure();
                var pos = this.position().clone();
                return new g.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);
            }
        });
        drawing.mixins.Paintable.extend(Text.fn);
        definePointAccessors(Text.fn, ['position']);
        var Circle = Element.extend({
            nodeType: 'Circle',
            init: function (geometry, options) {
                Element.fn.init.call(this, options);
                this.geometry(geometry || new g.Circle());
                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);
            }
        });
        drawing.mixins.Paintable.extend(Circle.fn);
        drawing.mixins.Measurable.extend(Circle.fn);
        defineGeometryAccessors(Circle.fn, ['geometry']);
        var Arc = Element.extend({
            nodeType: 'Arc',
            init: function (geometry, options) {
                Element.fn.init.call(this, options);
                this.geometry(geometry || new g.Arc());
                if (!defined(this.options.stroke)) {
                    this.stroke('#000');
                }
            },
            _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);
            }
        });
        drawing.mixins.Paintable.extend(Arc.fn);
        drawing.mixins.Measurable.extend(Arc.fn);
        defineGeometryAccessors(Arc.fn, ['geometry']);
        var GeometryElementsArray = ElementsArray.extend({
            _change: function () {
                this.geometryChange();
            }
        });
        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 rect;
                var segmentAnchor = this.anchor().transformCopy(matrix);
                var toSegmentAnchor = toSegment.anchor().transformCopy(matrix);
                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 g.Rect.fromPoints(p1, p2);
            },
            _curveBoundingBox: function (p1, cp1, cp2, p2) {
                var points = [
                        p1,
                        cp1,
                        cp2,
                        p2
                    ], extremesX = this._curveExtremesFor(points, 'x'), extremesY = this._curveExtremesFor(points, 'y'), xLimits = arrayLimits([
                        extremesX.min,
                        extremesX.max,
                        p1.x,
                        p2.x
                    ]), yLimits = arrayLimits([
                        extremesY.min,
                        extremesY.max,
                        p1.y,
                        p2.y
                    ]);
                return g.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: this._calculateCurveAt(extremes.min, field, points),
                    max: this._calculateCurveAt(extremes.max, field, points)
                };
            },
            _calculateCurveAt: function (t, field, points) {
                var t1 = 1 - t;
                return pow(t1, 3) * points[0][field] + 3 * pow(t1, 2) * t * points[1][field] + 3 * pow(t, 2) * t1 * points[2][field] + pow(t, 3) * points[3][field];
            },
            _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 = g.curveIntersectionsCount([
                        this.anchor(),
                        this.controlOut(),
                        segment.controlIn(),
                        segment.anchor()
                    ], point, this.bboxTo(segment));
                } else {
                    intersectionsCount = g.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 !g.isOutOfEndPoint(p1, p2, point);
                    } else if (endSegment == 'end' && p4.distanceTo(point) <= width) {
                        return !g.isOutOfEndPoint(p4, p3, point);
                    }
                    var hasRootsInRange = g.hasRootsInRange;
                    var points = [
                        p1,
                        p2,
                        p3,
                        p4
                    ];
                    if (hasRootsInRange(points, point, 'x', 'y', width) || hasRootsInRange(points, point, 'y', 'x', width)) {
                        return true;
                    }
                    var rotation = g.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 = util.deg(math.atan2(p2.y - p1.y, p2.x - p1.x));
                var rect = new g.Rect([
                    p1.x,
                    p1.y - width / 2
                ], [
                    p1.distanceTo(p2),
                    width
                ]);
                return rect.containsPoint(point.transformCopy(g.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.fn, [
            'anchor',
            'controlIn',
            'controlOut'
        ]);
        deepExtend(Segment.fn, ObserversMixin);
        var Path = Element.extend({
            nodeType: 'Path',
            init: function (options) {
                Element.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, 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 = util.rad(startAngle);
                    var center = new Point(anchor.x - radiusX * math.cos(start), anchor.y - radiusY * math.sin(start));
                    var arc = new g.Arc(center, {
                        startAngle: startAngle,
                        endAngle: endAngle,
                        radiusX: radiusX,
                        radiusY: radiusY,
                        anticlockwise: anticlockwise
                    });
                    this._addArcSegments(arc);
                }
                return this;
            },
            arcTo: function (end, rx, ry, largeArc, swipe) {
                if (this.segments.length > 0) {
                    var lastSegment = last(this.segments);
                    var anchor = lastSegment.anchor();
                    var arc = g.Arc.fromPoints(anchor, end, rx, ry, largeArc, swipe);
                    this._addArcSegments(arc);
                }
                return this;
            },
            _addArcSegments: function (arc) {
                this.suspend();
                var curvePoints = arc.curvePoints();
                for (var i = 1; i < curvePoints.length; i += 3) {
                    this.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 += g.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;
                width = width || this.options.stroke.width;
                if (length > 1) {
                    if (segments[0]._isOnPathTo(segments[1], point, width, 'start')) {
                        return true;
                    }
                    for (var idx = 2; idx <= length - 2; idx++) {
                        if (segments[idx - 1]._isOnPathTo(segments[idx], point, width)) {
                            return true;
                        }
                    }
                    if (segments[length - 2]._isOnPathTo(segments[length - 1], point, width, '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 g.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 = g.Rect.union(boundingBox, segmentBox);
                        } else {
                            boundingBox = segmentBox;
                        }
                    }
                }
                return boundingBox;
            }
        });
        drawing.mixins.Paintable.extend(Path.fn);
        drawing.mixins.Measurable.extend(Path.fn);
        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 pt = Point.create(points[i]);
                    if (pt) {
                        if (i === 0) {
                            path.moveTo(pt);
                        } else {
                            path.lineTo(pt);
                        }
                    }
                }
                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;
        };
        var MultiPath = Element.extend({
            nodeType: 'MultiPath',
            init: function (options) {
                Element.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) {
                if (this.paths.length > 0) {
                    last(this.paths).arcTo(end, rx, ry, largeArc, swipe);
                }
                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));
            }
        });
        drawing.mixins.Paintable.extend(MultiPath.fn);
        drawing.mixins.Measurable.extend(MultiPath.fn);
        var Image = Element.extend({
            nodeType: 'Image',
            init: function (src, rect, options) {
                Element.fn.init.call(this, options);
                this.src(src);
                this.rect(rect || new g.Rect());
            },
            src: function (value) {
                if (defined(value)) {
                    this.options.set('src', value);
                    return this;
                } else {
                    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();
            }
        });
        defineGeometryAccessors(Image.fn, ['rect']);
        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);
            }
        });
        defineOptionsAccessors(GradientStop.fn, [
            'offset',
            'color',
            'opacity'
        ]);
        deepExtend(GradientStop.fn, ObserversMixin);
        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;
            }
        };
        var StopsArray = ElementsArray.extend({
            _change: function () {
                this.optionsChange({ field: 'stops' });
            }
        });
        var Gradient = Class.extend({
            nodeType: 'gradient',
            init: function (options) {
                this.stops = new StopsArray(this._createStops(options.stops));
                this.stops.addObserver(this);
                this._userSpace = options.userSpace;
                this.id = generateDefinitionId();
            },
            userSpace: function (value) {
                if (defined(value)) {
                    this._userSpace = value;
                    this.optionsChange();
                    return this;
                } else {
                    return this._userSpace;
                }
            },
            _createStops: function (stops) {
                var result = [];
                var idx;
                stops = stops || [];
                for (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);
                }
            }
        });
        deepExtend(Gradient.fn, ObserversMixin, {
            optionsChange: function (e) {
                this.trigger('optionsChange', {
                    field: 'gradient' + (e ? '.' + e.field : ''),
                    value: this
                });
            },
            geometryChange: function () {
                this.optionsChange();
            }
        });
        var LinearGradient = Gradient.extend({
            init: function (options) {
                options = options || {};
                Gradient.fn.init.call(this, options);
                this.start(options.start || new Point());
                this.end(options.end || new Point(1, 0));
            }
        });
        definePointAccessors(LinearGradient.fn, [
            'start',
            'end'
        ]);
        var RadialGradient = Gradient.extend({
            init: function (options) {
                options = 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;
                } else {
                    return this._radius;
                }
            },
            fallbackFill: function (value) {
                if (defined(value)) {
                    this._fallbackFill = value;
                    this.optionsChange();
                    return this;
                } else {
                    return this._fallbackFill;
                }
            }
        });
        definePointAccessors(RadialGradient.fn, ['center']);
        var Rect = Element.extend({
            nodeType: 'Rect',
            init: function (geometry, options) {
                Element.fn.init.call(this, options);
                this.geometry(geometry || new g.Rect());
                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);
            }
        });
        drawing.mixins.Paintable.extend(Rect.fn);
        drawing.mixins.Measurable.extend(Rect.fn);
        defineGeometryAccessors(Rect.fn, ['geometry']);
        var Layout = Group.extend({
            init: function (rect, options) {
                Group.fn.init.call(this, kendo.deepExtend({}, this._defaults, options));
                this._rect = rect;
                this._fieldMap = {};
            },
            _defaults: {
                alignContent: START,
                justifyContent: START,
                alignItems: START,
                spacing: 0,
                orientation: HORIZONTAL,
                lineSpacing: 0,
                wrap: true
            },
            rect: function (value) {
                if (value) {
                    this._rect = value;
                    return this;
                } else {
                    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';
                }
            },
            reflow: function () {
                if (!this._rect || this.children.length === 0) {
                    return;
                }
                this._initMap();
                if (this.options.transform) {
                    this.transform(null);
                }
                var options = this.options;
                var fieldMap = this._fieldMap;
                var rect = this._rect;
                var groupOptions = this._initGroups();
                var groups = groupOptions.groups;
                var groupsSize = groupOptions.groupsSize;
                var sizeField = fieldMap.sizeField;
                var groupsSizeField = fieldMap.groupsSizeField;
                var groupAxis = fieldMap.groupAxis;
                var groupsAxis = fieldMap.groupsAxis;
                var groupStart = alignStart(groupsSize, rect, options.alignContent, groupsAxis, groupsSizeField);
                var groupOrigin = new Point();
                var elementOrigin = new Point();
                var size = new g.Size();
                var elementStart, bbox, element, group, groupBox;
                for (var groupIdx = 0; groupIdx < groups.length; groupIdx++) {
                    group = groups[groupIdx];
                    groupOrigin[groupAxis] = elementStart = alignStart(group.size, rect, options.justifyContent, groupAxis, sizeField);
                    groupOrigin[groupsAxis] = groupStart;
                    size[sizeField] = group.size;
                    size[groupsSizeField] = group.lineSize;
                    groupBox = new g.Rect(groupOrigin, size);
                    for (var idx = 0; idx < group.bboxes.length; idx++) {
                        element = group.elements[idx];
                        bbox = group.bboxes[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;
                    }
                    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 = g.transform();
                    if (groupAxis === 'x') {
                        transform.translate(rect.origin.x - scaledStart.x, newStart - scaledStart.y);
                    } else {
                        transform.translate(newStart - scaledStart.x, rect.origin.y - scaledStart.y);
                    }
                    transform.scale(scale, scale);
                    this.transform(transform);
                }
            },
            _initGroups: function () {
                var options = this.options;
                var children = this.children;
                var lineSpacing = options.lineSpacing;
                var sizeField = this._fieldMap.sizeField;
                var groupsSize = -lineSpacing;
                var groups = [];
                var group = this._newGroup();
                var addGroup = function () {
                    groups.push(group);
                    groupsSize += group.lineSize + lineSpacing;
                };
                var bbox, element;
                for (var idx = 0; idx < children.length; idx++) {
                    element = children[idx];
                    bbox = children[idx].clippedBBox();
                    if (element.visible() && bbox) {
                        if (options.wrap && group.size + bbox.size[sizeField] + options.spacing > this._rect.size[sizeField]) {
                            if (group.bboxes.length === 0) {
                                this._addToGroup(group, bbox, element);
                                addGroup();
                                group = this._newGroup();
                            } else {
                                addGroup();
                                group = this._newGroup();
                                this._addToGroup(group, bbox, element);
                            }
                        } else {
                            this._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: []
                };
            }
        });
        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 = g.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 = g.Rect.union(boundingBox, elementBoundingBox);
                        } else {
                            boundingBox = elementBoundingBox;
                        }
                    }
                }
            }
            return boundingBox;
        }
        function defineGeometryAccessors(fn, names) {
            for (var i = 0; i < names.length; i++) {
                fn[names[i]] = geometryAccessor(names[i]);
            }
        }
        function geometryAccessor(name) {
            var fieldName = '_' + name;
            return function (value) {
                if (defined(value)) {
                    this._observerField(fieldName, value);
                    this.geometryChange();
                    return this;
                } else {
                    return this[fieldName];
                }
            };
        }
        function definePointAccessors(fn, names) {
            for (var i = 0; i < names.length; i++) {
                fn[names[i]] = pointAccessor(names[i]);
            }
        }
        function pointAccessor(name) {
            var fieldName = '_' + name;
            return function (value) {
                if (defined(value)) {
                    this._observerField(fieldName, Point.create(value));
                    this.geometryChange();
                    return this;
                } else {
                    return this[fieldName];
                }
            };
        }
        function defineOptionsAccessors(fn, names) {
            for (var i = 0; i < names.length; i++) {
                fn[names[i]] = optionsAccessor(names[i]);
            }
        }
        function optionsAccessor(name) {
            return function (value) {
                if (defined(value)) {
                    this.options.set(name, value);
                    return this;
                } else {
                    return this.options.get(name);
                }
            };
        }
        function generateDefinitionId() {
            return 'kdef' + defId++;
        }
        function align(elements, rect, alignment) {
            alignElements(elements, rect, alignment, 'x', 'width');
        }
        function vAlign(elements, rect, alignment) {
            alignElements(elements, rect, alignment, 'y', 'height');
        }
        function stack(elements) {
            stackElements(getStackElements(elements), 'x', 'y', 'width');
        }
        function vStack(elements) {
            stackElements(getStackElements(elements), 'y', 'x', 'height');
        }
        function wrap(elements, rect) {
            return wrapElements(elements, rect, 'x', 'y', 'width');
        }
        function vWrap(elements, rect) {
            return wrapElements(elements, rect, 'y', 'x', 'height');
        }
        function wrapElements(elements, rect, axis, otherAxis, sizeField) {
            var result = [];
            var stacks = getStacks(elements, rect, sizeField);
            var origin = rect.origin.clone();
            var startElement;
            var elementIdx;
            var stack;
            var idx;
            for (idx = 0; idx < stacks.length; idx++) {
                stack = stacks[idx];
                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 (elementIdx = 0; elementIdx < stack.length; elementIdx++) {
                    result[idx].push(stack[elementIdx].element);
                }
            }
            return result;
        }
        function fit(element, rect) {
            var bbox = element.clippedBBox();
            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 = element.transform() || g.transform();
                transform.scale(scale, scale);
                element.transform(transform);
            }
        }
        function getStacks(elements, rect, sizeField) {
            var maxSize = rect.size[sizeField];
            var stackSize = 0;
            var stacks = [];
            var stack = [];
            var element;
            var size;
            var 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) {
                    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 getStackElements(elements) {
            var stackElements = [];
            var element;
            var bbox;
            for (var idx = 0; idx < elements.length; idx++) {
                element = elements[idx];
                bbox = element.clippedBBox();
                if (bbox) {
                    stackElements.push({
                        element: element,
                        bbox: bbox
                    });
                }
            }
            return stackElements;
        }
        function stackElements(elements, stackAxis, otherAxis, sizeField) {
            if (elements.length > 1) {
                var previousBBox = elements[0].bbox;
                var origin = new Point();
                var element;
                var bbox;
                for (var idx = 1; idx < elements.length; idx++) {
                    element = elements[idx].element;
                    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 alignElements(elements, rect, alignment, axis, sizeField) {
            var bbox, point;
            alignment = alignment || 'start';
            for (var idx = 0; idx < elements.length; idx++) {
                bbox = elements[idx].clippedBBox();
                if (bbox) {
                    point = bbox.origin.clone();
                    point[axis] = alignStart(bbox.size[sizeField], rect, alignment, axis, sizeField);
                    translateToPoint(point, bbox, elements[idx]);
                }
            }
        }
        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 translate(x, y, element) {
            var transofrm = element.transform() || g.transform();
            var matrix = transofrm.matrix();
            matrix.e += x;
            matrix.f += y;
            transofrm.matrix(matrix);
            element.transform(transofrm);
        }
        function translateToPoint(point, bbox, element) {
            translate(point.x - bbox.origin.x, point.y - bbox.origin.y, element);
        }
        deepExtend(drawing, {
            align: align,
            Arc: Arc,
            Circle: Circle,
            Element: Element,
            ElementsArray: ElementsArray,
            fit: fit,
            Gradient: Gradient,
            GradientStop: GradientStop,
            Group: Group,
            Image: Image,
            Layout: Layout,
            LinearGradient: LinearGradient,
            MultiPath: MultiPath,
            Path: Path,
            RadialGradient: RadialGradient,
            Rect: Rect,
            Segment: Segment,
            stack: stack,
            Text: Text,
            vAlign: vAlign,
            vStack: vStack,
            vWrap: vWrap,
            wrap: wrap
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/parser', ['drawing/shapes'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, drawing = kendo.drawing, geometry = kendo.geometry, Class = kendo.Class, Point = geometry.Point, deepExtend = kendo.deepExtend, trim = $.trim, util = kendo.util, last = util.last;
        var SEGMENT_REGEX = /([a-df-z]{1})([^a-df-z]*)(z)?/gi, SPLIT_REGEX = /[,\s]?([+\-]?(?:\d*\.\d+|\d+)(?:[eE][+\-]?\d+)?)/g, MOVE = 'm', CLOSE = 'z';
        var PathParser = Class.extend({
            parse: function (str, options) {
                var multiPath = new drawing.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(trim(params));
                    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;
            }
        });
        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;
                var controlOut, controlIn, point;
                for (var i = 0; i < parameters.length; i += 6) {
                    controlOut = new Point(parameters[i], parameters[i + 1]);
                    controlIn = new Point(parameters[i + 2], parameters[i + 3]);
                    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 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);
                    }
                    path.arcTo(endPoint, radiusX, radiusY, largeArc, swipe);
                    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 controlOut, endPoint, controlIn, lastControlIn;
                if (previousCommand == 's' || previousCommand == 'c') {
                    lastControlIn = last(last(path.paths).segments).controlIn();
                }
                for (var i = 0; i < parameters.length; i += 4) {
                    controlIn = new Point(parameters[i], parameters[i + 1]);
                    endPoint = new Point(parameters[i + 2], parameters[i + 3]);
                    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;
                var cubicControlPoints, endPoint, controlPoint;
                for (var i = 0; i < parameters.length; i += 4) {
                    controlPoint = new Point(parameters[i], parameters[i + 1]);
                    endPoint = new Point(parameters[i + 2], parameters[i + 3]);
                    if (options.isRelative) {
                        controlPoint.translateWith(position);
                        endPoint.translateWith(position);
                    }
                    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 cubicControlPoints, controlPoint, endPoint;
                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) {
                    endPoint = new Point(parameters[i], parameters[i + 1]);
                    if (options.isRelative) {
                        endPoint.translateWith(position);
                    }
                    if (controlPoint) {
                        controlPoint = reflectionPoint(controlPoint, position);
                    } else {
                        controlPoint = position.clone();
                    }
                    cubicControlPoints = quadraticToCubicControlPoints(position, controlPoint, endPoint);
                    path.curveTo(cubicControlPoints.controlOut, cubicControlPoints.controlIn, endPoint);
                    position.x = endPoint.x;
                    position.y = endPoint.y;
                }
            }
        };
        function parseParameters(str) {
            var parameters = [];
            str.replace(SPLIT_REGEX, function (match, number) {
                parameters.push(parseFloat(number));
            });
            return parameters;
        }
        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);
            }
        }
        function quadraticToCubicControlPoints(position, controlPoint, endPoint) {
            var third = 1 / 3;
            controlPoint = controlPoint.clone().scale(2 / 3);
            return {
                controlOut: controlPoint.clone().translateWith(position.scaleCopy(third)),
                controlIn: controlPoint.translateWith(endPoint.scaleCopy(third))
            };
        }
        PathParser.current = new PathParser();
        drawing.Path.parse = function (str, options) {
            return PathParser.current.parse(str, options);
        };
        deepExtend(drawing, { PathParser: PathParser });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/search', ['drawing/shapes'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, drawing = kendo.drawing, geometry = kendo.geometry, Class = kendo.Class, Rect = geometry.Rect, deepExtend = kendo.deepExtend, isArray = $.isArray, inArray = $.inArray, math = Math, LEVEL_STEP = 10000, MAX_LEVEL = 75;
        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++) {
                    result = result.concat(children[idx].pointShapes(point));
                }
                return result;
            },
            insert: function (shape, bbox) {
                var inserted = false;
                var children = this.children;
                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 rect = this.rect, children = this.children, center = rect.center(), halfWidth = rect.width() / 2, 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 ShapesQuadTree = Class.extend({
            ROOT_SIZE: 1000,
            init: function () {
                this.initRoots();
            },
            initRoots: function () {
                this.rootMap = {};
                this.root = new QuadRoot();
                this.rootElements = [];
            },
            clear: function () {
                var that = this;
                var rootElements = that.rootElements;
                for (var idx = 0; idx < rootElements.length; idx++) {
                    this.remove(rootElements[idx]);
                }
                this.initRoots();
            },
            pointShape: function (point) {
                var size = this.ROOT_SIZE;
                var result = this.root.pointShapes(point);
                var sectorRoot = (this.rootMap[math.floor(point.x / size)] || {})[math.floor(point.y / size)];
                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 element, levelWeight, zIndex, parents;
                for (var idx = 0; idx < elements.length; idx++) {
                    element = elements[idx];
                    zIndex = 0;
                    levelWeight = math.pow(LEVEL_STEP, MAX_LEVEL);
                    parents = [];
                    while (element) {
                        parents.push(element);
                        element = element.parent;
                    }
                    while (parents.length) {
                        element = parents.pop();
                        zIndex += (inArray(element, element.parent ? element.parent.children : this.rootElements) + 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) {
                if (element.nodeType === 'Group') {
                    for (var idx = 0; idx < element.children.length; idx++) {
                        this.bboxChange(element.children[idx]);
                    }
                } else {
                    if (element._quadNode) {
                        element._quadNode.remove(element);
                    }
                    this._insertShape(element);
                }
            },
            add: function (elements) {
                var elementsArray = isArray(elements) ? elements.slice(0) : [elements];
                this.rootElements.push.apply(this.rootElements, elementsArray);
                this._insert(elementsArray);
            },
            childrenChange: function (e) {
                if (e.action == 'remove') {
                    for (var idx = 0; idx < e.items.length; idx++) {
                        this.remove(e.items[idx]);
                    }
                } else {
                    this._insert(Array.prototype.slice.call(e.items, 0));
                }
            },
            _insert: function (elements) {
                var element;
                while (elements.length > 0) {
                    element = elements.pop();
                    element.addObserver(this);
                    if (element.nodeType == 'Group') {
                        elements.push.apply(elements, element.children);
                    } else {
                        this._insertShape(element);
                    }
                }
            },
            _insertShape: function (shape) {
                var bbox = shape.bbox();
                if (bbox) {
                    var rootSize = this.ROOT_SIZE;
                    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 {
                        if (!this.rootMap[x]) {
                            this.rootMap[x] = {};
                        }
                        if (!this.rootMap[x][y]) {
                            this.rootMap[x][y] = new QuadNode(new Rect([
                                x * rootSize,
                                y * rootSize
                            ], [
                                rootSize,
                                rootSize
                            ]));
                        }
                        this.rootMap[x][y].insert(shape, bbox);
                    }
                }
            },
            remove: function (element) {
                element.removeObserver(this);
                if (element.nodeType == 'Group') {
                    var children = element.children;
                    for (var idx = 0; idx < children.length; idx++) {
                        this.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 rootSize = this.ROOT_SIZE;
                var bottomRight = rect.bottomRight();
                var bottomX = math.floor(bottomRight.x / rootSize);
                var bottomY = math.floor(bottomRight.y / rootSize);
                var sectors = [
                    [],
                    []
                ];
                for (var x = math.floor(rect.origin.x / rootSize); x <= bottomX; x++) {
                    sectors[0].push(x);
                }
                for (var y = math.floor(rect.origin.y / rootSize); 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;
        }
        deepExtend(drawing, {
            ShapesQuadTree: ShapesQuadTree,
            QuadNode: QuadNode
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/svg', [
        'drawing/shapes',
        'util/main'
    ], f);
}(function () {
    (function ($) {
        var doc = document, kendo = window.kendo, deepExtend = kendo.deepExtend, g = kendo.geometry, d = kendo.drawing, BaseNode = d.BaseNode, util = kendo.util, defined = util.defined, isTransparent = util.isTransparent, renderAttr = util.renderAttr, renderAllAttr = util.renderAllAttr, renderTemplate = util.renderTemplate, inArray = $.inArray;
        var BUTT = 'butt', DASH_ARRAYS = d.DASH_ARRAYS, GRADIENT = 'gradient', NONE = 'none', NS = '.kendo', SOLID = 'solid', SPACE = ' ', SVG_NS = 'http://www.w3.org/2000/svg', TRANSFORM = 'transform', UNDEFINED = 'undefined';
        var Surface = d.Surface.extend({
            init: function (element, options) {
                d.Surface.fn.init.call(this, element, options);
                this._root = new RootNode(this.options);
                renderSVG(this.element[0], this._template(this));
                this._rootElement = this.element[0].firstElementChild;
                alignToScreen(this._rootElement);
                this._root.attachTo(this._rootElement);
                this.element.on('click' + NS, this._click);
                this.element.on('mouseover' + NS, this._mouseenter);
                this.element.on('mouseout' + NS, this._mouseleave);
                this.element.on('mousemove' + NS, this._mousemove);
                this.resize();
            },
            type: 'svg',
            destroy: function () {
                if (this._root) {
                    this._root.destroy();
                    this._root = null;
                    this._rootElement = null;
                    this.element.off(NS);
                }
                d.Surface.fn.destroy.call(this);
            },
            translate: function (offset) {
                var viewBox = kendo.format('{0} {1} {2} {3}', 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) {
                d.Surface.fn.draw.call(this, element);
                this._root.load([element]);
            },
            clear: function () {
                d.Surface.fn.clear.call(this);
                this._root.clear();
            },
            svg: function () {
                return '<?xml version=\'1.0\' ?>' + this._template(this);
            },
            exportVisual: function () {
                var visual = this._visual;
                var offset = this._offset;
                if (offset) {
                    var wrap = new d.Group();
                    wrap.children.push(visual);
                    wrap.transform(g.transform().translate(-offset.x, -offset.y));
                    visual = wrap;
                }
                return visual;
            },
            _resize: function () {
                if (this._offset) {
                    this.translate(this._offset);
                }
            },
            _template: renderTemplate('<svg style=\'width: 100%; height: 100%; overflow: hidden;\' ' + 'xmlns=\'' + SVG_NS + '\' ' + 'xmlns:xlink=\'http://www.w3.org/1999/xlink\' ' + 'version=\'1.1\'>#= d._root.render() #</svg>')
        });
        var Node = BaseNode.extend({
            init: function (srcElement) {
                BaseNode.fn.init.call(this, srcElement);
                this.definitions = {};
            },
            destroy: function () {
                if (this.element) {
                    this.element._kendoNode = null;
                    this.element = null;
                }
                this.clearDefinitions();
                BaseNode.fn.destroy.call(this);
            },
            load: function (elements, pos) {
                var node = this, element = node.element, childNode, srcElement, children, i;
                for (i = 0; i < elements.length; i++) {
                    srcElement = elements[i];
                    children = srcElement.children;
                    childNode = new nodeMap[srcElement.nodeType](srcElement);
                    if (defined(pos)) {
                        node.insertAt(childNode, pos);
                    } else {
                        node.append(childNode);
                    }
                    childNode.createDefinitions();
                    if (children && children.length > 0) {
                        childNode.load(children);
                    }
                    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 = doc.createElement('div');
                renderSVG(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) {
                var nodes = this.childNodes, childElement, i;
                if (this.element) {
                    this.element._kendoNode = null;
                }
                this.element = element;
                this.element._kendoNode = this;
                for (i = 0; i < nodes.length; i++) {
                    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: renderTemplate('#= d.renderChildren() #'),
            render: function () {
                return this.template(this);
            },
            renderChildren: function () {
                var nodes = this.childNodes, output = '', i;
                for (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);
                }
                BaseNode.fn.optionsChange.call(this, e);
            },
            attr: function (name, value) {
                if (this.element) {
                    this.element.setAttribute(name, value);
                }
            },
            allAttr: function (attrs) {
                for (var i = 0; i < attrs.length; i++) {
                    this.attr(attrs[i][0], attrs[i][1]);
                }
            },
            css: function (name, value) {
                if (this.element) {
                    this.element.style[name] = value;
                }
            },
            allCss: function (styles) {
                for (var i = 0; i < styles.length; i++) {
                    this.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', util.renderStyle(this.mapStyle(true)));
            },
            renderOpacity: function () {
                return renderAttr('opacity', this.srcElement.options.opacity);
            },
            createDefinitions: function () {
                var srcElement = this.srcElement;
                var definitions = this.definitions;
                var definition, field, options, hasDefinitions;
                if (srcElement) {
                    options = srcElement.options;
                    for (field in DefinitionMap) {
                        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, refUrl(value.id));
                }
            },
            clearDefinitions: function () {
                var definitions = this.definitions;
                var field;
                for (field in definitions) {
                    this.definitionChange({
                        action: 'remove',
                        definitions: definitions
                    });
                    this.definitions = {};
                    break;
                }
            },
            renderDefinitions: function () {
                return renderAllAttr(this.mapDefinitions());
            },
            mapDefinitions: function () {
                var definitions = this.definitions;
                var attrs = [];
                var field;
                for (field in definitions) {
                    attrs.push([
                        DefinitionMap[field],
                        refUrl(definitions[field].id)
                    ]);
                }
                return attrs;
            }
        });
        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.fn.clear.call(this);
            },
            template: renderTemplate('#=d.defs.render()##= d.renderChildren() #'),
            definitionChange: function (e) {
                this.defs.definitionChange(e);
            }
        });
        var DefinitionNode = Node.extend({
            init: function () {
                Node.fn.init.call(this);
                this.definitionMap = {};
            },
            attachTo: function (domElement) {
                this.element = domElement;
            },
            template: renderTemplate('<defs>#= d.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 d.LinearGradient) {
                        nodeType = LinearGradientNode;
                    } else if (item instanceof d.RadialGradient) {
                        nodeType = RadialGradientNode;
                    }
                }
                return new nodeType(item);
            },
            addDefinitions: function (definitions) {
                for (var field in definitions) {
                    this.addDefinition(field, definitions[field]);
                }
            },
            addDefinition: function (type, srcElement) {
                var definitionMap = this.definitionMap;
                var id = srcElement.id;
                var element = this.element;
                var node, mapItem;
                mapItem = definitionMap[id];
                if (!mapItem) {
                    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) {
                for (var field in definitions) {
                    this.removeDefinition(definitions[field]);
                }
            },
            removeDefinition: function (srcElement) {
                var definitionMap = this.definitionMap;
                var id = srcElement.id;
                var mapItem;
                mapItem = definitionMap[id];
                if (mapItem) {
                    mapItem.count--;
                    if (mapItem.count === 0) {
                        this.remove(inArray(mapItem.element, this.childNodes), 1);
                        delete definitionMap[id];
                    }
                }
            }
        });
        var ClipNode = Node.extend({
            init: function (srcElement) {
                Node.fn.init.call(this);
                this.srcElement = srcElement;
                this.id = srcElement.id;
                this.load([srcElement]);
            },
            template: renderTemplate('<clipPath id=\'#=d.id#\'>#= d.renderChildren()#</clipPath>')
        });
        var GroupNode = Node.extend({
            template: renderTemplate('<g#= d.renderTransform() + d.renderStyle() + d.renderOpacity() + d.renderDefinitions()#>#= d.renderChildren() #</g>'),
            optionsChange: function (e) {
                if (e.field == TRANSFORM) {
                    this.transformChange(e.value);
                }
                Node.fn.optionsChange.call(this, e);
            }
        });
        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 = this.attributeMap[e.field];
                    if (name) {
                        this.attr(name, e.value);
                    }
                    break;
                }
                Node.fn.optionsChange.call(this, e);
            },
            attributeMap: {
                'fill.opacity': 'fill-opacity',
                'stroke.color': 'stroke',
                'stroke.width': 'stroke-width',
                'stroke.opacity': 'stroke-opacity'
            },
            content: function () {
                if (this.element) {
                    this.element.textContent = this.srcElement.content();
                }
            },
            renderData: function () {
                return this.printPath(this.srcElement);
            },
            printPath: function (path) {
                var segments = path.segments, length = segments.length;
                if (length > 0) {
                    var parts = [], output, segmentType, currentType, i;
                    for (i = 1; i < length; i++) {
                        segmentType = this.segmentType(segments[i - 1], segments[i]);
                        if (segmentType !== currentType) {
                            currentType = segmentType;
                            parts.push(segmentType);
                        }
                        if (segmentType === 'L') {
                            parts.push(this.printPoints(segments[i].anchor()));
                        } else {
                            parts.push(this.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, length = points.length, i, result = [];
                for (i = 0; i < length; i++) {
                    result.push(points[i].toString(3));
                }
                return result.join(SPACE);
            },
            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 width = stroke.width || 1, dashType = stroke.dashType;
                if (dashType && dashType != SOLID) {
                    var dashArray = DASH_ARRAYS[dashType.toLowerCase()], result = [], i;
                    for (i = 0; i < dashArray.length; i++) {
                        result.push(dashArray[i] * width);
                    }
                    return result.join(' ');
                }
            },
            renderLinecap: function (stroke) {
                var dashType = stroke.dashType, 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: renderTemplate('<path #= d.renderStyle() # #= d.renderOpacity() # ' + '#= kendo.util.renderAttr(\'d\', d.renderData()) # ' + '#= d.renderStroke() # ' + '#= d.renderFill() # ' + '#= d.renderDefinitions() # ' + '#= d.renderTransform() #></path>')
        });
        var ArcNode = PathNode.extend({
            renderData: function () {
                return this.printPath(this.srcElement.toPath());
            }
        });
        var MultiPathNode = PathNode.extend({
            renderData: function () {
                var paths = this.srcElement.paths;
                if (paths.length > 0) {
                    var result = [], i;
                    for (i = 0; i < paths.length; i++) {
                        result.push(this.printPath(paths[i]));
                    }
                    return result.join(' ');
                }
            }
        });
        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: renderTemplate('<circle #= d.renderStyle() # #= d.renderOpacity() # ' + 'cx=\'#= d.center().x #\' cy=\'#= d.center().y #\' ' + 'r=\'#= d.radius() #\' ' + '#= d.renderStroke() # ' + '#= d.renderFill() # ' + '#= d.renderDefinitions() # ' + '#= d.renderTransform() # ></circle>')
        });
        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', util.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
                ]);
                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 content;
            },
            template: renderTemplate('<text #= d.renderStyle() # #= d.renderOpacity() # ' + 'x=\'#= this.pos().x #\' y=\'#= this.pos().y #\' ' + '#= d.renderStroke() # ' + '#= d.renderTransform() # ' + '#= d.renderDefinitions() # ' + '#= d.renderFill() #>#= d.renderContent() #</text>')
        });
        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: renderTemplate('<image preserveAspectRatio=\'none\' #= d.renderStyle() # #= d.renderTransform()# #= d.renderOpacity() # ' + '#= d.renderPosition() # #= d.renderSource() # #= d.renderDefinitions()#>' + '</image>')
        });
        var GradientStopNode = Node.extend({
            template: renderTemplate('<stop #=d.renderOffset()# #=d.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 srcElement = this.srcElement;
                var stops = srcElement.stops;
                var element = this.element;
                var stopNode;
                var idx;
                for (idx = 0; idx < stops.length; idx++) {
                    stopNode = new GradientStopNode(stops[idx]);
                    this.append(stopNode);
                    if (element) {
                        stopNode.attachTo(element);
                    }
                }
            },
            optionsChange: function (e) {
                if (e.field == 'gradient.stops') {
                    BaseNode.fn.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: renderTemplate('<linearGradient id=\'#=d.id#\' #=d.renderCoordinates()#>' + '#= d.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: renderTemplate('<radialGradient id=\'#=d.id#\' #=d.renderCoordinates()#>' + '#= d.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 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: renderTemplate('<rect #= d.renderStyle() # #= d.renderOpacity() # ' + 'x=\'#= d.origin().x #\' y=\'#= d.origin().y #\' ' + 'width=\'#= d.size().width #\' height=\'#= d.size().height #\'' + '#= d.renderStroke() # ' + '#= d.renderFill() # ' + '#= d.renderDefinitions() # ' + '#= d.renderTransform() # />')
        });
        var nodeMap = {
            Group: GroupNode,
            Text: TextNode,
            Path: PathNode,
            MultiPath: MultiPathNode,
            Circle: CircleNode,
            Arc: ArcNode,
            Image: ImageNode,
            Rect: RectNode
        };
        var renderSVG = function (container, svg) {
            container.innerHTML = svg;
        };
        (function () {
            var testFragment = '<svg xmlns=\'' + SVG_NS + '\'></svg>', testContainer = doc.createElement('div'), hasParser = typeof DOMParser != UNDEFINED;
            testContainer.innerHTML = testFragment;
            if (hasParser && testContainer.firstChild.namespaceURI != SVG_NS) {
                renderSVG = function (container, svg) {
                    var parser = new DOMParser(), chartDoc = parser.parseFromString(svg, 'text/xml'), importedDoc = doc.adoptNode(chartDoc.documentElement);
                    container.innerHTML = '';
                    container.appendChild(importedDoc);
                };
            }
        }());
        function alignToScreen(element) {
            var ctm;
            try {
                ctm = element.getScreenCTM ? element.getScreenCTM() : null;
            } catch (e) {
            }
            if (ctm) {
                var left = -ctm.e % 1, top = -ctm.f % 1, style = element.style;
                if (left !== 0 || top !== 0) {
                    style.left = left + 'px';
                    style.top = top + 'px';
                }
            }
        }
        function baseUrl() {
            var base = document.getElementsByTagName('base')[0], url = '', href = document.location.href, hashIndex = href.indexOf('#');
            if (base && !kendo.support.browser.msie) {
                if (hashIndex !== -1) {
                    href = href.substring(0, hashIndex);
                }
                url = href;
            }
            return url;
        }
        function refUrl(id) {
            return 'url(' + baseUrl() + '#' + id + ')';
        }
        function exportGroup(group) {
            var root = new RootNode();
            var bbox = group.clippedBBox();
            if (bbox) {
                var origin = bbox.getOrigin();
                var exportRoot = new d.Group();
                exportRoot.transform(g.transform().translate(-origin.x, -origin.y));
                exportRoot.children.push(group);
                group = exportRoot;
            }
            root.load([group]);
            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;
        }
        function exportSVG(group, options) {
            var svg = exportGroup(group);
            if (!options || !options.raw) {
                svg = 'data:image/svg+xml;base64,' + util.encodeBase64(svg);
            }
            return $.Deferred().resolve(svg).promise();
        }
        function isDefinition(type, value) {
            return type == 'clip' || type == 'fill' && (!value || value.nodeType == GRADIENT);
        }
        function decodeEntities(text) {
            if (!text || !text.indexOf || text.indexOf('&') < 0) {
                return text;
            } else {
                var element = decodeEntities._element;
                element.innerHTML = text;
                return element.textContent || element.innerText;
            }
        }
        decodeEntities._element = document.createElement('span');
        var DefinitionMap = {
            clip: 'clip-path',
            fill: 'fill'
        };
        kendo.support.svg = function () {
            return doc.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1');
        }();
        if (kendo.support.svg) {
            d.SurfaceFactory.current.register('svg', Surface, 10);
        }
        deepExtend(d, {
            exportSVG: exportSVG,
            svg: {
                ArcNode: ArcNode,
                CircleNode: CircleNode,
                ClipNode: ClipNode,
                DefinitionNode: DefinitionNode,
                GradientStopNode: GradientStopNode,
                GroupNode: GroupNode,
                ImageNode: ImageNode,
                LinearGradientNode: LinearGradientNode,
                MultiPathNode: MultiPathNode,
                Node: Node,
                PathNode: PathNode,
                RadialGradientNode: RadialGradientNode,
                RectNode: RectNode,
                RootNode: RootNode,
                Surface: Surface,
                TextNode: TextNode,
                _exportGroup: exportGroup
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/canvas', [
        'drawing/search',
        'kendo.color'
    ], f);
}(function () {
    (function ($) {
        var doc = document, kendo = window.kendo, deepExtend = kendo.deepExtend, util = kendo.util, defined = util.defined, isTransparent = util.isTransparent, renderTemplate = util.renderTemplate, valueOrDefault = util.valueOrDefault, g = kendo.geometry, d = kendo.drawing, BaseNode = d.BaseNode, proxy = $.proxy;
        var BUTT = 'butt', DASH_ARRAYS = d.DASH_ARRAYS, FRAME_DELAY = 1000 / 60, SOLID = 'solid', NS = '.kendo';
        var Surface = d.Surface.extend({
            init: function (element, options) {
                d.Surface.fn.init.call(this, element, options);
                this.element[0].innerHTML = this._template(this);
                var canvas = this.element[0].firstElementChild;
                canvas.width = $(element).width();
                canvas.height = $(element).height();
                this._rootElement = canvas;
                this._root = new RootNode(canvas);
            },
            destroy: function () {
                d.Surface.fn.destroy.call(this);
                if (this._root) {
                    this._root.destroy();
                    this._root = null;
                }
                if (this._searchTree) {
                    this._searchTree.clear();
                    delete this._searchTree;
                }
                this.element.off(NS);
            },
            type: 'canvas',
            draw: function (element) {
                d.Surface.fn.draw.call(this, element);
                this._root.load([element], undefined, this.options.cors);
                if (this._searchTree) {
                    this._searchTree.add([element]);
                }
            },
            clear: function () {
                d.Surface.fn.clear.call(this);
                this._root.clear();
                if (this._searchTree) {
                    this._searchTree.clear();
                }
            },
            eventTarget: function (e) {
                if (this._searchTree) {
                    var point = this._surfacePoint(e);
                    var shape = this._searchTree.pointShape(point);
                    return shape;
                }
            },
            image: function () {
                var root = this._root;
                var rootElement = this._rootElement;
                var loadingStates = [];
                root.traverse(function (childNode) {
                    if (childNode.loading) {
                        loadingStates.push(childNode.loading);
                    }
                });
                var defer = $.Deferred();
                $.when.apply($, loadingStates).done(function () {
                    root._invalidate();
                    try {
                        var data = rootElement.toDataURL();
                        defer.resolve(data);
                    } catch (e) {
                        defer.reject(e);
                    }
                }).fail(function (e) {
                    defer.reject(e);
                });
                return defer.promise();
            },
            suspendTracking: function () {
                d.Surface.fn.suspendTracking.call(this);
                if (this._searchTree) {
                    this._searchTree.clear();
                    delete this._searchTree;
                }
            },
            resumeTracking: function () {
                d.Surface.fn.resumeTracking.call(this);
                if (!this._searchTree) {
                    this._searchTree = new d.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: renderTemplate('<canvas style=\'width: 100%; height: 100%;\'></canvas>'),
            _enableTracking: function () {
                this._searchTree = new d.ShapesQuadTree();
                this._mouseTrackHandler = proxy(this._trackMouse, this);
                this.element.on('click' + NS, this._mouseTrackHandler);
                this.element.on('mousemove' + NS, this._mouseTrackHandler);
                d.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'
                    });
                }
            }
        });
        var Node = 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();
                    PathNode.fn.renderPoints(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 node = this, childNode, srcElement, children, i;
                for (i = 0; i < elements.length; i++) {
                    srcElement = elements[i];
                    children = srcElement.children;
                    childNode = new nodeMap[srcElement.nodeType](srcElement, cors);
                    if (children && children.length > 0) {
                        childNode.load(children, pos, cors);
                    }
                    if (defined(pos)) {
                        node.insertAt(childNode, pos);
                    } else {
                        node.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) {
                if (value && ctx.globalAlpha) {
                    value *= ctx.globalAlpha;
                }
                ctx.globalAlpha = value;
            },
            visible: function () {
                var src = this.srcElement;
                return !src || src && src.options.visible !== false;
            }
        });
        var GroupNode = Node.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();
            }
        });
        d.mixins.Traversable.extend(GroupNode.fn, 'childNodes');
        var RootNode = GroupNode.extend({
            init: function (canvas) {
                GroupNode.fn.init.call(this);
                this.canvas = canvas;
                this.ctx = canvas.getContext('2d');
                var invalidateHandler = proxy(this._invalidate, this);
                this.invalidate = kendo.throttle(function () {
                    kendo.animationFrame(invalidateHandler);
                }, FRAME_DELAY);
            },
            destroy: function () {
                GroupNode.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);
            }
        });
        d.mixins.Traversable.extend(RootNode.fn, 'childNodes');
        var PathNode = Node.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 d.LinearGradient) {
                    var start = fill.start();
                    var end = fill.end();
                    gradient = ctx.createLinearGradient(start.x, start.y, end.x, end.y);
                } else if (fill instanceof d.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) {
                var segments = path.segments;
                if (segments.length === 0) {
                    return;
                }
                var seg = segments[0];
                var anchor = seg.anchor();
                ctx.moveTo(anchor.x, anchor.y);
                for (var i = 1; i < segments.length; i++) {
                    seg = segments[i];
                    anchor = seg.anchor();
                    var prevSeg = segments[i - 1];
                    var prevOut = prevSeg.controlOut();
                    var controlIn = seg.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 MultiPathNode = PathNode.extend({
            renderPoints: function (ctx) {
                var paths = this.srcElement.paths;
                for (var i = 0; i < paths.length; i++) {
                    PathNode.fn.renderPoints(ctx, paths[i]);
                }
            }
        });
        var CircleNode = PathNode.extend({
            renderPoints: function (ctx) {
                var geometry = this.srcElement.geometry();
                var c = geometry.center;
                var r = geometry.radius;
                ctx.arc(c.x, c.y, r, 0, Math.PI * 2);
            }
        });
        var ArcNode = PathNode.extend({
            renderPoints: function (ctx) {
                var path = this.srcElement.toPath();
                PathNode.fn.renderPoints.call(this, ctx, path);
            }
        });
        var TextNode = PathNode.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;
                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();
            }
        });
        var ImageNode = PathNode.extend({
            init: function (srcElement, cors) {
                PathNode.fn.init.call(this, srcElement);
                this.onLoad = proxy(this.onLoad, this);
                this.onError = proxy(this.onError, this);
                this.loading = $.Deferred();
                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 = $.Deferred();
                    this.img.src = this.srcElement.src();
                } else {
                    PathNode.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 tl = rect.topLeft();
                ctx.drawImage(this.img, tl.x, tl.y, rect.width(), rect.height());
            }
        });
        var RectNode = PathNode.extend({
            renderPoints: function (ctx) {
                var geometry = this.srcElement.geometry();
                var origin = geometry.origin;
                var size = geometry.size;
                ctx.rect(origin.x, origin.y, size.width, size.height);
            }
        });
        function exportImage(group, options) {
            var defaults = {
                width: '800px',
                height: '600px',
                cors: 'Anonymous'
            };
            var bbox = group.clippedBBox();
            if (bbox) {
                var origin = bbox.getOrigin();
                var exportRoot = new d.Group();
                exportRoot.transform(g.transform().translate(-origin.x, -origin.y));
                exportRoot.children.push(group);
                group = exportRoot;
                var size = bbox.getSize();
                defaults.width = size.width + 'px';
                defaults.height = size.height + 'px';
            }
            options = deepExtend(defaults, options);
            var container = $('<div />').css({
                display: 'none',
                width: options.width,
                height: options.height
            }).appendTo(document.body);
            var surface = new Surface(container, options);
            surface.suspendTracking();
            surface.draw(group);
            var promise = surface.image();
            promise.always(function () {
                surface.destroy();
                container.remove();
            });
            return promise;
        }
        var nodeMap = {
            Group: GroupNode,
            Text: TextNode,
            Path: PathNode,
            MultiPath: MultiPathNode,
            Circle: CircleNode,
            Arc: ArcNode,
            Image: ImageNode,
            Rect: RectNode
        };
        function addGradientStops(gradient, stops) {
            var color, stop, idx;
            for (idx = 0; idx < stops.length; idx++) {
                stop = stops[idx];
                color = kendo.parseColor(stop.color());
                color.a *= stop.opacity();
                gradient.addColorStop(stop.offset(), color.toCssRgba());
            }
        }
        kendo.support.canvas = function () {
            return !!doc.createElement('canvas').getContext;
        }();
        if (kendo.support.canvas) {
            d.SurfaceFactory.current.register('canvas', Surface, 20);
        }
        deepExtend(kendo.drawing, {
            exportImage: exportImage,
            canvas: {
                ArcNode: ArcNode,
                CircleNode: CircleNode,
                GroupNode: GroupNode,
                ImageNode: ImageNode,
                MultiPathNode: MultiPathNode,
                Node: Node,
                PathNode: PathNode,
                RectNode: RectNode,
                RootNode: RootNode,
                Surface: Surface,
                TextNode: TextNode
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/vml', [
        'drawing/shapes',
        'kendo.color'
    ], f);
}(function () {
    (function ($) {
        var doc = document, math = Math, atan2 = math.atan2, ceil = math.ceil, sqrt = math.sqrt, kendo = window.kendo, deepExtend = kendo.deepExtend, noop = $.noop, d = kendo.drawing, BaseNode = d.BaseNode, g = kendo.geometry, toMatrix = g.toMatrix, Color = kendo.Color, util = kendo.util, isTransparent = util.isTransparent, defined = util.defined, deg = util.deg, round = util.round, valueOrDefault = util.valueOrDefault;
        var NONE = 'none', NS = '.kendo', COORDINATE_MULTIPLE = 100, COORDINATE_SIZE = COORDINATE_MULTIPLE * COORDINATE_MULTIPLE, GRADIENT = 'gradient', TRANSFORM_PRECISION = 4;
        var Surface = d.Surface.extend({
            init: function (element, options) {
                d.Surface.fn.init.call(this, element, options);
                enableVML();
                this.element.empty();
                this._root = new RootNode();
                this._root.attachTo(this.element[0]);
                this.element.on('click' + NS, this._click);
                this.element.on('mouseover' + NS, this._mouseenter);
                this.element.on('mouseout' + NS, this._mouseleave);
                this.element.on('mousemove' + NS, this._mousemove);
            },
            type: 'vml',
            destroy: function () {
                if (this._root) {
                    this._root.destroy();
                    this._root = null;
                    this.element.off(NS);
                }
                d.Surface.fn.destroy.call(this);
            },
            draw: function (element) {
                d.Surface.fn.draw.call(this, element);
                this._root.load([element], undefined, null);
            },
            clear: function () {
                d.Surface.fn.clear.call(this);
                this._root.clear();
            }
        });
        var Node = BaseNode.extend({
            init: function (srcElement) {
                BaseNode.fn.init.call(this, srcElement);
                this.createElement();
                this.attachReference();
            },
            observe: noop,
            destroy: function () {
                if (this.element) {
                    this.element._kendoNode = null;
                    this.element = null;
                }
                BaseNode.fn.destroy.call(this);
            },
            clear: function () {
                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) {
                    this.element.parentNode.removeChild(this.element);
                    this.element = null;
                }
                BaseNode.fn.removeSelf.call(this);
            },
            createElement: function () {
                this.element = doc.createElement('div');
            },
            attachReference: function () {
                this.element._kendoNode = this;
            },
            load: function (elements, pos, transform, opacity) {
                opacity = valueOrDefault(opacity, 1);
                if (this.srcElement) {
                    opacity *= valueOrDefault(this.srcElement.options.opacity, 1);
                }
                for (var i = 0; i < elements.length; i++) {
                    var srcElement = elements[i];
                    var children = srcElement.children;
                    var combinedTransform = srcElement.currentTransform(transform);
                    var currentOpacity = opacity * valueOrDefault(srcElement.options.opacity, 1);
                    var childNode = new nodeMap[srcElement.nodeType](srcElement, combinedTransform, currentOpacity);
                    if (children && children.length > 0) {
                        childNode.load(children, pos, combinedTransform, opacity);
                    }
                    if (defined(pos)) {
                        this.insertAt(childNode, pos);
                    } else {
                        this.append(childNode);
                    }
                    childNode.attachTo(this.element, pos);
                }
            },
            attachTo: function (domElement, pos) {
                if (defined(pos)) {
                    domElement.insertBefore(this.element, domElement.children[pos] || null);
                } else {
                    domElement.appendChild(this.element);
                }
            },
            optionsChange: function (e) {
                if (e.field == 'visible') {
                    this.css('display', e.value !== false ? '' : NONE);
                }
            },
            setStyle: function () {
                this.allCss(this.mapStyle());
            },
            mapStyle: function () {
                var style = [];
                if (this.srcElement && this.srcElement.options.visible === false) {
                    style.push([
                        'display',
                        NONE
                    ]);
                }
                return style;
            },
            mapOpacityTo: function (attrs, multiplier) {
                var opacity = valueOrDefault(this.opacity, 1);
                opacity *= valueOrDefault(multiplier, 1);
                attrs.push([
                    'opacity',
                    opacity
                ]);
            },
            attr: function (name, value) {
                if (this.element) {
                    this.element[name] = value;
                }
            },
            allAttr: function (attrs) {
                for (var i = 0; i < attrs.length; i++) {
                    this.attr(attrs[i][0], attrs[i][1]);
                }
            },
            css: function (name, value) {
                if (this.element) {
                    this.element.style[name] = value;
                }
            },
            allCss: function (styles) {
                for (var i = 0; i < styles.length; i++) {
                    this.css(styles[i][0], styles[i][1]);
                }
            }
        });
        var RootNode = Node.extend({
            createElement: function () {
                Node.fn.createElement.call(this);
                this.allCss([
                    [
                        'width',
                        '100%'
                    ],
                    [
                        'height',
                        '100%'
                    ],
                    [
                        'position',
                        'relative'
                    ],
                    [
                        'visibility',
                        'visible'
                    ]
                ]);
            },
            attachReference: noop
        });
        var ClipObserver = kendo.Class.extend({
            init: function (srcElement, observer) {
                this.srcElement = srcElement;
                this.observer = observer;
                srcElement.addObserver(this);
            },
            geometryChange: function () {
                this.observer.optionsChange({
                    field: 'clip',
                    value: this.srcElement
                });
            },
            clear: function () {
                this.srcElement.removeObserver(this);
            }
        });
        var ObserverNode = Node.extend({
            init: function (srcElement) {
                Node.fn.init.call(this, srcElement);
                if (srcElement) {
                    this.initClip();
                }
            },
            observe: function () {
                BaseNode.fn.observe.call(this);
            },
            mapStyle: function () {
                var style = Node.fn.mapStyle.call(this);
                if (this.srcElement && this.srcElement.clip()) {
                    style.push([
                        'clip',
                        this.clipRect()
                    ]);
                }
                return style;
            },
            optionsChange: function (e) {
                if (e.field == 'clip') {
                    this.clearClip();
                    this.initClip();
                    this.setClip();
                }
                Node.fn.optionsChange.call(this, e);
            },
            clear: function () {
                this.clearClip();
                Node.fn.clear.call(this);
            },
            initClip: function () {
                if (this.srcElement.clip()) {
                    this.clip = new ClipObserver(this.srcElement.clip(), this);
                    this.clip.observer = this;
                }
            },
            clearClip: function () {
                if (this.clip) {
                    this.clip.clear();
                    this.clip = null;
                    this.css('clip', this.clipRect());
                }
            },
            setClip: function () {
                if (this.clip) {
                    this.css('clip', this.clipRect());
                }
            },
            clipRect: function () {
                var clipRect = EMPTY_CLIP;
                var clip = this.srcElement.clip();
                if (clip) {
                    var bbox = this.clipBBox(clip);
                    var topLeft = bbox.topLeft();
                    var bottomRight = bbox.bottomRight();
                    clipRect = kendo.format('rect({0}px {1}px {2}px {3}px)', topLeft.y, bottomRight.x, bottomRight.y, topLeft.x);
                }
                return clipRect;
            },
            clipBBox: function (clip) {
                var topLeft = this.srcElement.rawBBox().topLeft();
                var clipBBox = clip.rawBBox();
                clipBBox.origin.translate(-topLeft.x, -topLeft.y);
                return clipBBox;
            }
        });
        var GroupNode = ObserverNode.extend({
            createElement: function () {
                Node.fn.createElement.call(this);
                this.setStyle();
            },
            attachTo: function (domElement, pos) {
                this.css('display', NONE);
                Node.fn.attachTo.call(this, domElement, pos);
                if (this.srcElement.options.visible !== false) {
                    this.css('display', '');
                }
            },
            _attachTo: function (domElement) {
                var frag = document.createDocumentFragment();
                frag.appendChild(this.element);
                domElement.appendChild(frag);
            },
            mapStyle: function () {
                var style = ObserverNode.fn.mapStyle.call(this);
                style.push([
                    'position',
                    'absolute'
                ]);
                style.push([
                    'white-space',
                    'nowrap'
                ]);
                return style;
            },
            optionsChange: function (e) {
                if (e.field === 'transform') {
                    this.refreshTransform();
                }
                if (e.field === 'opacity') {
                    this.refreshOpacity();
                }
                ObserverNode.fn.optionsChange.call(this, e);
            },
            refreshTransform: function (transform) {
                var currentTransform = this.srcElement.currentTransform(transform), children = this.childNodes, length = children.length, i;
                this.setClip();
                for (i = 0; i < length; i++) {
                    children[i].refreshTransform(currentTransform);
                }
            },
            currentOpacity: function () {
                var opacity = valueOrDefault(this.srcElement.options.opacity, 1);
                if (this.parent && this.parent.currentOpacity) {
                    opacity *= this.parent.currentOpacity();
                }
                return opacity;
            },
            refreshOpacity: function () {
                var children = this.childNodes, length = children.length, i;
                var opacity = this.currentOpacity();
                for (i = 0; i < length; i++) {
                    children[i].refreshOpacity(opacity);
                }
            },
            initClip: function () {
                ObserverNode.fn.initClip.call(this);
                if (this.clip) {
                    var bbox = this.clip.srcElement.bbox(this.srcElement.currentTransform());
                    if (bbox) {
                        this.css('width', bbox.width() + bbox.origin.x);
                        this.css('height', bbox.height() + bbox.origin.y);
                    }
                }
            },
            clipBBox: function (clip) {
                return clip.bbox(this.srcElement.currentTransform());
            },
            clearClip: function () {
                ObserverNode.fn.clearClip.call(this);
            }
        });
        var StrokeNode = Node.extend({
            init: function (srcElement, opacity) {
                this.opacity = opacity;
                Node.fn.init.call(this, srcElement);
            },
            createElement: function () {
                this.element = createElementVML('stroke');
                this.setOpacity();
            },
            optionsChange: function (e) {
                if (e.field.indexOf('stroke') === 0) {
                    this.setStroke();
                }
            },
            refreshOpacity: function (opacity) {
                this.opacity = opacity;
                this.setStroke();
            },
            setStroke: function () {
                this.allAttr(this.mapStroke());
            },
            setOpacity: function () {
                this.setStroke();
            },
            mapStroke: function () {
                var stroke = this.srcElement.options.stroke;
                var attrs = [];
                if (stroke && !isTransparent(stroke.color) && stroke.width !== 0) {
                    attrs.push([
                        'on',
                        'true'
                    ]);
                    attrs.push([
                        'color',
                        stroke.color
                    ]);
                    attrs.push([
                        'weight',
                        (stroke.width || 1) + 'px'
                    ]);
                    this.mapOpacityTo(attrs, stroke.opacity);
                    if (defined(stroke.dashType)) {
                        attrs.push([
                            'dashstyle',
                            stroke.dashType
                        ]);
                    }
                    if (defined(stroke.lineJoin)) {
                        attrs.push([
                            'joinstyle',
                            stroke.lineJoin
                        ]);
                    }
                    if (defined(stroke.lineCap)) {
                        var lineCap = stroke.lineCap.toLowerCase();
                        if (lineCap === 'butt') {
                            lineCap = lineCap === 'butt' ? 'flat' : lineCap;
                        }
                        attrs.push([
                            'endcap',
                            lineCap
                        ]);
                    }
                } else {
                    attrs.push([
                        'on',
                        'false'
                    ]);
                }
                return attrs;
            }
        });
        var FillNode = Node.extend({
            init: function (srcElement, transform, opacity) {
                this.opacity = opacity;
                Node.fn.init.call(this, srcElement);
            },
            createElement: function () {
                this.element = createElementVML('fill');
                this.setFill();
            },
            optionsChange: function (e) {
                if (fillField(e.field)) {
                    this.setFill();
                }
            },
            refreshOpacity: function (opacity) {
                this.opacity = opacity;
                this.setOpacity();
            },
            setFill: function () {
                this.allAttr(this.mapFill());
            },
            setOpacity: function () {
                this.setFill();
            },
            attr: function (name, value) {
                var element = this.element;
                if (element) {
                    var fields = name.split('.');
                    while (fields.length > 1) {
                        element = element[fields.shift()];
                    }
                    element[fields[0]] = value;
                }
            },
            mapFill: function () {
                var fill = this.srcElement.fill();
                var attrs = [[
                        'on',
                        'false'
                    ]];
                if (fill) {
                    if (fill.nodeType == GRADIENT) {
                        attrs = this.mapGradient(fill);
                    } else if (!isTransparent(fill.color)) {
                        attrs = this.mapFillColor(fill);
                    }
                }
                return attrs;
            },
            mapFillColor: function (fill) {
                var attrs = [
                    [
                        'on',
                        'true'
                    ],
                    [
                        'color',
                        fill.color
                    ]
                ];
                this.mapOpacityTo(attrs, fill.opacity);
                return attrs;
            },
            mapGradient: function (fill) {
                var options = this.srcElement.options;
                var fallbackFill = options.fallbackFill || fill.fallbackFill && fill.fallbackFill();
                var attrs;
                if (fill instanceof d.LinearGradient) {
                    attrs = this.mapLinearGradient(fill);
                } else if (fill instanceof d.RadialGradient && fill.supportVML) {
                    attrs = this.mapRadialGradient(fill);
                } else if (fallbackFill) {
                    attrs = this.mapFillColor(fallbackFill);
                } else {
                    attrs = [[
                            'on',
                            'false'
                        ]];
                }
                return attrs;
            },
            mapLinearGradient: function (fill) {
                var start = fill.start();
                var end = fill.end();
                var angle = util.deg(atan2(end.y - start.y, end.x - start.x));
                var attrs = [
                    [
                        'on',
                        'true'
                    ],
                    [
                        'type',
                        GRADIENT
                    ],
                    [
                        'focus',
                        0
                    ],
                    [
                        'method',
                        'none'
                    ],
                    [
                        'angle',
                        270 - angle
                    ]
                ];
                this.addColors(attrs);
                return attrs;
            },
            mapRadialGradient: function (fill) {
                var bbox = this.srcElement.rawBBox();
                var center = fill.center();
                var focusx = (center.x - bbox.origin.x) / bbox.width();
                var focusy = (center.y - bbox.origin.y) / bbox.height();
                var attrs = [
                    [
                        'on',
                        'true'
                    ],
                    [
                        'type',
                        'gradienttitle'
                    ],
                    [
                        'focus',
                        '100%'
                    ],
                    [
                        'focusposition',
                        focusx + ' ' + focusy
                    ],
                    [
                        'method',
                        'none'
                    ]
                ];
                this.addColors(attrs);
                return attrs;
            },
            addColors: function (attrs) {
                var options = this.srcElement.options;
                var opacity = valueOrDefault(this.opacity, 1);
                var stopColors = [];
                var stops = options.fill.stops;
                var baseColor = options.baseColor;
                var colorsField = this.element.colors ? 'colors.value' : 'colors';
                var color = stopColor(baseColor, stops[0], opacity);
                var color2 = stopColor(baseColor, stops[stops.length - 1], opacity);
                var stop;
                for (var idx = 0; idx < stops.length; idx++) {
                    stop = stops[idx];
                    stopColors.push(math.round(stop.offset() * 100) + '% ' + stopColor(baseColor, stop, opacity));
                }
                attrs.push([
                    colorsField,
                    stopColors.join(',')
                ], [
                    'color',
                    color
                ], [
                    'color2',
                    color2
                ]);
            }
        });
        var TransformNode = Node.extend({
            init: function (srcElement, transform) {
                this.transform = transform;
                Node.fn.init.call(this, srcElement);
            },
            createElement: function () {
                this.element = createElementVML('skew');
                this.setTransform();
            },
            optionsChange: function (e) {
                if (e.field === 'transform') {
                    this.refresh(this.srcElement.currentTransform());
                }
            },
            refresh: function (transform) {
                this.transform = transform;
                this.setTransform();
            },
            transformOrigin: function () {
                return '-0.5,-0.5';
            },
            setTransform: function () {
                this.allAttr(this.mapTransform());
            },
            mapTransform: function () {
                var transform = this.transform;
                var attrs = [], matrix = toMatrix(transform);
                if (matrix) {
                    matrix.round(TRANSFORM_PRECISION);
                    attrs.push([
                        'on',
                        'true'
                    ], [
                        'matrix',
                        [
                            matrix.a,
                            matrix.c,
                            matrix.b,
                            matrix.d,
                            0,
                            0
                        ].join(',')
                    ], [
                        'offset',
                        matrix.e + 'px,' + matrix.f + 'px'
                    ], [
                        'origin',
                        this.transformOrigin()
                    ]);
                } else {
                    attrs.push([
                        'on',
                        'false'
                    ]);
                }
                return attrs;
            }
        });
        var ShapeNode = ObserverNode.extend({
            init: function (srcElement, transform, opacity) {
                this.fill = this.createFillNode(srcElement, transform, opacity);
                this.stroke = new StrokeNode(srcElement, opacity);
                this.transform = this.createTransformNode(srcElement, transform);
                ObserverNode.fn.init.call(this, srcElement);
            },
            attachTo: function (domElement, pos) {
                this.fill.attachTo(this.element);
                this.stroke.attachTo(this.element);
                this.transform.attachTo(this.element);
                Node.fn.attachTo.call(this, domElement, pos);
            },
            createFillNode: function (srcElement, transform, opacity) {
                return new FillNode(srcElement, transform, opacity);
            },
            createTransformNode: function (srcElement, transform) {
                return new TransformNode(srcElement, transform);
            },
            createElement: function () {
                this.element = createElementVML('shape');
                this.setCoordsize();
                this.setStyle();
            },
            optionsChange: function (e) {
                if (fillField(e.field)) {
                    this.fill.optionsChange(e);
                } else if (e.field.indexOf('stroke') === 0) {
                    this.stroke.optionsChange(e);
                } else if (e.field === 'transform') {
                    this.transform.optionsChange(e);
                } else if (e.field === 'opacity') {
                    this.fill.setOpacity();
                    this.stroke.setOpacity();
                }
                ObserverNode.fn.optionsChange.call(this, e);
            },
            refreshTransform: function (transform) {
                this.transform.refresh(this.srcElement.currentTransform(transform));
            },
            refreshOpacity: function (opacity) {
                opacity *= valueOrDefault(this.srcElement.options.opacity, 1);
                this.fill.refreshOpacity(opacity);
                this.stroke.refreshOpacity(opacity);
            },
            mapStyle: function (width, height) {
                var styles = ObserverNode.fn.mapStyle.call(this);
                if (!width || !height) {
                    width = height = COORDINATE_MULTIPLE;
                }
                styles.push([
                    'position',
                    'absolute'
                ], [
                    'width',
                    width + 'px'
                ], [
                    'height',
                    height + 'px'
                ]);
                var cursor = this.srcElement.options.cursor;
                if (cursor) {
                    styles.push([
                        'cursor',
                        cursor
                    ]);
                }
                return styles;
            },
            setCoordsize: function () {
                this.allAttr([
                    [
                        'coordorigin',
                        '0 0'
                    ],
                    [
                        'coordsize',
                        COORDINATE_SIZE + ' ' + COORDINATE_SIZE
                    ]
                ]);
            }
        });
        var PathDataNode = Node.extend({
            createElement: function () {
                this.element = createElementVML('path');
                this.setPathData();
            },
            geometryChange: function () {
                this.setPathData();
            },
            setPathData: function () {
                this.attr('v', this.renderData());
            },
            renderData: function () {
                return printPath(this.srcElement);
            }
        });
        var PathNode = ShapeNode.extend({
            init: function (srcElement, transform, opacity) {
                this.pathData = this.createDataNode(srcElement);
                ShapeNode.fn.init.call(this, srcElement, transform, opacity);
            },
            attachTo: function (domElement, pos) {
                this.pathData.attachTo(this.element);
                ShapeNode.fn.attachTo.call(this, domElement, pos);
            },
            createDataNode: function (srcElement) {
                return new PathDataNode(srcElement);
            },
            geometryChange: function () {
                this.pathData.geometryChange();
                ShapeNode.fn.geometryChange.call(this);
            }
        });
        var MultiPathDataNode = PathDataNode.extend({
            renderData: function () {
                var paths = this.srcElement.paths;
                if (paths.length > 0) {
                    var result = [], i, open;
                    for (i = 0; i < paths.length; i++) {
                        open = i < paths.length - 1;
                        result.push(printPath(paths[i], open));
                    }
                    return result.join(' ');
                }
            }
        });
        var MultiPathNode = PathNode.extend({
            createDataNode: function (srcElement) {
                return new MultiPathDataNode(srcElement);
            }
        });
        var CircleTransformNode = TransformNode.extend({
            transformOrigin: function () {
                var boundingBox = this.srcElement.geometry().bbox(), center = boundingBox.center(), originX = -ceil(center.x) / ceil(boundingBox.width()), originY = -ceil(center.y) / ceil(boundingBox.height());
                return originX + ',' + originY;
            }
        });
        var CircleNode = ShapeNode.extend({
            createElement: function () {
                this.element = createElementVML('oval');
                this.setStyle();
            },
            createTransformNode: function (srcElement, transform) {
                return new CircleTransformNode(srcElement, transform);
            },
            geometryChange: function () {
                ShapeNode.fn.geometryChange.call(this);
                this.setStyle();
                this.refreshTransform();
            },
            mapStyle: function () {
                var geometry = this.srcElement.geometry();
                var radius = geometry.radius;
                var center = geometry.center;
                var diameter = ceil(radius * 2);
                var styles = ShapeNode.fn.mapStyle.call(this, diameter, diameter);
                styles.push([
                    'left',
                    ceil(center.x - radius) + 'px'
                ], [
                    'top',
                    ceil(center.y - radius) + 'px'
                ]);
                return styles;
            }
        });
        var ArcDataNode = PathDataNode.extend({
            renderData: function () {
                return printPath(this.srcElement.toPath());
            }
        });
        var ArcNode = PathNode.extend({
            createDataNode: function (srcElement) {
                return new ArcDataNode(srcElement);
            }
        });
        var TextPathDataNode = PathDataNode.extend({
            createElement: function () {
                PathDataNode.fn.createElement.call(this);
                this.attr('textpathok', true);
            },
            renderData: function () {
                var rect = this.srcElement.rect();
                var center = rect.center();
                return 'm ' + printPoints([new g.Point(rect.topLeft().x, center.y)]) + ' l ' + printPoints([new g.Point(rect.bottomRight().x, center.y)]);
            }
        });
        var TextPathNode = Node.extend({
            createElement: function () {
                this.element = createElementVML('textpath');
                this.attr('on', true);
                this.attr('fitpath', false);
                this.setStyle();
                this.setString();
            },
            optionsChange: function (e) {
                if (e.field === 'content') {
                    this.setString();
                } else {
                    this.setStyle();
                }
                Node.fn.optionsChange.call(this, e);
            },
            mapStyle: function () {
                return [[
                        'font',
                        this.srcElement.options.font
                    ]];
            },
            setString: function () {
                this.attr('string', this.srcElement.content());
            }
        });
        var TextNode = PathNode.extend({
            init: function (srcElement, transform, opacity) {
                this.path = new TextPathNode(srcElement);
                PathNode.fn.init.call(this, srcElement, transform, opacity);
            },
            createDataNode: function (srcElement) {
                return new TextPathDataNode(srcElement);
            },
            attachTo: function (domElement, pos) {
                this.path.attachTo(this.element);
                PathNode.fn.attachTo.call(this, domElement, pos);
            },
            optionsChange: function (e) {
                if (e.field === 'font' || e.field === 'content') {
                    this.path.optionsChange(e);
                    this.pathData.geometryChange(e);
                }
                PathNode.fn.optionsChange.call(this, e);
            }
        });
        var ImagePathDataNode = PathDataNode.extend({
            renderData: function () {
                var rect = this.srcElement.rect();
                var path = new d.Path().moveTo(rect.topLeft()).lineTo(rect.topRight()).lineTo(rect.bottomRight()).lineTo(rect.bottomLeft()).close();
                return printPath(path);
            }
        });
        var ImageFillNode = TransformNode.extend({
            init: function (srcElement, transform, opacity) {
                this.opacity = opacity;
                TransformNode.fn.init.call(this, srcElement, transform);
            },
            createElement: function () {
                this.element = createElementVML('fill');
                this.attr('type', 'frame');
                this.attr('rotate', true);
                this.setOpacity();
                this.setSrc();
                this.setTransform();
            },
            optionsChange: function (e) {
                if (e.field === 'src') {
                    this.setSrc();
                }
                TransformNode.fn.optionsChange.call(this, e);
            },
            geometryChange: function () {
                this.refresh();
            },
            refreshOpacity: function (opacity) {
                this.opacity = opacity;
                this.setOpacity();
            },
            setOpacity: function () {
                var attrs = [];
                this.mapOpacityTo(attrs, this.srcElement.options.opacity);
                this.allAttr(attrs);
            },
            setSrc: function () {
                this.attr('src', this.srcElement.src());
            },
            mapTransform: function () {
                var img = this.srcElement;
                var rawbbox = img.rawBBox();
                var rawcenter = rawbbox.center();
                var fillOrigin = COORDINATE_MULTIPLE / 2;
                var fillSize = COORDINATE_MULTIPLE;
                var x;
                var y;
                var width = rawbbox.width() / fillSize;
                var height = rawbbox.height() / fillSize;
                var angle = 0;
                var transform = this.transform;
                if (transform) {
                    var matrix = toMatrix(transform);
                    var sx = sqrt(matrix.a * matrix.a + matrix.b * matrix.b);
                    var sy = sqrt(matrix.c * matrix.c + matrix.d * matrix.d);
                    width *= sx;
                    height *= sy;
                    var ax = deg(atan2(matrix.b, matrix.d));
                    var ay = deg(atan2(-matrix.c, matrix.a));
                    angle = (ax + ay) / 2;
                    if (angle !== 0) {
                        var center = img.bbox().center();
                        x = (center.x - fillOrigin) / fillSize;
                        y = (center.y - fillOrigin) / fillSize;
                    } else {
                        x = (rawcenter.x * sx + matrix.e - fillOrigin) / fillSize;
                        y = (rawcenter.y * sy + matrix.f - fillOrigin) / fillSize;
                    }
                } else {
                    x = (rawcenter.x - fillOrigin) / fillSize;
                    y = (rawcenter.y - fillOrigin) / fillSize;
                }
                width = round(width, TRANSFORM_PRECISION);
                height = round(height, TRANSFORM_PRECISION);
                x = round(x, TRANSFORM_PRECISION);
                y = round(y, TRANSFORM_PRECISION);
                angle = round(angle, TRANSFORM_PRECISION);
                return [
                    [
                        'size',
                        width + ',' + height
                    ],
                    [
                        'position',
                        x + ',' + y
                    ],
                    [
                        'angle',
                        angle
                    ]
                ];
            }
        });
        var ImageNode = PathNode.extend({
            createFillNode: function (srcElement, transform, opacity) {
                return new ImageFillNode(srcElement, transform, opacity);
            },
            createDataNode: function (srcElement) {
                return new ImagePathDataNode(srcElement);
            },
            optionsChange: function (e) {
                if (e.field === 'src' || e.field === 'transform') {
                    this.fill.optionsChange(e);
                }
                PathNode.fn.optionsChange.call(this, e);
            },
            geometryChange: function () {
                this.fill.geometryChange();
                PathNode.fn.geometryChange.call(this);
            },
            refreshTransform: function (transform) {
                PathNode.fn.refreshTransform.call(this, transform);
                this.fill.refresh(this.srcElement.currentTransform(transform));
            }
        });
        var RectDataNode = PathDataNode.extend({
            renderData: function () {
                var rect = this.srcElement.geometry();
                var parts = [
                    'm',
                    printPoints([rect.topLeft()]),
                    'l',
                    printPoints([
                        rect.topRight(),
                        rect.bottomRight(),
                        rect.bottomLeft()
                    ]),
                    'x e'
                ];
                return parts.join(' ');
            }
        });
        var RectNode = PathNode.extend({
            createDataNode: function (srcElement) {
                return new RectDataNode(srcElement);
            }
        });
        var nodeMap = {
            Group: GroupNode,
            Text: TextNode,
            Path: PathNode,
            MultiPath: MultiPathNode,
            Circle: CircleNode,
            Arc: ArcNode,
            Image: ImageNode,
            Rect: RectNode
        };
        function enableVML() {
            if (doc.namespaces && !doc.namespaces.kvml) {
                doc.namespaces.add('kvml', 'urn:schemas-microsoft-com:vml');
                var stylesheet = doc.styleSheets.length > 30 ? doc.styleSheets[0] : doc.createStyleSheet();
                stylesheet.addRule('.kvml', 'behavior:url(#default#VML)');
            }
        }
        function createElementVML(type) {
            var element = doc.createElement('kvml:' + type);
            element.className = 'kvml';
            return element;
        }
        function printPoints(points) {
            var length = points.length;
            var result = [];
            for (var i = 0; i < length; i++) {
                result.push(points[i].scaleCopy(COORDINATE_MULTIPLE).toString(0, ','));
            }
            return result.join(' ');
        }
        function printPath(path, open) {
            var segments = path.segments, length = segments.length;
            if (length > 0) {
                var parts = [], output, type, currentType, i;
                for (i = 1; i < length; i++) {
                    type = segmentType(segments[i - 1], segments[i]);
                    if (type !== currentType) {
                        currentType = type;
                        parts.push(type);
                    }
                    if (type === 'l') {
                        parts.push(printPoints([segments[i].anchor()]));
                    } else {
                        parts.push(printPoints([
                            segments[i - 1].controlOut(),
                            segments[i].controlIn(),
                            segments[i].anchor()
                        ]));
                    }
                }
                output = 'm ' + printPoints([segments[0].anchor()]) + ' ' + parts.join(' ');
                if (path.options.closed) {
                    output += ' x';
                }
                if (open !== true) {
                    output += ' e';
                }
                return output;
            }
        }
        function segmentType(segmentStart, segmentEnd) {
            return segmentStart.controlOut() && segmentEnd.controlIn() ? 'c' : 'l';
        }
        function fillField(field) {
            return field.indexOf('fill') === 0 || field.indexOf(GRADIENT) === 0;
        }
        function stopColor(baseColor, stop, baseOpacity) {
            var opacity = baseOpacity * valueOrDefault(stop.opacity(), 1);
            var color;
            if (baseColor) {
                color = blendColors(baseColor, stop.color(), opacity);
            } else {
                color = blendColors(stop.color(), '#fff', 1 - opacity);
            }
            return color;
        }
        function blendColors(base, overlay, alpha) {
            var baseColor = new Color(base), overlayColor = new Color(overlay), r = blendChannel(baseColor.r, overlayColor.r, alpha), g = blendChannel(baseColor.g, overlayColor.g, alpha), b = blendChannel(baseColor.b, overlayColor.b, alpha);
            return new Color(r, g, b).toHex();
        }
        function blendChannel(a, b, alpha) {
            return math.round(alpha * b + (1 - alpha) * a);
        }
        kendo.support.vml = function () {
            var browser = kendo.support.browser;
            return browser.msie && browser.version < 9;
        }();
        var EMPTY_CLIP = 'inherit';
        if (kendo.support.browser.msie && kendo.support.browser.version < 8) {
            EMPTY_CLIP = 'rect(auto auto auto auto)';
        }
        if (kendo.support.vml) {
            d.SurfaceFactory.current.register('vml', Surface, 30);
        }
        deepExtend(d, {
            vml: {
                ArcDataNode: ArcDataNode,
                ArcNode: ArcNode,
                CircleTransformNode: CircleTransformNode,
                CircleNode: CircleNode,
                FillNode: FillNode,
                GroupNode: GroupNode,
                ImageNode: ImageNode,
                ImageFillNode: ImageFillNode,
                ImagePathDataNode: ImagePathDataNode,
                MultiPathDataNode: MultiPathDataNode,
                MultiPathNode: MultiPathNode,
                Node: Node,
                PathDataNode: PathDataNode,
                PathNode: PathNode,
                RectDataNode: RectDataNode,
                RectNode: RectNode,
                RootNode: RootNode,
                StrokeNode: StrokeNode,
                Surface: Surface,
                TextNode: TextNode,
                TextPathNode: TextPathNode,
                TextPathDataNode: TextPathDataNode,
                TransformNode: TransformNode
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/html', [
        'kendo.color',
        'drawing/shapes',
        'util/main',
        'util/text-metrics'
    ], f);
}(function () {
    (function ($, parseFloat, Math) {
        'use strict';
        var drawing = kendo.drawing;
        var geo = kendo.geometry;
        var slice = Array.prototype.slice;
        var browser = kendo.support.browser;
        var romanNumeral = kendo.util.arabicToRoman;
        var mergeSort = kendo.util.mergeSort;
        var KENDO_PSEUDO_ELEMENT = 'KENDO-PSEUDO-ELEMENT';
        var IMAGE_CACHE = {};
        var nodeInfo = {};
        nodeInfo._root = nodeInfo;
        var TextRect = drawing.Text.extend({
            nodeType: 'Text',
            init: function (str, rect, options) {
                drawing.Text.fn.init.call(this, str, rect.getOrigin(), options);
                this._pdfRect = rect;
            },
            rect: function () {
                return this._pdfRect;
            },
            rawBBox: function () {
                return this._pdfRect;
            }
        });
        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 defer = $.Deferred();
            element = $(element)[0];
            if (!element) {
                return defer.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+.');
            }
            if (kendo.pdf) {
                kendo.pdf.defineFont(getFontFaces(element.ownerDocument));
            }
            var scale = getXY(options.scale || 1);
            function doOne(element) {
                var group = new drawing.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 = geo.Matrix.unit();
                nodeInfo._stackingContext = {
                    element: element,
                    group: group
                };
                if (options.avoidLinks === true) {
                    nodeInfo._avoidLinks = 'a';
                } else {
                    nodeInfo._avoidLinks = options.avoidLinks;
                }
                $(element).addClass('k-pdf-export');
                renderElement(element, group);
                $(element).removeClass('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 = !!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 drawing.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);
                                    defer.resolve(group);
                                }
                            }());
                        } else {
                            x.pages.forEach(function (page) {
                                group.append(doOne(page));
                            });
                            x.container.parentNode.removeChild(x.container);
                            defer.resolve(group);
                        }
                    }, element, forceBreak, pageWidth ? pageWidth - margin.left - margin.right : null, pageHeight ? pageHeight - margin.top - margin.bottom : null, margin, options);
                } else {
                    defer.resolve(doOne(element));
                }
            });
            function makeTemplate(template) {
                if (template != null) {
                    if (typeof template == 'string') {
                        template = kendo.template(template.replace(/^\s+|\s+$/g, ''));
                    }
                    if (typeof template == 'function') {
                        return function (data) {
                            var el = template(data);
                            if (el) {
                                if (typeof el == 'string') {
                                    el = el.replace(/^\s+|\s+$/g, '');
                                }
                                return $(el)[0];
                            }
                        };
                    }
                    return function () {
                        return $(template).clone()[0];
                    };
                }
            }
            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$/i.test(el.tagName)) {
                        el.removeAttribute('name');
                    } else {
                        for (i = el.firstChild; i; i = i.nextSibling) {
                            clone.appendChild(cloneNodes(i));
                        }
                    }
                }
                return clone;
            }
            function handlePageBreaks(callback, element, forceBreak, pageWidth, pageHeight, margin, options) {
                var template = 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;
                $(copy).find('tfoot').each(function () {
                    this.parentNode.appendChild(this);
                });
                $(copy).find('ol').each(function () {
                    $(this).children().each(function (index) {
                        this.setAttribute('kendo-split-index', index);
                    });
                });
                $(container).css({
                    display: 'block',
                    position: 'absolute',
                    boxSizing: 'content-box',
                    left: '-10000px',
                    top: '-10000px'
                });
                if (pageWidth) {
                    $(container).css({
                        width: pageWidth,
                        paddingLeft: margin.left,
                        paddingRight: margin.right
                    });
                    $(copy).css({ 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) {
                        var count = pages.length;
                        pages.forEach(function (page, i) {
                            var el = template({
                                element: page,
                                pageNum: i + 1,
                                totalPages: pages.length
                            });
                            if (el) {
                                page.appendChild(el);
                                cacheImages(el, function () {
                                    if (--count === 0) {
                                        next();
                                    }
                                });
                            }
                        });
                    } else {
                        next();
                    }
                    function next() {
                        whenImagesAreActuallyLoaded(pages, function () {
                            callback({
                                pages: pages,
                                container: container
                            });
                        });
                    }
                }
                function keepTogether(jqel) {
                    if (options.keepTogether && jqel.is(options.keepTogether) && jqel.height() <= pageHeight - adjust) {
                        return true;
                    }
                    var tag = jqel[0].tagName;
                    if (/^h[1-6]$/i.test(tag) && jqel.height() >= pageHeight - adjust) {
                        return false;
                    }
                    return jqel.data('kendoChart') || /^(?:img|tr|thead|th|tfoot|iframe|svg|object|canvas|input|textarea|select|video|h[1-6])$/i.test(tag);
                }
                function splitElement(element) {
                    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;
                            var jqel = $(el);
                            if (jqel.is(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(jqel)) {
                                    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 = $(el).closest('table');
                    colgroup = table.find('colgroup:first');
                    if (options.repeatHeaders) {
                        thead = table.find('thead:first');
                        grid = $(el).closest('.k-grid[data-role="grid"]');
                        if (grid[0] && grid[0].querySelector('.k-auto-scrollable')) {
                            gridHead = grid.find('.k-grid-header:first');
                        }
                    }
                    var page = makePage();
                    var range = doc.createRange();
                    range.setStartBefore(copy);
                    range.setEndBefore(el);
                    page.appendChild(range.extractContents());
                    copy.parentNode.insertBefore(page, copy);
                    if (table[0]) {
                        table = $(el).closest('table');
                        if (options.repeatHeaders && thead[0]) {
                            thead.clone().prependTo(table);
                        }
                        if (colgroup[0]) {
                            colgroup.clone().prependTo(table);
                        }
                    }
                    if (options.repeatHeaders && gridHead && gridHead[0]) {
                        grid = $(el).closest('.k-grid[data-role="grid"]');
                        if (gridHead[0]) {
                            gridHead.clone().prependTo(grid);
                        }
                    }
                }
                function makePage() {
                    var page = doc.createElement('KENDO-PDF-PAGE');
                    $(page).css({
                        display: 'block',
                        boxSizing: 'content-box',
                        width: pageWidth || 'auto',
                        padding: margin.top + 'px ' + margin.right + 'px ' + margin.bottom + 'px ' + margin.left + 'px',
                        position: 'relative',
                        height: pageHeight || '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);
                        }
                    }
                    splitText(nextnode);
                }
            }
            return defer.promise();
        }
        drawing.drawDOM = drawDOM;
        drawDOM.getFontFaces = getFontFaces;
        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) {
                        input = input.substr(color.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 = 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) {
                            ret.push(trim(input.substring(last, pos)));
                            last = pos + m[0].length;
                        }
                        pos += m[0].length;
                    } else {
                        pos++;
                    }
                }
                if (last < pos) {
                    ret.push(trim(input.substring(last, 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(null));
        var getFontHeight = function (cache) {
            return function (font) {
                var height = cache[font];
                if (height == null) {
                    height = cache[font] = kendo.util.measureText('Mapq', { font: font }).height;
                }
                return height;
            };
        }(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 parseColor(str, css) {
            var color = kendo.parseColor(str);
            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.call(element.children).forEach(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 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 = geo.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) {
            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 (browser.msie) {
                    val = style.getPropertyValue('-ms-' + prop);
                }
            }
            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 (browser.msie) {
                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(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 = getPropertyValue(style, 'transform');
            if (transform == 'none') {
                return null;
            }
            var matrix = /^\s*matrix\(\s*(.*?)\s*\)\s*$/.exec(transform);
            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 geo.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 geo.Arc([
                    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 drawing.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 = parseFloat(val) + '';
            switch (style) {
            case 'decimal-leading-zero':
                if (str.length < 2) {
                    str = '0' + str;
                }
                return str;
            case 'lower-roman':
                return romanNumeral(val).toLowerCase();
            case 'upper-roman':
                return romanNumeral(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);
                if (style.content && style.content != 'normal' && style.content != 'none' && style.width != '0px') {
                    var psel = element.ownerDocument.createElement(KENDO_PSEUDO_ELEMENT);
                    psel.style.cssText = getCssText(style);
                    psel.textContent = evalPseudoElementContent(element, style.content);
                    element.insertBefore(psel, place);
                    fake.push(psel);
                }
            }
            pseudo(':before', element.firstChild);
            pseudo(':after', null);
            var saveClass = element.className;
            element.className += ' kendo-pdf-hide-pseudo-elements';
            _renderElement(element, group);
            element.className = saveClass;
            fake.forEach(function (el) {
                element.removeChild(el);
            });
        }
        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(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'));
            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 drawing.Group();
                    var clipPath = new drawing.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 (boxes.length > 0 && display == 'list-item') {
                drawBullet(boxes[0]);
            }
            (function () {
                function clipit() {
                    var clipPath = elementRoundBox(element, innerbox, 'padding');
                    var tmp = new drawing.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);
            }
            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.call(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) {
                if (Wtop <= 0) {
                    return;
                }
                var path, edge = new drawing.Group();
                setTransform(edge, transform);
                group.append(edge);
                sanitizeRadius(rl);
                sanitizeRadius(rr);
                path = new drawing.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) {
                    var angle = Math.PI / 2 * Wright / (Wright + Wtop);
                    var ri = {
                        x: r.x - Wright,
                        y: r.y - Wtop
                    };
                    var path = new drawing.Path({
                        fill: { color: color },
                        stroke: null
                    }).moveTo(0, 0);
                    setTransform(path, transform);
                    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 drawing.Group();
                setClipping(background, roundBox(box, rTL0, rTR0, rBR0, rBL0));
                group.append(background);
                if (element.tagName == 'A' && element.href && !/^#?$/.test($(element).attr('href'))) {
                    if (!nodeInfo._avoidLinks || !$(element).is(nodeInfo._avoidLinks)) {
                        background._pdfLink = {
                            url: element.href,
                            top: box.top,
                            right: box.right,
                            bottom: box.bottom,
                            left: box.left
                        };
                    }
                }
                if (backgroundColor) {
                    var path = new drawing.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 drawing.Image(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 = (backgroundPosition + '').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 geo.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 + '').length < 2) {
                                idx = '0' + idx;
                            }
                            bullet.innerHTML = idx + '.';
                        });
                    });
                    break;
                case 'lower-roman':
                case 'upper-roman':
                    _drawBullet(function (bullet) {
                        elementIndex(function (idx) {
                            idx = romanNumeral(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 (true) {
                    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 drawing.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 drawing.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 drawing.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 drawing.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(drawing.Path.fromRect(rect).stroke(null).fill(new drawing.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) {
            if (element.getAttribute(kendo.attr('role'))) {
                var widget = kendo.widgetInstance($(element));
                if (widget && (widget.exportDOMVisual || widget.exportVisual)) {
                    var visual;
                    if (widget.exportDOMVisual) {
                        visual = widget.exportDOMVisual();
                    } else {
                        visual = widget.exportVisual();
                    }
                    if (!visual) {
                        return false;
                    }
                    var wrap = new drawing.Group();
                    wrap.children.push(visual);
                    var bbox = element.getBoundingClientRect();
                    wrap.transform(geo.transform().translate(bbox.left, bbox.top));
                    group.append(wrap);
                    return true;
                }
            }
        }
        function renderImage(element, url, group) {
            var box = getContentBox(element);
            var rect = new geo.Rect([
                box.left,
                box.top
            ], [
                box.width,
                box.height
            ]);
            var image = new drawing.Image(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(drawing.Path.fromRect(new geo.Rect([
                    box.left + 1,
                    box.top + 1
                ], [
                    box.width - 2,
                    box.height - 2
                ])).stroke(color, 1));
                if (element.checked) {
                    group.append(new drawing.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 drawing.Circle(new geo.Circle([
                    (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 drawing.Circle(new geo.Circle([
                        (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 blocks = [], floats = [], inline = [], 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 display = getPropertyValue(style, 'display');
                        var floating = getPropertyValue(style, 'float');
                        var position = getPropertyValue(style, 'position');
                        if (position != 'static') {
                            positioned.push(i);
                        } else if (display != 'inline') {
                            if (floating != 'none') {
                                floats.push(i);
                            } else {
                                blocks.push(i);
                            }
                        } else {
                            inline.push(i);
                        }
                        break;
                    }
                }
                mergeSort(blocks, zIndexSort).forEach(function (el) {
                    renderElement(el, group);
                });
                mergeSort(floats, zIndexSort).forEach(function (el) {
                    renderElement(el, group);
                });
                mergeSort(inline, 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 = getPropertyValue(style, 'text-align');
            var isJustified = align == 'justify';
            var whiteSpace = getPropertyValue(style, 'white-space');
            var textOverflow, saveTextOverflow;
            if (browser.msie) {
                textOverflow = style.textOverflow;
                if (textOverflow == 'ellipsis') {
                    saveTextOverflow = element.style.textOverflow;
                    element.style.textOverflow = 'clip';
                }
            }
            var estimateLineLength = element.getBoundingClientRect().width / fontSize * 5;
            if (estimateLineLength === 0) {
                estimateLineLength = 500;
            }
            var prevLineBottom = null;
            while (!doChunk()) {
            }
            if (browser.msie && textOverflow == 'ellipsis') {
                element.style.textOverflow = saveTextOverflow;
            }
            return;
            function actuallyGetRangeBoundingRect(range) {
                if (browser.msie || browser.chrome) {
                    var rectangles = range.getClientRects(), box = {
                            top: +Infinity,
                            right: -Infinity,
                            bottom: -Infinity,
                            left: +Infinity
                        };
                    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);
                    }
                    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) {
                    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;
                    }
                    if (pos > 0) {
                        range.setEnd(node, range.startOffset + pos);
                        box = actuallyGetRangeBoundingRect(range);
                    }
                }
                if (browser.msie) {
                    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 (browser.msie && !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
                    };
                }
                var text = new TextRect(str, new geo.Rect([
                    box.left,
                    box.top
                ], [
                    box.width,
                    box.height
                ]), {
                    font: font,
                    fill: { color: color }
                });
                group.append(text);
                decorate(box);
            }
            function decorate(box) {
                line(nodeInfo['underline'], box.bottom);
                line(nodeInfo['line-through'], box.bottom - box.height / 2.7);
                line(nodeInfo['overline'], box.top);
                function line(color, ypos) {
                    if (color) {
                        var width = fontSize / 12;
                        var path = new drawing.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 drawing.Group();
            main.insertAt(tmp, i);
            tmp._dom_zIndex = zIndex;
            if (main !== group) {
                if (nodeInfo._clipbox) {
                    var m = nodeInfo._matrix.invert();
                    var r = nodeInfo._clipbox.transformCopy(m);
                    setClipping(tmp, drawing.Path.fromRect(r));
                }
            }
            return tmp;
        }
        function renderElement(element, container) {
            var style = getComputedStyle(element);
            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);
            }
            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
            ];
        }
    }(window.kendo.jQuery, parseFloat, Math));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/animation', [
        'drawing/geometry',
        'drawing/core'
    ], f);
}(function () {
    (function ($) {
        var noop = $.noop, kendo = window.kendo, Class = kendo.Class, util = kendo.util, animationFrame = kendo.animationFrame, deepExtend = kendo.deepExtend;
        var Animation = Class.extend({
            init: function (element, options) {
                var anim = this;
                anim.options = deepExtend({}, anim.options, options);
                anim.element = element;
            },
            options: {
                duration: 500,
                easing: 'swing'
            },
            setup: noop,
            step: noop,
            play: function () {
                var anim = this, options = anim.options, easing = $.easing[options.easing], duration = options.duration, delay = options.delay || 0, start = util.now() + delay, finish = start + duration;
                if (duration === 0) {
                    anim.step(1);
                    anim.abort();
                } else {
                    setTimeout(function () {
                        var loop = function () {
                            if (anim._stopped) {
                                return;
                            }
                            var wallTime = util.now();
                            var time = util.limitValue(wallTime - start, 0, duration);
                            var pos = time / duration;
                            var easingPos = easing(pos, time, 0, 1, duration);
                            anim.step(easingPos);
                            if (wallTime < finish) {
                                animationFrame(loop);
                            } else {
                                anim.abort();
                            }
                        };
                        loop();
                    }, delay);
                }
            },
            abort: function () {
                this._stopped = true;
            },
            destroy: function () {
                this.abort();
            }
        });
        var AnimationFactory = function () {
            this._items = [];
        };
        AnimationFactory.prototype = {
            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();
        Animation.create = function (type, element, options) {
            return AnimationFactory.current.create(type, element, options);
        };
        deepExtend(kendo.drawing, {
            Animation: Animation,
            AnimationFactory: AnimationFactory
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.drawing', [
        'kendo.color',
        'util/main',
        'util/text-metrics',
        'util/base64',
        'mixins/observers',
        'drawing/geometry',
        'drawing/core',
        'drawing/mixins',
        'drawing/shapes',
        'drawing/parser',
        'drawing/search',
        'drawing/svg',
        'drawing/canvas',
        'drawing/vml',
        'drawing/html',
        'drawing/animation'
    ], 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)();
}));
/** 
 * Kendo UI v2016.3.1118 (http://www.telerik.com/kendo-ui)                                                                                                                                              
 * Copyright 2016 Telerik AD. 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('util/main', ['kendo.core'], f);
}(function () {
    (function () {
        var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend;
        var DEG_TO_RAD = math.PI / 180, MAX_NUM = Number.MAX_VALUE, MIN_NUM = -Number.MAX_VALUE, UNDEFINED = 'undefined';
        function defined(value) {
            return typeof value !== UNDEFINED;
        }
        function round(value, precision) {
            var power = pow(precision);
            return math.round(value * power) / power;
        }
        function pow(p) {
            if (p) {
                return math.pow(10, p);
            } else {
                return 1;
            }
        }
        function limitValue(value, min, max) {
            return math.max(math.min(value, max), min);
        }
        function rad(degrees) {
            return degrees * DEG_TO_RAD;
        }
        function deg(radians) {
            return radians / DEG_TO_RAD;
        }
        function isNumber(val) {
            return typeof val === 'number' && !isNaN(val);
        }
        function valueOrDefault(value, defaultValue) {
            return defined(value) ? value : defaultValue;
        }
        function sqr(value) {
            return value * value;
        }
        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 hashObject(object) {
            return hashKey(objectKey(object));
        }
        var now = Date.now;
        if (!now) {
            now = function () {
                return new Date().getTime();
            };
        }
        function arrayLimits(arr) {
            var length = arr.length, i, min = MAX_NUM, max = MIN_NUM;
            for (i = 0; i < length; i++) {
                max = math.max(max, arr[i]);
                min = math.min(min, arr[i]);
            }
            return {
                min: min,
                max: max
            };
        }
        function arrayMin(arr) {
            return arrayLimits(arr).min;
        }
        function arrayMax(arr) {
            return arrayLimits(arr).max;
        }
        function sparseArrayMin(arr) {
            return sparseArrayLimits(arr).min;
        }
        function sparseArrayMax(arr) {
            return sparseArrayLimits(arr).max;
        }
        function sparseArrayLimits(arr) {
            var min = MAX_NUM, max = MIN_NUM;
            for (var i = 0, length = arr.length; i < length; i++) {
                var n = arr[i];
                if (n !== null && isFinite(n)) {
                    min = math.min(min, n);
                    max = math.max(max, n);
                }
            }
            return {
                min: min === MAX_NUM ? undefined : min,
                max: max === MIN_NUM ? undefined : max
            };
        }
        function last(array) {
            if (array) {
                return array[array.length - 1];
            }
        }
        function append(first, second) {
            first.push.apply(first, second);
            return first;
        }
        function renderTemplate(text) {
            return kendo.template(text, {
                useWithBlock: false,
                paramName: 'd'
            });
        }
        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;
            }
        }
        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 isTransparent(color) {
            return color === '' || color === null || color === 'none' || color === 'transparent' || !defined(color);
        }
        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 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 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);
        }
        deepExtend(kendo, {
            util: {
                MAX_NUM: MAX_NUM,
                MIN_NUM: MIN_NUM,
                append: append,
                arrayLimits: arrayLimits,
                arrayMin: arrayMin,
                arrayMax: arrayMax,
                defined: defined,
                deg: deg,
                hashKey: hashKey,
                hashObject: hashObject,
                isNumber: isNumber,
                isTransparent: isTransparent,
                last: last,
                limitValue: limitValue,
                now: now,
                objectKey: objectKey,
                round: round,
                rad: rad,
                renderAttr: renderAttr,
                renderAllAttr: renderAllAttr,
                renderPos: renderPos,
                renderSize: renderSize,
                renderStyle: renderStyle,
                renderTemplate: renderTemplate,
                sparseArrayLimits: sparseArrayLimits,
                sparseArrayMin: sparseArrayMin,
                sparseArrayMax: sparseArrayMax,
                sqr: sqr,
                valueOrDefault: valueOrDefault,
                romanToArabic: romanToArabic,
                arabicToRoman: arabicToRoman,
                memoize: memoize,
                ucs2encode: ucs2encode,
                ucs2decode: ucs2decode,
                mergeSort: mergeSort
            }
        });
        kendo.drawing.util = kendo.util;
        kendo.dataviz.util = kendo.util;
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf/core', [
        'kendo.core',
        'util/main'
    ], f);
}(function () {
    (function (window, parseFloat, undefined) {
        'use strict';
        var kendo = window.kendo;
        var HAS_TYPED_ARRAYS = !!window.Uint8Array;
        var NL = '\n';
        var RESOURCE_COUNTER = 0;
        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;
                }
            };
        }();
        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() {
                for (var i = 0; i < arguments.length; ++i) {
                    var x = arguments[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(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());
            catalog.setPages(pageTree);
            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: new PDFDictionary({
                        Producer: new PDFString(getOption('producer', 'Kendo UI PDF Generator v.' + kendo.version)),
                        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 v.' + kendo.version)),
                        CreationDate: getOption('date', new Date())
                    })
                }), 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) {
            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 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 kendo.pdf.TTFFont(data);
                        FONT_CACHE[url] = font;
                        cont(font);
                    }
                });
            }
        }
        var IMAGE_CACHE = {};
        function loadImage(url, 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 && !kendo.support.browser.msie) {
                    _onload();
                } else {
                    img.onload = _onload;
                    img.onerror = _onerror;
                }
            }
            function _onerror() {
                cont(IMAGE_CACHE[url] = 'TAINTED');
            }
            function _onload() {
                if (blob && /^image\/jpe?g$/i.test(blob.type)) {
                    var reader = new FileReader();
                    reader.onload = function () {
                        img = new PDFJpegImage(img.width, img.height, BinaryStream(new Uint8Array(this.result)));
                        URL.revokeObjectURL(bloburl);
                        cont(IMAGE_CACHE[url] = img);
                    };
                    reader.readAsArrayBuffer(blob);
                    return;
                }
                var canvas = document.createElement('canvas');
                canvas.width = img.width;
                canvas.height = img.height;
                var ctx = canvas.getContext('2d');
                ctx.drawImage(img, 0, 0);
                var imgdata;
                try {
                    imgdata = ctx.getImageData(0, 0, img.width, img.height);
                } catch (ex) {
                    return _onerror();
                } 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(img.width, img.height, rgb, alpha);
                } else {
                    var data = canvas.toDataURL('image/jpeg');
                    data = data.substr(data.indexOf(';base64,') + 8);
                    var stream = BinaryStream();
                    stream.writeBase64(data);
                    stream.offset(0);
                    img = new PDFJpegImage(img.width, img.height, stream);
                }
                cont(IMAGE_CACHE[url] = img);
            }
        }
        function manyLoader(loadOne) {
            return function (urls, callback) {
                var n = urls.length, i = n;
                if (n === 0) {
                    return callback();
                }
                while (i-- > 0) {
                    loadOne(urls[i], function () {
                        if (--n === 0) {
                            callback();
                        }
                    });
                }
            };
        }
        var loadFonts = manyLoader(loadFont);
        var loadImages = manyLoader(loadImage);
        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 === 'TAINTED') {
                        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(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 = '', esc = this.escape();
                for (var i = 0; i < esc.length; ++i) {
                    txt += String.fromCharCode(esc.charCodeAt(i) & 255);
                }
                out('(', txt, ')');
            },
            escape: function () {
                return this.value.replace(/([\(\)\\])/g, '\\$1');
            },
            toString: function () {
                return this.value;
            }
        });
        var PDFHexString = defclass(function PDFHexString(value) {
            this.value = value;
        }, {
            render: function (out) {
                out('<');
                for (var i = 0; i < this.value.length; ++i) {
                    out(zeropad(this.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 && window.pako && typeof window.pako.deflate == 'function') {
                    if (!props.Filter) {
                        props.Filter = [];
                    } else if (!(props.Filter instanceof Array)) {
                        props.Filter = [props.Filter];
                    }
                    props.Filter.unshift(_('FlateDecode'));
                    data = window.pako.deflate(data);
                }
                props.Length = data.length;
                out(new PDFDictionary(props), ' stream', NL);
                out.writeData(data);
                out(NL, 'endstream');
            }
        });
        var PDFCatalog = defclass(function PDFCatalog(props) {
            props = this.props = props || {};
            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);
        function PDFJpegImage(width, height, data) {
            this.asStream = function () {
                var stream = new PDFStream(data, {
                    Type: _('XObject'),
                    Subtype: _('Image'),
                    Width: width,
                    Height: height,
                    BitsPerComponent: 8,
                    ColorSpace: _('DeviceRGB'),
                    Filter: _('DCTDecode')
                });
                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(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(text + ''));
            },
            getTextWidth: function (fontSize, text) {
                var width = 0, codeMap = this._font.cmap.codeMap;
                for (var i = 0; i < text.length; ++i) {
                    var glyphId = codeMap[text.charCodeAt(i)];
                    width += this._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 = kendo.util.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 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 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;
                }
            }
        }
        kendo.pdf = {
            Document: PDFDocument,
            BinaryStream: BinaryStream,
            defineFont: defineFont,
            parseFontDef: parseFontDef,
            getFontURL: getFontURL,
            loadFonts: loadFonts,
            loadImages: loadImages,
            getPaperOptions: getPaperOptions,
            TEXT_RENDERING_MODE: {
                fill: 0,
                stroke: 1,
                fillAndStroke: 2,
                invisible: 3,
                fillAndClip: 4,
                strokeAndClip: 5,
                fillStrokeClip: 6,
                clip: 7
            }
        };
        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;
        }
    }(window, parseFloat));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf/ttf', [
        'pdf/core',
        'util/main'
    ], f);
}(function () {
    (function (window) {
        'use strict';
        function hasOwnProperty(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);
        }
        var PDF = window.kendo.pdf;
        var BinaryStream = PDF.BinaryStream;
        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 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(tables, tag)) {
                        var table = tables[tag];
                        out.writeString(tag);
                        out.writeLong(this.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(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 out = BinaryStream();
                for (var i = 0; i < glyphIds.length; ++i) {
                    var m = this.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 out = BinaryStream(this.raw.get());
                    for (var i = 0; i < this.glyphIds.length; ++i) {
                        var id = this.glyphIds[i];
                        out.offset(this.idOffsets[i]);
                        out.writeShort(old2new[id]);
                    }
                    return out.get();
                }
            };
            return deftable({
                parse: function () {
                    this.cache = {};
                },
                glyphFor: function (id) {
                    var cache = this.cache;
                    if (hasOwnProperty(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 strings = this.strings;
                    var strCount = 0;
                    for (var i in strings) {
                        if (hasOwnProperty(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(strings, i)) {
                            var list = i == 6 ? [new NameEntry(psName, this.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) {
                    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.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) {
                    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.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 = 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 kendo.util.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) {
                if (!result) {
                    result = {};
                }
                for (var i = 0; i < glyphIds.length; ++i) {
                    var id = glyphIds[i];
                    if (!result[id]) {
                        var glyph = result[id] = this.font.glyf.glyphFor(id);
                        if (glyph && glyph.compound) {
                            this.glyphsFor(glyph.glyphIds, result);
                        }
                    }
                }
                return result;
            },
            render: function () {
                var glyphs = this.glyphsFor(this.glyphIds());
                for (var old_gid in glyphs) {
                    if (hasOwnProperty(glyphs, old_gid)) {
                        old_gid = parseInt(old_gid, 10);
                        if (this.ogid2ngid[old_gid] == null) {
                            var new_gid = this.nextGid++;
                            this.ogid2ngid[old_gid] = new_gid;
                            this.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 out = BinaryStream(), len = 0;
                for (var cid = this.firstChar; cid < this.next; ++cid) {
                    while (len < cid) {
                        out.writeShort(0);
                        len++;
                    }
                    var old_gid = this.ncid2ogid[cid];
                    if (old_gid) {
                        var new_gid = this.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') {
                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) {
                    var offset = data.readLong();
                    data.saveExcursion(function () {
                        data.offset(offset);
                        self.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);
            }
        };
        PDF.TTFFont = TTFFont;
    }(window));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/text-metrics', [
        'kendo.core',
        'util/main'
    ], f);
}(function () {
    (function ($) {
        var doc = document, kendo = window.kendo, Class = kendo.Class, util = kendo.util, defined = util.defined;
        var LRUCache = Class.extend({
            init: function (size) {
                this._size = size;
                this._length = 0;
                this._map = {};
            },
            put: function (key, value) {
                var lru = this, map = lru._map, entry = {
                        key: key,
                        value: value
                    };
                map[key] = entry;
                if (!lru._head) {
                    lru._head = lru._tail = entry;
                } else {
                    lru._tail.newer = entry;
                    entry.older = lru._tail;
                    lru._tail = entry;
                }
                if (lru._length >= lru._size) {
                    map[lru._head.key] = null;
                    lru._head = lru._head.newer;
                    lru._head.older = null;
                } else {
                    lru._length++;
                }
            },
            get: function (key) {
                var lru = this, entry = lru._map[key];
                if (entry) {
                    if (entry === lru._head && entry !== lru._tail) {
                        lru._head = entry.newer;
                        lru._head.older = null;
                    }
                    if (entry !== lru._tail) {
                        if (entry.older) {
                            entry.older.newer = entry.newer;
                            entry.newer.older = entry.older;
                        }
                        entry.older = lru._tail;
                        entry.newer = null;
                        lru._tail.newer = entry;
                        lru._tail = entry;
                    }
                    return entry.value;
                }
            }
        });
        var defaultMeasureBox = $('<div style=\'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: nowrap!important;\' />')[0];
        function zeroSize() {
            return {
                width: 0,
                height: 0,
                baseline: 0
            };
        }
        var TextMetrics = Class.extend({
            init: function (options) {
                this._cache = new LRUCache(1000);
                this._initOptions(options);
            },
            options: { baselineMarkerSize: 1 },
            measure: function (text, style, box) {
                if (!text) {
                    return zeroSize();
                }
                var styleKey = util.objectKey(style), cacheKey = util.hashKey(text + styleKey), cachedResult = this._cache.get(cacheKey);
                if (cachedResult) {
                    return cachedResult;
                }
                var size = zeroSize();
                var measureBox = box ? box : defaultMeasureBox;
                var baselineMarker = this._baselineMarker().cloneNode(false);
                for (var key in style) {
                    var value = style[key];
                    if (defined(value)) {
                        measureBox.style[key] = value;
                    }
                }
                $(measureBox).text(text);
                measureBox.appendChild(baselineMarker);
                doc.body.appendChild(measureBox);
                if ((text + '').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 () {
                return $('<div class=\'k-baseline-marker\' ' + 'style=\'display: inline-block; vertical-align: baseline;' + 'width: ' + this.options.baselineMarkerSize + 'px; height: ' + this.options.baselineMarkerSize + 'px;' + 'overflow: hidden;\' />')[0];
            }
        });
        TextMetrics.current = new TextMetrics();
        function measureText(text, style, measureBox) {
            return TextMetrics.current.measure(text, style, measureBox);
        }
        function loadFonts(fonts, callback) {
            var promises = [];
            if (fonts.length > 0 && document.fonts) {
                try {
                    promises = fonts.map(function (font) {
                        return document.fonts.load(font);
                    });
                } catch (e) {
                    kendo.logToConsole(e);
                }
                Promise.all(promises).then(callback, callback);
            } else {
                callback();
            }
        }
        kendo.util.TextMetrics = TextMetrics;
        kendo.util.LRUCache = LRUCache;
        kendo.util.loadFonts = loadFonts;
        kendo.util.measureText = measureText;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/base64', ['util/main'], f);
}(function () {
    (function () {
        var kendo = window.kendo, deepExtend = kendo.deepExtend, fromCharCode = String.fromCharCode;
        var KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        function encodeBase64(input) {
            var output = '';
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;
            input = encodeUTF8(input);
            while (i < input.length) {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);
                enc1 = chr1 >> 2;
                enc2 = (chr1 & 3) << 4 | chr2 >> 4;
                enc3 = (chr2 & 15) << 2 | chr3 >> 6;
                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 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;
        }
        deepExtend(kendo.util, {
            encodeBase64: encodeBase64,
            encodeUTF8: encodeUTF8
        });
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('mixins/observers', ['kendo.core'], f);
}(function () {
    (function ($) {
        var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend, inArray = $.inArray;
        var ObserversMixin = {
            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 = inArray(element, observers);
                if (index != -1) {
                    observers.splice(index, 1);
                }
                return this;
            },
            trigger: function (methodName, event) {
                var observers = this._observers;
                var observer;
                var idx;
                if (observers && !this._suspended) {
                    for (idx = 0; idx < observers.length; idx++) {
                        observer = observers[idx];
                        if (observer[methodName]) {
                            observer[methodName](event);
                        }
                    }
                }
                return this;
            },
            optionsChange: function (e) {
                e = 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);
            }
        };
        deepExtend(kendo, { mixins: { ObserversMixin: ObserversMixin } });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf/drawing', [
        'kendo.core',
        'kendo.color',
        'kendo.drawing',
        'pdf/core'
    ], f);
}(function () {
    (function (kendo, $) {
        'use strict';
        var drawing = kendo.drawing;
        var geo = kendo.geometry;
        var TEXT_RENDERING_MODE = kendo.pdf.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');
            group.traverse(function (element) {
                dispatch({
                    Image: function (element) {
                        if (images.indexOf(element.src()) < 0) {
                            images.push(element.src());
                        }
                    },
                    Text: function (element) {
                        var style = kendo.pdf.parseFontDef(element.options.font);
                        var url = kendo.pdf.getFontURL(style);
                        if (fonts.indexOf(url) < 0) {
                            fonts.push(url);
                        }
                    }
                }, element);
            });
            function doIt() {
                if (--count > 0) {
                    return;
                }
                var pdf = new kendo.pdf.Document({
                    producer: getOption('producer'),
                    title: getOption('title'),
                    author: getOption('author'),
                    subject: getOption('subject'),
                    keywords: getOption('keywords'),
                    creator: getOption('creator'),
                    date: getOption('date')
                });
                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 geo.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;
            kendo.pdf.loadFonts(fonts, doIt);
            kendo.pdf.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 Blob([data.get()], { type: 'application/pdf' }));
            });
        }
        function saveAs(group, filename, proxy, callback) {
            if (window.Blob && !kendo.support.browser.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(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(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(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 = kendo.pdf.parseFontDef(element.options.font);
            var pos = element._position;
            var mode;
            if (element.fill() && element.stroke()) {
                mode = TEXT_RENDERING_MODE.fillAndStroke;
            } else if (element.fill()) {
                mode = TEXT_RENDERING_MODE.fill;
            } else if (element.stroke()) {
                mode = TEXT_RENDERING_MODE.stroke;
            }
            page.transform(1, 0, 0, -1, pos.x, pos.y + style.fontSize);
            page.beginText();
            page.setFont(kendo.pdf.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 exportPDF(group, options) {
            var defer = $.Deferred();
            for (var i in options) {
                if (i == 'margin' && group.options.pdf && group.options.pdf._ignoreMargin) {
                    continue;
                }
                group.options.set('pdf.' + i, options[i]);
            }
            drawing.pdf.toDataURL(group, defer.resolve);
            return defer.promise();
        }
        function parseColor(x) {
            var color = kendo.parseColor(x, true);
            return color ? color.toRGB() : null;
        }
        function optimize(root) {
            var clipbox = false;
            var matrix = geo.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 ? geo.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 = geo.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 ? geo.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);
                });
            }
        }
        kendo.deepExtend(drawing, {
            exportPDF: exportPDF,
            pdf: {
                toDataURL: toDataURL,
                toBlob: toBlob,
                saveAs: saveAs,
                toStream: render
            }
        });
    }(window.kendo, window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pdf', [
        'kendo.core',
        'pdf/core',
        'pdf/ttf',
        'pdf/drawing',
        'kendo.drawing'
    ], f);
}(function () {
    var __meta__ = {
        id: 'pdf',
        name: 'PDF export',
        description: 'PDF Generation framework',
        mixin: true,
        category: 'framework',
        depends: [
            'core',
            'drawing'
        ]
    };
    (function (kendo, $) {
        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();
            }
        };
    }(kendo, window.kendo.jQuery));
    return kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
/** 
 * Kendo UI v2016.3.1118 (http://www.telerik.com/kendo-ui)                                                                                                                                              
 * Copyright 2016 Telerik AD. 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('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('util/main', ['kendo.core'], f);
}(function () {
    (function () {
        var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend;
        var DEG_TO_RAD = math.PI / 180, MAX_NUM = Number.MAX_VALUE, MIN_NUM = -Number.MAX_VALUE, UNDEFINED = 'undefined';
        function defined(value) {
            return typeof value !== UNDEFINED;
        }
        function round(value, precision) {
            var power = pow(precision);
            return math.round(value * power) / power;
        }
        function pow(p) {
            if (p) {
                return math.pow(10, p);
            } else {
                return 1;
            }
        }
        function limitValue(value, min, max) {
            return math.max(math.min(value, max), min);
        }
        function rad(degrees) {
            return degrees * DEG_TO_RAD;
        }
        function deg(radians) {
            return radians / DEG_TO_RAD;
        }
        function isNumber(val) {
            return typeof val === 'number' && !isNaN(val);
        }
        function valueOrDefault(value, defaultValue) {
            return defined(value) ? value : defaultValue;
        }
        function sqr(value) {
            return value * value;
        }
        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 hashObject(object) {
            return hashKey(objectKey(object));
        }
        var now = Date.now;
        if (!now) {
            now = function () {
                return new Date().getTime();
            };
        }
        function arrayLimits(arr) {
            var length = arr.length, i, min = MAX_NUM, max = MIN_NUM;
            for (i = 0; i < length; i++) {
                max = math.max(max, arr[i]);
                min = math.min(min, arr[i]);
            }
            return {
                min: min,
                max: max
            };
        }
        function arrayMin(arr) {
            return arrayLimits(arr).min;
        }
        function arrayMax(arr) {
            return arrayLimits(arr).max;
        }
        function sparseArrayMin(arr) {
            return sparseArrayLimits(arr).min;
        }
        function sparseArrayMax(arr) {
            return sparseArrayLimits(arr).max;
        }
        function sparseArrayLimits(arr) {
            var min = MAX_NUM, max = MIN_NUM;
            for (var i = 0, length = arr.length; i < length; i++) {
                var n = arr[i];
                if (n !== null && isFinite(n)) {
                    min = math.min(min, n);
                    max = math.max(max, n);
                }
            }
            return {
                min: min === MAX_NUM ? undefined : min,
                max: max === MIN_NUM ? undefined : max
            };
        }
        function last(array) {
            if (array) {
                return array[array.length - 1];
            }
        }
        function append(first, second) {
            first.push.apply(first, second);
            return first;
        }
        function renderTemplate(text) {
            return kendo.template(text, {
                useWithBlock: false,
                paramName: 'd'
            });
        }
        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;
            }
        }
        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 isTransparent(color) {
            return color === '' || color === null || color === 'none' || color === 'transparent' || !defined(color);
        }
        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 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 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);
        }
        deepExtend(kendo, {
            util: {
                MAX_NUM: MAX_NUM,
                MIN_NUM: MIN_NUM,
                append: append,
                arrayLimits: arrayLimits,
                arrayMin: arrayMin,
                arrayMax: arrayMax,
                defined: defined,
                deg: deg,
                hashKey: hashKey,
                hashObject: hashObject,
                isNumber: isNumber,
                isTransparent: isTransparent,
                last: last,
                limitValue: limitValue,
                now: now,
                objectKey: objectKey,
                round: round,
                rad: rad,
                renderAttr: renderAttr,
                renderAllAttr: renderAllAttr,
                renderPos: renderPos,
                renderSize: renderSize,
                renderStyle: renderStyle,
                renderTemplate: renderTemplate,
                sparseArrayLimits: sparseArrayLimits,
                sparseArrayMin: sparseArrayMin,
                sparseArrayMax: sparseArrayMax,
                sqr: sqr,
                valueOrDefault: valueOrDefault,
                romanToArabic: romanToArabic,
                arabicToRoman: arabicToRoman,
                memoize: memoize,
                ucs2encode: ucs2encode,
                ucs2decode: ucs2decode,
                mergeSort: mergeSort
            }
        });
        kendo.drawing.util = kendo.util;
        kendo.dataviz.util = kendo.util;
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/text-metrics', [
        'kendo.core',
        'util/main'
    ], f);
}(function () {
    (function ($) {
        var doc = document, kendo = window.kendo, Class = kendo.Class, util = kendo.util, defined = util.defined;
        var LRUCache = Class.extend({
            init: function (size) {
                this._size = size;
                this._length = 0;
                this._map = {};
            },
            put: function (key, value) {
                var lru = this, map = lru._map, entry = {
                        key: key,
                        value: value
                    };
                map[key] = entry;
                if (!lru._head) {
                    lru._head = lru._tail = entry;
                } else {
                    lru._tail.newer = entry;
                    entry.older = lru._tail;
                    lru._tail = entry;
                }
                if (lru._length >= lru._size) {
                    map[lru._head.key] = null;
                    lru._head = lru._head.newer;
                    lru._head.older = null;
                } else {
                    lru._length++;
                }
            },
            get: function (key) {
                var lru = this, entry = lru._map[key];
                if (entry) {
                    if (entry === lru._head && entry !== lru._tail) {
                        lru._head = entry.newer;
                        lru._head.older = null;
                    }
                    if (entry !== lru._tail) {
                        if (entry.older) {
                            entry.older.newer = entry.newer;
                            entry.newer.older = entry.older;
                        }
                        entry.older = lru._tail;
                        entry.newer = null;
                        lru._tail.newer = entry;
                        lru._tail = entry;
                    }
                    return entry.value;
                }
            }
        });
        var defaultMeasureBox = $('<div style=\'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: nowrap!important;\' />')[0];
        function zeroSize() {
            return {
                width: 0,
                height: 0,
                baseline: 0
            };
        }
        var TextMetrics = Class.extend({
            init: function (options) {
                this._cache = new LRUCache(1000);
                this._initOptions(options);
            },
            options: { baselineMarkerSize: 1 },
            measure: function (text, style, box) {
                if (!text) {
                    return zeroSize();
                }
                var styleKey = util.objectKey(style), cacheKey = util.hashKey(text + styleKey), cachedResult = this._cache.get(cacheKey);
                if (cachedResult) {
                    return cachedResult;
                }
                var size = zeroSize();
                var measureBox = box ? box : defaultMeasureBox;
                var baselineMarker = this._baselineMarker().cloneNode(false);
                for (var key in style) {
                    var value = style[key];
                    if (defined(value)) {
                        measureBox.style[key] = value;
                    }
                }
                $(measureBox).text(text);
                measureBox.appendChild(baselineMarker);
                doc.body.appendChild(measureBox);
                if ((text + '').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 () {
                return $('<div class=\'k-baseline-marker\' ' + 'style=\'display: inline-block; vertical-align: baseline;' + 'width: ' + this.options.baselineMarkerSize + 'px; height: ' + this.options.baselineMarkerSize + 'px;' + 'overflow: hidden;\' />')[0];
            }
        });
        TextMetrics.current = new TextMetrics();
        function measureText(text, style, measureBox) {
            return TextMetrics.current.measure(text, style, measureBox);
        }
        function loadFonts(fonts, callback) {
            var promises = [];
            if (fonts.length > 0 && document.fonts) {
                try {
                    promises = fonts.map(function (font) {
                        return document.fonts.load(font);
                    });
                } catch (e) {
                    kendo.logToConsole(e);
                }
                Promise.all(promises).then(callback, callback);
            } else {
                callback();
            }
        }
        kendo.util.TextMetrics = TextMetrics;
        kendo.util.LRUCache = LRUCache;
        kendo.util.loadFonts = loadFonts;
        kendo.util.measureText = measureText;
    }(window.kendo.jQuery));
}, 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('util/base64', ['util/main'], f);
}(function () {
    (function () {
        var kendo = window.kendo, deepExtend = kendo.deepExtend, fromCharCode = String.fromCharCode;
        var KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        function encodeBase64(input) {
            var output = '';
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;
            input = encodeUTF8(input);
            while (i < input.length) {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);
                enc1 = chr1 >> 2;
                enc2 = (chr1 & 3) << 4 | chr2 >> 4;
                enc3 = (chr2 & 15) << 2 | chr3 >> 6;
                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 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;
        }
        deepExtend(kendo.util, {
            encodeBase64: encodeBase64,
            encodeUTF8: encodeUTF8
        });
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('mixins/observers', ['kendo.core'], f);
}(function () {
    (function ($) {
        var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend, inArray = $.inArray;
        var ObserversMixin = {
            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 = inArray(element, observers);
                if (index != -1) {
                    observers.splice(index, 1);
                }
                return this;
            },
            trigger: function (methodName, event) {
                var observers = this._observers;
                var observer;
                var idx;
                if (observers && !this._suspended) {
                    for (idx = 0; idx < observers.length; idx++) {
                        observer = observers[idx];
                        if (observer[methodName]) {
                            observer[methodName](event);
                        }
                    }
                }
                return this;
            },
            optionsChange: function (e) {
                e = 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);
            }
        };
        deepExtend(kendo, { mixins: { ObserversMixin: ObserversMixin } });
    }(window.kendo.jQuery));
    return window.kendo;
}, 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 = 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.exec();
            },
            undo: function () {
                this.setState(this._state);
            },
            getState: function () {
                this._state = this.range().getState(this._property);
            },
            setState: function (state) {
                this.range().setState(state);
            },
            _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));
            }
        });
        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();
                range.link(this._link);
                if (range.value() == null) {
                    this._hasSetValue = true;
                    range.value(this._link);
                }
            },
            undo: function () {
                var range = this.range();
                range.link(this._prevLink);
                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();
                    range[this._property](this._value);
                }
            }
        });
        kendo.spreadsheet.ClearContentCommand = Command.extend({
            exec: function () {
                this.getState();
                this.range().clearContent();
            }
        });
        kendo.spreadsheet.EditCommand = PropertyChangeCommand.extend({
            init: function (options) {
                options.property = options.property || 'input';
                PropertyChangeCommand.fn.init.call(this, options);
            },
            rejectState: function (validationState) {
                this.undo();
                return {
                    title: validationState.title,
                    body: validationState.message,
                    reason: 'error',
                    type: 'validationError'
                };
            },
            getState: function () {
                this._state = this.range().getState();
            },
            exec: function () {
                var range = this.range();
                if (!range.enable()) {
                    return {
                        reason: 'error',
                        type: 'rangeDisabled'
                    };
                }
                var value = this._value;
                this.getState();
                if (this._property == 'value') {
                    range.value(value);
                    return;
                }
                try {
                    range.link(null);
                    if (value === '') {
                        range.value(null);
                    } else {
                        range.input(value);
                        if (/\n/.test(range.value())) {
                            range.wrap(true);
                        }
                    }
                    range._adjustRowHeight();
                    var validationState = range._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.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._decimals = options.value;
                options.property = 'format';
                Command.fn.init.call(this, options);
            },
            exec: function () {
                var sheet = this.range().sheet();
                var decimals = this._decimals;
                var formatting = kendo.spreadsheet.formatting;
                this.getState();
                sheet.batch(function () {
                    this.range().forEachCell(function (row, col, cell) {
                        var format = cell.format;
                        if (format || decimals > 0) {
                            format = formatting.adjustDecimals(format || '#', decimals);
                            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;
            },
            exec: function () {
                this.getState();
                this[this._type](this._style);
            },
            noBorders: function () {
                var range = this.range();
                range.sheet().batch(function () {
                    range.borderLeft(null).borderTop(null).borderRight(null).borderBottom(null);
                }.bind(this), {});
            },
            allBorders: function (style) {
                var range = this.range();
                range.sheet().batch(function () {
                    range.borderLeft(style).borderTop(style).borderRight(style).borderBottom(style);
                }.bind(this), {});
            },
            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.sheet().batch(function () {
                    range.leftColumn().borderLeft(style);
                    range.topRow().borderTop(style);
                    range.rightColumn().borderRight(style);
                    range.bottomRow().borderBottom(style);
                }.bind(this), {});
            },
            insideBorders: function (style) {
                this.range().sheet().batch(function () {
                    this.allBorders(style);
                    this.outsideBorders(null);
                }.bind(this), {});
            },
            insideHorizontalBorders: function (style) {
                var range = this.range();
                range.sheet().batch(function () {
                    range.borderBottom(style);
                    range.bottomRow().borderBottom(null);
                }.bind(this), {});
            },
            insideVerticalBorders: function (style) {
                var range = this.range();
                range.sheet().batch(function () {
                    range.borderRight(style);
                    range.rightColumn().borderRight(null);
                }.bind(this), {});
            }
        });
        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 = this._workbook.clipboard();
            },
            getState: function () {
                this._range = this._workbook.activeSheet().range(this._clipboard.pasteRef());
                this._state = this._range.getState();
            },
            exec: function () {
                var status = this._clipboard.canPaste();
                this._clipboard.menuInvoked = true;
                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'
                        };
                    }
                    return { reason: 'error' };
                }
                this.getState();
                this._clipboard.paste();
                var range = this._workbook.activeSheet().range(this._clipboard.pasteRef());
                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.CopyCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._clipboard = options.workbook.clipboard();
            },
            undo: $.noop,
            exec: function () {
                var status = this._clipboard.canCopy();
                this._clipboard.menuInvoked = true;
                if (!status.canCopy) {
                    if (status.menuInvoked) {
                        return {
                            reason: 'error',
                            type: 'useKeyboard'
                        };
                    } else if (status.multiSelection) {
                        return {
                            reason: 'error',
                            type: 'unsupportedSelection'
                        };
                    }
                    return;
                }
                this._clipboard.copy();
            }
        });
        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.CutCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._clipboard = options.workbook.clipboard();
            },
            exec: function () {
                if (this.range().enable() && this._clipboard.canCopy()) {
                    this.getState();
                    this._clipboard.cut();
                }
            }
        });
        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();
                if (!range.enable()) {
                    return {
                        reason: 'error',
                        type: 'rangeDisabled'
                    };
                }
                this.getState();
                try {
                    range.fillFrom(this._origin);
                } catch (ex) {
                    if (ex instanceof kendo.spreadsheet.Range.FillError) {
                        return {
                            reason: 'error',
                            type: ex.code
                        };
                    }
                    throw ex;
                }
            }
        });
        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();
                if (range.hasFilter()) {
                    range.filter(false);
                } else if (!range.intersectingMerged().length) {
                    range.filter(true);
                } else {
                    return {
                        reason: 'error',
                        type: 'filterRangeContainingMerges'
                    };
                }
            }
        });
        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();
                }
                if (!range.intersectingMerged().length) {
                    range.sort({
                        column: col,
                        ascending: ascending
                    });
                } else {
                    return {
                        reason: 'error',
                        type: 'sortRangeContainingMerges'
                    };
                }
            },
            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 = kendo.spreadsheet.DeleteCommand = Command.extend({
            undo: function () {
                var sheet = this.range().sheet();
                sheet.setState(this._state);
            }
        });
        kendo.spreadsheet.DeleteRowCommand = DeleteCommand.extend({
            exec: function () {
                var sheet = this.range().sheet();
                this._state = sheet.getState();
                sheet.axisManager().deleteSelectedRows();
            }
        });
        kendo.spreadsheet.DeleteColumnCommand = DeleteCommand.extend({
            exec: function () {
                var sheet = this.range().sheet();
                this._state = sheet.getState();
                sheet.axisManager().deleteSelectedColumns();
            }
        });
        var AddCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._value = options.value;
            },
            undo: function () {
                var sheet = this.range().sheet();
                sheet.setState(this._state);
            }
        });
        kendo.spreadsheet.AddColumnCommand = AddCommand.extend({
            exec: function () {
                var sheet = this.range().sheet();
                this._state = sheet.getState();
                if (this._value === 'left') {
                    sheet.axisManager().addColumnLeft();
                } else {
                    sheet.axisManager().addColumnRight();
                }
            }
        });
        kendo.spreadsheet.AddRowCommand = AddCommand.extend({
            exec: function () {
                var sheet = this.range().sheet();
                if (!sheet.axisManager().canAddRow()) {
                    return {
                        reason: 'error',
                        type: 'shiftingNonblankCells'
                    };
                }
                this._state = sheet.getState();
                if (this._value === 'above') {
                    sheet.axisManager().addRowAbove();
                } else {
                    sheet.axisManager().addRowBelow();
                }
            }
        });
        kendo.spreadsheet.EditValidationCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._value = options.value;
            },
            exec: function () {
                this.range().validation(this._value);
            }
        });
        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'
                    };
                }
                this.options.workbook.fromFile(this.options.file);
            }
        });
        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';
                }
                this.enableEditing(enable);
                this.element.toggleClass('k-state-disabled', !enable);
            },
            enableEditing: function (enable) {
                if (enable) {
                    this.element.attr('contenteditable', enable);
                } else {
                    this.element.removeAttr('contenteditable');
                }
            },
            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);
            },
            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 () {
                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;
            },
            _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.enableEditing(false);
                this.element.hide();
                this._cellTooltip.hide();
            },
            show: function () {
                this.enableEditing(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 (/^(?:ref|op|punc)$/.test(left.type)) {
                            return {
                                token: left,
                                end: point.end
                            };
                        }
                        if (/^(?:punc|op)$/.test(left.type)) {
                            return /^[,;({]$/.test(left.value) ? {
                                token: left,
                                end: point.end
                            } : null;
                        }
                    }
                    return false;
                }
            },
            refAtPoint: function (ref) {
                var x = this._canInsertRef();
                if (x) {
                    this._replaceAt(x, ref.simplify().toString());
                }
            },
            _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();
                this._sync();
            },
            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);
                }
            },
            _value: function (value) {
                this.element.text(value);
            },
            value: function (value) {
                if (value === undefined) {
                    var txt = this.element[0].innerText;
                    if (kendo.support.browser.mozilla) {
                        txt = txt.replace(/\n$/, '');
                    }
                    return txt;
                }
                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) {
                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.threshold = 5;
                this._pressLocation = null;
                target.on('keydown', this.keyDownProxy);
                target.on('contextmenu mousedown cut copy paste scroll wheel click dblclick focus', this.mouseProxy);
                $(document.documentElement).on('mousemove mouseup', this.mouseProxy);
                if (handlers) {
                    for (var key in handlers) {
                        this.on(key, handlers[key]);
                    }
                }
            },
            keyDown: function (e) {
                this.handleEvent(e, keyName(e.originalEvent));
            },
            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 passThrough(value) {
            return value;
        }
        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 > 0) {
                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 Value(start, end, value) {
                this.start = start;
                this.end = end;
                this.value = value;
            },
            intersects: function (range) {
                return range.start <= this.end && range.end >= this.start;
            }
        });
        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(passThrough);
            },
            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;
            }
        });
        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].end < index) {
                    this.index++;
                }
                return 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 $ = kendo.jQuery;
        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, validations) {
                Property.prototype.init.call(this, values);
                this.validations = validations;
                this.formats = formats;
            },
            set: function (start, end, value) {
                if (value instanceof Date) {
                    value = kendo.spreadsheet.dateToNumber(value);
                    this.formats.value(start, end, toExcelFormat(kendo.culture().calendar.patterns.d));
                }
                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: ValueProperty,
                    name: 'value',
                    value: null,
                    sortable: true,
                    serializable: true,
                    depends: 'format'
                },
                {
                    property: Property,
                    name: 'format',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'formula',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'background',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: JsonProperty,
                    name: 'borderBottom',
                    value: null,
                    sortable: false,
                    serializable: true
                },
                {
                    property: JsonProperty,
                    name: 'borderRight',
                    value: null,
                    sortable: false,
                    serializable: true
                },
                {
                    property: JsonProperty,
                    name: 'borderLeft',
                    value: null,
                    sortable: false,
                    serializable: true
                },
                {
                    property: JsonProperty,
                    name: 'borderTop',
                    value: null,
                    sortable: false,
                    serializable: true
                },
                {
                    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: '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: false,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'editor',
                    value: null,
                    sortable: false,
                    serializable: true
                }
            ],
            init: function (cellCount) {
                this.properties = {};
                this.lists = {};
                this.specs.forEach(function (spec) {
                    this.lists[spec.name] = new kendo.spreadsheet.SparseRangeList(0, cellCount, spec.value);
                }, this);
                this.specs.forEach(function (spec) {
                    this.properties[spec.name] = new spec.property(this.lists[spec.name], this.lists[spec.depends]);
                }, this);
            },
            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];
                }
                return this.properties[name].get(index);
            },
            set: function (name, start, end, value) {
                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);
                        }
                    }
                }
            },
            copy: function (sourceStart, sourceEnd, targetStart) {
                this.specs.forEach(function (spec) {
                    this.properties[spec.name].copy(sourceStart, sourceEnd, targetStart);
                }, this);
            },
            iterator: function (name, start, end) {
                return this.properties[name].iterator(start, end);
            },
            sortable: function () {
                return this.specs.filter(function (spec) {
                    return spec.sortable;
                }).map(function (spec) {
                    return this.lists[spec.name];
                }, this);
            },
            iterators: function (start, end) {
                var specs = this.specs.filter(function (spec) {
                    return spec.serializable;
                });
                return specs.map(function (spec) {
                    var iterator = this.iterator(spec.name, start, end);
                    return {
                        name: spec.name,
                        value: spec.value,
                        at: function (index) {
                            return spec.property.fn.parse(iterator.at(index));
                        }
                    };
                }, this);
            },
            forEach: function (start, end, callback) {
                var iterators = this.iterators(start, end);
                for (var index = start; index <= end; index++) {
                    var 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;
                        }
                    }
                    callback(values);
                }
            },
            forEachProperty: function (callback) {
                for (var name in this.properties) {
                    callback(this.properties[name]);
                }
            }
        });
        kendo.spreadsheet.ALL_PROPERTIES = $.map(kendo.spreadsheet.PropertyBag.prototype.specs, function (spec) {
            return spec.name;
        });
    }(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-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 (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;
        },
        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(callback, 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) {
            return new UnionRef(this.refs.map(callback, obj));
        },
        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;
                if (!sheet.select().contains(this.refForMode(ref, mode))) {
                    this.select(ref, mode);
                }
            },
            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 selection = sheet.currentNavigationRange();
                var selTopLeft = selection.topLeft;
                var selBottomRight = selection.bottomRight;
                var done = false;
                var topLeftCol = topLeft.col;
                var topLeftRow = topLeft.row;
                while (!done) {
                    var current = new CellRef(row, column);
                    switch (direction) {
                    case 'next':
                        if (selBottomRight.eq(current)) {
                            selection = sheet.nextNavigationRange();
                            row = selection.topLeft.row;
                            column = selection.topLeft.col;
                        } else {
                            column = columns.nextVisible(topLeftCol, true);
                            if (column > selBottomRight.col) {
                                column = selTopLeft.col;
                                row = rows.nextVisible(row, true);
                            }
                        }
                        break;
                    case 'previous':
                        if (selTopLeft.eq(current)) {
                            selection = sheet.previousNavigationRange();
                            row = selection.bottomRight.row;
                            column = selection.bottomRight.col;
                        } else {
                            column = columns.prevVisible(topLeftCol, true);
                            if (column < selTopLeft.col) {
                                column = selBottomRight.col;
                                row = rows.prevVisible(row, true);
                            }
                        }
                        break;
                    case 'lower':
                        if (selBottomRight.eq(current)) {
                            selection = sheet.nextNavigationRange();
                            row = selection.topLeft.row;
                            column = selection.topLeft.col;
                        } else {
                            row = rows.nextVisible(topLeftRow, true);
                            if (row > selBottomRight.row) {
                                row = selTopLeft.row;
                                column = columns.nextVisible(column, true);
                            }
                        }
                        break;
                    case 'upper':
                        if (selTopLeft.eq(current)) {
                            selection = sheet.previousNavigationRange();
                            row = selection.bottomRight.row;
                            column = selection.bottomRight.col;
                        } else {
                            row = rows.prevVisible(topLeftRow, true);
                            if (row < selTopLeft.row) {
                                row = selBottomRight.row;
                                column = columns.prevVisible(column, true);
                            }
                        }
                        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) {
                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, row;
                if (!punch) {
                    var preview = sheet.range(dest)._previewFillFrom(sheet.range(origin));
                    if (preview) {
                        direction = preview.direction;
                        var props = preview.props;
                        if (direction === 0 || direction == 1) {
                            row = props[props.length - 1];
                            hint = row[row.length - 1].value;
                        } else if (direction === 2) {
                            row = props[0];
                            hint = row[row.length - 1].value;
                        } else if (direction === 3) {
                            row = props[props.length - 1];
                            hint = row[0].value;
                        }
                    }
                }
                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 () {
                this.forEachSelectedColumn(function (sheet, index, i) {
                    sheet.deleteColumn(index - i);
                });
            },
            deleteSelectedRows: function () {
                this.forEachSelectedRow(function (sheet, index, i) {
                    sheet.deleteRow(index - i);
                });
            },
            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);
                });
            },
            addColumnLeft: function () {
                this.forEachSelectedColumn(function (sheet, index, i) {
                    sheet.insertColumn(index - i);
                });
            },
            addColumnRight: function () {
                this.forEachSelectedColumn(function (sheet, index, i) {
                    sheet.insertColumn(index + (i + 1));
                });
            },
            canAddRow: function () {
                var range = this._sheet.select().toRangeRef();
                var rowCount = range.height();
                return this._sheet.canInsertRow(0, rowCount);
            },
            addRowAbove: function () {
                this.forEachSelectedRow(function (sheet, index, i) {
                    sheet.insertRow(index - i);
                });
            },
            addRowBelow: function () {
                this.forEachSelectedRow(function (sheet, index, i) {
                    sheet.insertRow(index + (i + 1));
                });
            }
        });
        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.workbook = workbook;
                this.origin = kendo.spreadsheet.NULLREF;
                this.iframe = document.createElement('iframe');
                this.iframe.className = 'k-spreadsheet-clipboard-paste';
                this.menuInvoked = true;
                this._external = {};
                this._uid = kendo.guid();
                document.body.appendChild(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 status = { canPaste: true };
                if (ref === kendo.spreadsheet.NULLREF) {
                    var external = this.isExternal();
                    status.pasteOnMerged = this.intersectsMerged();
                    status.canPaste = status.pasteOnMerged ? false : external;
                    return status;
                }
                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();
                var state = this.parse(this._external);
                this.origin = getSourceRef(state);
                var ref = this.pasteRef();
                return !ref.eq(sheet.unionWithMerged(ref));
            },
            copy: function () {
                var sheet = this.workbook.activeSheet();
                this.origin = sheet.select();
                this.contents = sheet.selection().getState();
                delete this._external.html;
                delete this._external.plain;
            },
            cut: function () {
                var sheet = this.workbook.activeSheet();
                this.copy();
                sheet.range(sheet.select()).clear();
            },
            pasteRef: function () {
                var sheet = this.workbook.activeSheet();
                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);
            },
            destroy: function () {
                document.body.removeChild(this.iframe);
            },
            paste: function () {
                var state = {};
                var sheet = this.workbook.activeSheet();
                if (this._isInternal()) {
                    state = this.contents;
                } else {
                    state = this.parse(this._external);
                    this.origin = getSourceRef(state);
                }
                var pasteRef = this.pasteRef();
                sheet.range(pasteRef).setState(state, this);
                sheet.triggerChange({
                    recalc: true,
                    ref: pasteRef
                });
            },
            external: function (data) {
                if (data && (data.html || data.plain)) {
                    this._external = data;
                } else {
                    return this._external;
                }
            },
            isExternal: function () {
                return !this._isInternal();
            },
            parse: function (data) {
                var state = newState();
                if (data.html) {
                    var doc = this.iframe.contentWindow.document;
                    doc.open();
                    doc.write(data.html);
                    doc.close();
                    var table = $(doc).find('table:first');
                    if (table.length) {
                        state = parseHTML(table);
                    } else if (!data.plain) {
                        var element = $(doc.body).find(':not(style)');
                        setStateData(state, 0, 0, cellState(element.text()));
                    } else {
                        state = parseTSV(data.plain);
                    }
                } else {
                    state = parseTSV(data.plain);
                }
                return state;
            },
            _isInternal: function () {
                if (this._external.html === undefined) {
                    return true;
                }
                var internalHTML = $('<div/>').html(this._external.html).find('table.kendo-clipboard-' + this._uid).length ? true : false;
                var internalPlain = $('<div/>').html(this._external.plain).find('table.kendo-clipboard-' + this._uid).length ? true : false;
                if (internalHTML || internalPlain) {
                    return true;
                }
                return false;
            }
        });
        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 getSourceRef(state) {
            return state.origRef;
        }
        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(element) {
            var styles = window.getComputedStyle(element[0]);
            var text = element[0].innerText;
            var borders = borderObject(styles);
            var state = {
                value: text === '' ? null : text,
                borderBottom: borders.borderBottom,
                borderRight: borders.borderRight,
                borderLeft: borders.borderLeft,
                borderTop: borders.borderTop,
                fontSize: parseInt(styles['font-size'], 10)
            };
            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();
            table.find('>tr, >tbody>tr').each(function (rowIndex, tr) {
                $(tr).find('>td, >th').each(function (colIndex, td) {
                    var rowspan = parseInt($(td).attr('rowspan'), 10) - 1 || 0;
                    var colspan = parseInt($(td).attr('colspan'), 10) - 1 || 0;
                    var blankCell = '<td/>';
                    var ci;
                    if (rowspan) {
                        var endRow = rowIndex + rowspan;
                        for (var ri = rowIndex; ri <= endRow; ri++) {
                            var row = table.find('tr').eq(ri);
                            if (ri > rowIndex) {
                                blankCell = '<td class=\'rowspan\'></td>';
                                if (colIndex === 0) {
                                    row.find('td').eq(colIndex).after(blankCell);
                                } else {
                                    var last = Math.min(row.find('td').length, colIndex);
                                    row.find('td').eq(last - 1).after(blankCell);
                                }
                            }
                            if (colspan) {
                                for (ci = colIndex; ci < colspan + colIndex; ci++) {
                                    blankCell = '<td class=\'rowspan colspan\'></td>';
                                    row.find('td').eq(ci).after(blankCell);
                                }
                            }
                        }
                    } else {
                        if (colspan) {
                            for (ci = colIndex; ci < colspan + colIndex; ci++) {
                                blankCell = '<td class=\'colspan\'></td>';
                                $(tr).find('td').eq(ci).after(blankCell);
                            }
                        }
                    }
                });
            });
            table.find('>tr, >tbody>tr').each(function (rowIndex, tr) {
                $(tr).find('>td, >th').each(function (colIndex, td) {
                    var rowspan = parseInt($(td).attr('rowspan'), 10) - 1 || 0;
                    var colspan = parseInt($(td).attr('colspan'), 10) - 1 || 0;
                    setStateData(state, rowIndex, colIndex, cellState($(td)));
                    if (rowspan || colspan) {
                        var startCol = String.fromCharCode(65 + colIndex);
                        var endCol = String.fromCharCode(65 + colIndex + colspan);
                        var address = startCol + (rowIndex + 1) + ':' + endCol + (rowIndex + 1 + rowspan);
                        state.mergedCells.push(address);
                    }
                });
            });
            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'
    ], 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',
            'verticalAlign',
            'background',
            'format',
            'link',
            'editor'
        ];
        var borders = {
            borderTop: {
                complement: 'borderBottom',
                direction: {
                    top: -1,
                    bottom: -1
                }
            },
            borderLeft: {
                complement: 'borderRight',
                direction: {
                    left: -1,
                    right: -1
                }
            },
            borderRight: {
                complement: 'borderLeft',
                direction: {
                    left: 1,
                    right: 1
                }
            },
            borderBottom: {
                complement: 'borderTop',
                direction: {
                    top: 1,
                    bottom: 1
                }
            }
        };
        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 add(ref) {
                    if (ref instanceof UnionRef) {
                        ref.forEach(add);
                    } else {
                        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,
                        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);
                });
            },
            _border: function (property, value) {
                var result;
                var complement = borders[property].complement;
                var direction = borders[property].direction;
                var sheet = this._sheet;
                sheet.batch(function () {
                    result = this._property(property, value);
                    if (value !== undefined) {
                        this._resizedRef(direction).forEach(function (ref) {
                            if (ref !== kendo.spreadsheet.NULLREF) {
                                new Range(ref, sheet)._property(complement, null);
                            }
                        });
                    }
                }.bind(this), {});
                return result;
            },
            _collapsedBorder: function (property) {
                var result = this._property(property);
                var complement = borders[property].complement;
                var direction = borders[property].direction;
                this._resizedRef(direction).forEach(function (ref) {
                    if (!result && ref !== kendo.spreadsheet.NULLREF) {
                        var range = new Range(ref, this._sheet);
                        result = range._property(complement);
                    }
                }.bind(this));
                return result;
            },
            borderTop: function (value) {
                return this._border('borderTop', value);
            },
            borderRight: function (value) {
                return this._border('borderRight', value);
            },
            borderBottom: function (value) {
                return this._border('borderBottom', value);
            },
            borderLeft: function (value) {
                return this._border('borderLeft', value);
            },
            collapsedBorderTop: function () {
                return this._collapsedBorder('borderTop');
            },
            collapsedBorderRight: function () {
                return this._collapsedBorder('borderRight');
            },
            collapsedBorderBottom: function () {
                return this._collapsedBorder('borderBottom');
            },
            collapsedBorderLeft: function () {
                return this._collapsedBorder('borderLeft');
            },
            input: function (value) {
                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);
                    this._sheet.batch(function () {
                        var formula = null;
                        if (x.type == 'exp') {
                            formula = kendo.spreadsheet.calc.compile(x);
                        } else if (existingFormat != '@') {
                            if (x.type == 'date') {
                                this.format(x.format || toExcelFormat(kendo.culture().calendar.patterns.d));
                            } else if (x.type == 'percent') {
                                this.format(x.value * 100 == (x.value * 100 | 0) ? '0%' : '0.00%');
                            } else if (x.format && !existingFormat) {
                                this.format(x.format);
                            }
                        } else if (x.type != 'string') {
                            x.value = value;
                        }
                        this.formula(formula);
                        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);
                                if (typeof x.value == 'number') {
                                    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 = value * 100 + '%';
                            } else if (typeof value == 'string' && (/^[=']/.test(value) || /^(?:true|false)$/i.test(value) || looksLikeANumber(value))) {
                                value = '\'' + value;
                            }
                        }
                    return value;
                }
            },
            enable: function (value) {
                if (value === undefined) {
                    value = true;
                    this._sheet.forEach(this._ref.toRangeRef(), function (_, __, data) {
                        if (data.enable === false) {
                            value = false;
                        }
                    });
                    return value;
                }
                return this._property('enable', value);
            },
            formula: function (value) {
                if (value === undefined) {
                    var f = this._get('formula');
                    return f ? '' + f : null;
                }
                return this._property('formula', value);
            },
            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) {
                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++) {
                        for (ri = topLeftRow; ri <= bottomRightRow; ri++) {
                            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) {
                var clearAll = !options || !Object.keys(options).length;
                var sheet = this._sheet;
                var reason = {
                    recalc: clearAll || options && options.contentsOnly === true,
                    ref: this._ref
                };
                sheet.batch(function () {
                    if (reason.recalc) {
                        this.formula(null);
                    }
                    if (clearAll) {
                        this.validation(null);
                    }
                    if (clearAll || options && options.formatOnly === true) {
                        PROPERTIES.forEach(function (x) {
                            this[x](null);
                        }.bind(this));
                        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._ref instanceof UnionRef || this._ref === kendo.spreadsheet.NULLREF);
            },
            sort: function (spec) {
                if (this._ref instanceof UnionRef) {
                    throw new Error('Unsupported for multiple ranges.');
                }
                if (this._ref === kendo.spreadsheet.NULLREF) {
                    throw new Error('Unsupported for NULLREF.');
                }
                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(i);
                    }
                    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
                };
                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) {
                        cellState[property] = typeof cell[property] == 'undefined' ? null : cell[property];
                    });
                });
                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;
                sheet.batch(function () {
                    if (state.mergedCells) {
                        this.unmerge();
                    }
                    var row = origin.row;
                    state.data.forEach(function (data, dr) {
                        if (clipboard && !clipboard.isExternal() && sheet.isHiddenRow(state.ref.row + dr)) {
                            return;
                        }
                        var col = origin.col;
                        data.forEach(function (cellState, dc) {
                            if (clipboard && !clipboard.isExternal() && 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 (clipboard && clipboard.isExternal()) {
                                        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 });
            },
            _adjustRowHeight: function () {
                var sheet = this._sheet;
                var state = this.getState();
                var mergedCells = [];
                for (var i = 0; i < state.mergedCells.length; i++) {
                    mergedCells.push(sheet.range(state.mergedCells[i]));
                }
                this.forEachRow(function (row) {
                    if (row.topLeft().row >= row.sheet()._rows._count) {
                        return;
                    }
                    var maxHeight = row.sheet().rowHeight(row.topLeft().row);
                    row.forEachCell(function (rowIndex, colIndex, cell) {
                        var cellRange = sheet.range(rowIndex, colIndex);
                        var totalWidth = 0;
                        for (var i = 0; i < mergedCells.length; i++) {
                            if (cellRange._ref.intersects(mergedCells[i]._ref)) {
                                totalWidth += cell.width;
                                break;
                            }
                        }
                        var width = Math.max(sheet.columnWidth(colIndex), totalWidth);
                        maxHeight = Math.max(maxHeight, kendo.spreadsheet.util.getTextHeight(cell.value, width, cell.fontSize, cell.wrap));
                    });
                    sheet.rowHeight(row.topLeft().row, Math.max(sheet.rowHeight(row.topLeft().row), maxHeight));
                });
            },
            forEachCell: function (callback) {
                this._ref.forEach(function (ref) {
                    this._sheet.forEach(ref.toRangeRef(), callback.bind(this));
                }.bind(this));
            },
            hasValue: function () {
                var result = false;
                this.forEachCell(function (row, col, cell) {
                    if (Object.keys(cell).length !== 0) {
                        result = true;
                    }
                });
                return result;
            },
            wrap: function (flag) {
                if (flag === undefined) {
                    return !!this._property('wrap');
                }
                this.forEachRow(function (range) {
                    var maxHeight = range.sheet().rowHeight(range.topLeft().row);
                    range.forEachCell(function (row, col, cell) {
                        var width = this._sheet.columnWidth(col);
                        if (cell.value !== null && cell.value !== undefined) {
                            maxHeight = Math.max(maxHeight, kendo.spreadsheet.util.getTextHeight(cell.value, width, cell.fontSize, true));
                        }
                    });
                    range.sheet().rowHeight(range.topLeft().row, maxHeight);
                }.bind(this));
                this._property('wrap', flag);
                return this;
            },
            fontSize: function (size) {
                if (size === undefined) {
                    return this._property('fontSize');
                }
                this.forEachRow(function (range) {
                    var maxHeight = range.sheet().rowHeight(range.topLeft().row);
                    range.forEachCell(function (row, col, cell) {
                        var width = this._sheet.columnWidth(col);
                        if (cell.value !== null && cell.value !== undefined) {
                            maxHeight = Math.max(maxHeight, kendo.spreadsheet.util.getTextHeight(cell.value, width, size, cell.wrap));
                        }
                    });
                    range.sheet().rowHeight(range.topLeft().row, maxHeight);
                }.bind(this));
                this._property('fontSize', size);
                return this;
            },
            draw: function (options, callback) {
                this._sheet.draw(this, options, callback);
            }
        });
        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 !important; margin: 0 !important; border: 1px solid black !important;' + 'line-height: normal !important; visibility: hidden !important;' + 'white-space: pre-wrap !important; word-break: break-all !important;" />')[0];
        function getTextHeight(text, width, fontSize, wrap) {
            var styles = {
                'baselineMarkerSize': 0,
                'width': width + 'px',
                'font-size': (fontSize || 12) + 'px',
                'word-break': wrap === true ? 'break-all' : 'normal',
                'white-space': wrap === true ? 'pre-wrap' : 'pre'
            };
            return kendo.util.measureText(text, styles, measureBox).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;
            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, f) {
            var ret = [];
            for (var i = 0; i < a.length; ++i) {
                var val = a[i];
                if (val instanceof Ref) {
                    val = this.getRefData(val);
                    ret = ret.concat(val);
                } else if (Array.isArray(val)) {
                    ret = ret.concat(this.cellValues(val));
                } else if (val instanceof Matrix) {
                    ret = ret.concat(this.cellValues(val.data));
                } else {
                    ret.push(val);
                }
            }
            if (f) {
                return f.apply(this, ret);
            }
            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;
        },
        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) {
            var f = this.formula;
            return this.ss.getRefCells(refs, hiddenInfo, f.sheet, f.row, f.col);
        },
        getRefData: function (ref) {
            var f = this.formula;
            return this.ss.getData(ref, f.sheet, f.row, f.col);
        },
        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;
        },
        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) {
            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;
        },
        clone: function (sheet, row, col, forceRefs) {
            var lcsheet = sheet.toLowerCase();
            var refs = this.refs;
            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;
                });
            }
            return new Formula(refs, this.handler, this.print, sheet, row, col);
        },
        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);
                while (parentContext) {
                    if (parentContext.formula === this) {
                        this.pending = false;
                        ctx.resolve(new CalcError('CIRCULAR'));
                        return;
                    }
                    parentContext = parentContext.parent;
                }
                if (this.pending) {
                    return;
                }
                this.pending = true;
                if (!this.absrefs) {
                    this.absrefs = this.refs.map(function (ref) {
                        return ref.absolute(this.row, this.col);
                    }, this);
                }
                this.handler.call(ctx);
            }
        },
        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;
            this.refs = this.refs.map(function (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);
            }, this);
        },
        toString: function () {
            return this.print(this.row, this.col);
        }
    });
    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, roundFloatErrors);
        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 n = type[2];
                    force();
                    code += 'try {' + 'var $' + name + ' = this.cellValues(args.slice(i';
                    if (n) {
                        code += ', i + ' + n;
                    }
                    code += ')).filter(function($' + name + '){ ';
                    if (type[0] == 'collect') {
                        code += 'if ($' + name + ' instanceof CalcError) throw $' + name + '; ';
                    }
                    code += 'return ' + cond(type[1]) + '; }, 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\') || ' + '(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.asMatrix(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 == '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 roundFloatErrors(num) {
        return Math.round(num * 1000000000000000) / 1000000000000000;
    }
    function maybeRoundFloatErrors(num) {
        if (typeof num == 'number') {
            return roundFloatErrors(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]) {
                                        var m = args[i];
                                        xargs[i] = m.get(row % m.height, col % m.width);
                                    } 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]) {
                                        var m = args[i];
                                        xargs[i] = m.get(row % m.height, col % m.width);
                                    } 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 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) {
        return kendo.parseDate(str) || kendo.parseDate(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.isLeapYear = isLeapYear;
    exports.daysInYear = daysInYear;
    exports.parseDate = parseDate;
    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) {
        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) {
        return m;
    }).args([[
            'm',
            'matrix'
        ]]);
    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 : 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
            }));
        },
        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) {
            if (this.from) {
                this.from.adjust(affectedSheet, operation, start, delta);
            }
            if (this.to) {
                this.to.adjust(affectedSheet, operation, start, delta);
            }
            if (this.sheet.toLowerCase() == affectedSheet.toLowerCase()) {
                var formulaRow = this.row;
                var formulaCol = this.col;
                switch (operation) {
                case 'row':
                    if (formulaRow >= start) {
                        this.row += delta;
                    }
                    break;
                case 'col':
                    if (formulaCol >= start) {
                        this.col += delta;
                    }
                    break;
                }
            }
        },
        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 CellRef = kendo.spreadsheet.CellRef;
        var Range = kendo.spreadsheet.Range;
        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.originalSelection = ref;
                    this.selection = expanded;
                    if (changeActiveCell !== false) {
                        if (ref.isCell()) {
                            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);
            },
            _reinit: function (rowCount, columnCount, rowHeight, columnWidth, headerHeight, headerWidth) {
                var cellCount = rowCount * columnCount - 1;
                this._rows = new kendo.spreadsheet.Axis(rowCount, rowHeight);
                this._columns = new kendo.spreadsheet.Axis(columnCount, columnWidth);
                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(cellCount);
                this._sorter = new kendo.spreadsheet.Sorter(this._grid, this._properties.sortable());
                this._viewSelection = new Selection(this);
                this._editSelection = new Selection(this);
                this._formulaSelections = [];
            },
            _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;
            },
            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) {
                return this._property(this._columns.hide.bind(this._columns), columnIndex, { layout: true });
            },
            unhideColumn: function (columnIndex) {
                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);
            },
            _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) {
                            formula.adjust(affectedSheet, operation, start, delta);
                        });
                        sheet._forValidations(function (validation) {
                            validation.adjust(affectedSheet, operation, start, delta);
                        });
                    });
                    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);
            },
            _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);
            },
            canInsertRow: function (rowIndex, count) {
                count = count || 1;
                var grid = this._grid;
                var range = this.range(grid.rowCount - count, 0, count, grid.columnCount);
                return !range.hasValue();
            },
            insertRow: function (rowIndex) {
                if (!this.canInsertRow(rowIndex)) {
                    throw new Error('Shifting nonblank cells off the worksheet is not supported!');
                }
                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();
                    }
                    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('insertRow', { 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;
                }
                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();
                        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('deleteRow', { index: rowIndex });
                return this;
            },
            insertColumn: function (columnIndex) {
                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();
                        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;
                }
                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();
                        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;
            },
            hideRow: function (rowIndex) {
                return this._property(this._rows.hide.bind(this._rows), rowIndex, { layout: true });
            },
            unhideRow: function (rowIndex) {
                return this._property(this._rows.unhide.bind(this._rows), rowIndex, { layout: true });
            },
            isHiddenRow: function (rowIndex) {
                return this._grid._rows.hidden(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);
            },
            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) {
                if (!(ref instanceof RangeRef)) {
                    ref = this._ref(ref);
                }
                var topLeft = this._grid.normalize(ref.topLeft);
                var bottomRight = this._grid.normalize(ref.bottomRight);
                for (var ci = topLeft.col; ci <= bottomRight.col; ci++) {
                    var ri = topLeft.row;
                    var startCellIndex = this._grid.index(ri, ci);
                    var endCellIndex = this._grid.index(bottomRight.row, ci);
                    this._properties.forEach(startCellIndex, endCellIndex, function (value) {
                        callback(ri++, ci, value);
                    });
                }
            },
            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;
            },
            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 });
                    }
                }
            },
            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 });
            },
            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 rowSelection = bottomRight.col >= maxCol;
                    var colSelection = bottomRight.row >= maxRow;
                    if (colSelection) {
                        allRows = true;
                        colState = 'full';
                    }
                    if (rowSelection) {
                        allCols = true;
                        rowState = 'full';
                    }
                    if (!colSelection) {
                        for (i = ref.topLeft.row; i <= bottomRight.row; i++) {
                            if (rows[i] !== 'full') {
                                rows[i] = rowState;
                            }
                        }
                    }
                    if (!rowSelection) {
                        for (i = ref.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 = [];
                this.forEach(kendo.spreadsheet.SHEETREF, function (row, col, 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) {
                        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
                };
                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) {
                                        cell.formula = this._compileFormula(rowIndex, columnIndex, cell.formula);
                                    }
                                    if (cell.validation) {
                                        cell.validation = this._compileValidation(rowIndex, columnIndex, cell.validation);
                                    }
                                    this._properties.fromJSON(this._grid.index(rowIndex, columnIndex), cell);
                                }
                            }
                        }
                    }
                    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;
                    }
                    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 (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.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._rows.hidden(ri)) {
                            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.hideRow(cell.row);
                            }
                        }
                    }, this);
                    this._filter = {
                        ref: ref,
                        columns: columns
                    };
                }, {
                    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();
                    }, {
                        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;
            }
        });
        kendo.spreadsheet.Sheet = Sheet;
    }(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-font-icon',
            sheetsBarKButton: 'k-button k-button-icon',
            sheetsBarKButtonBare: 'k-button-bare',
            sheetsBarKArrowW: 'k-i-arrow-w',
            sheetsBarKArrowE: 'k-i-arrow-e',
            sheetsBarKReset: 'k-reset k-tabstrip-items',
            sheetsBarKIconX: 'k-i-x',
            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._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())]));
                        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();
                }
                this.trigger('remove', { name: removedSheetName });
            },
            _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) {
                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.sheetsBarKSprite + EMPTYCHAR + 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 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 = Object.create(null);
    var ParseError = kendo.Class.extend({
        init: function ParseError(message, pos) {
            this.message = message;
            this.pos = pos;
        },
        toString: function () {
            return this.message;
        }
    });
    (function (ops) {
        ops.forEach(function (cls, i) {
            cls.forEach(function (op) {
                OPERATORS[op] = ops.length - i;
            });
        });
    }([
        [':'],
        [' '],
        [','],
        ['%'],
        ['^'],
        [
            '*',
            '/'
        ],
        [
            '+',
            '-'
        ],
        ['&'],
        [
            '=',
            '<',
            '>',
            '<=',
            '>=',
            '<>'
        ]
    ]));
    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', ',')) {
                    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(commas)), 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', ',')) {
                    args.push({ type: 'null' });
                    input.next();
                    continue;
                }
                args.push(parseExpression(false));
                if (input.eof() || is('punc', ')')) {
                    break;
                }
                skip('op', ',');
            }
            skip('punc', ')', true);
            return {
                type: 'func',
                func: fname,
                args: args
            };
        }
        function fixReference(ref) {
            if (!ref.hasSheet()) {
                ref.setSheet(sheet);
            }
            return addReference(ref);
        }
        function parseAtom(commas) {
            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(commas)
                };
            } else if (!input.peek()) {
                input.croak('Incomplete expression');
            } 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('punc', ';')) {
                    value.push(row = []);
                    input.next();
                } else {
                    skip('op', ',');
                }
                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 != ',')) {
                var his_prec = OPERATORS[tok.value];
                if (his_prec > my_prec) {
                    input.next();
                    var right = maybeBinary(parseAtom(commas), his_prec, commas);
                    return maybeBinary({
                        type: 'binary',
                        op: 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
        };
    }
    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':
            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 == ':');
                    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(' + \', \' + ') : '\'\'') + ' + \')\'';
            case 'matrix':
                return '\'{ \' + ' + node.value.map(function (el) {
                    return el.map(function (el) {
                        return print(el, node, 0);
                    }).join(' + \', \' + ');
                }).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 == '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 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));
    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;
        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\n\xA0\u200B'.indexOf(ch) >= 0;
    }
    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) || ch.toLowerCase() != ch.toUpperCase();
        }
        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 == '.') {
                    if (has_dot) {
                        return false;
                    }
                    has_dot = true;
                    return true;
                }
                return isDigit(ch);
            });
            return {
                type: 'num',
                value: parseFloat(number)
            };
        }
        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 0;
            }
            if (!a && !c || a && c) {
                var negative = a && /-$/.test(a);
                var num = parseInt(b, 10);
                if (negative) {
                    num = -num;
                }
                if (!a) {
                    num--;
                }
                return num;
            }
        }
        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 == '.') {
                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: ' + ch);
            }
            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;
        }
    }
    var EOF = { type: 'eof' };
    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) {
        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);
        if (date) {
            return {
                type: 'date',
                value: runtime.dateToSerial(date)
            };
        }
        var num = parseFloat(input);
        if (!isNaN(num) && input.length > 0 && num == input) {
            return {
                type: 'number',
                value: num
            };
        }
        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;
        }
    }
    exports.parseNameDefinition = parseNameDefinition;
    exports.parseFormula = parseFormula;
    exports.parseReference = parseReference;
    exports.compile = makeFormula;
    exports.InputStream = InputStream;
    exports.ParseError = ParseError;
    exports.tokenize = tokenize;
    registerFormatParser(function (input) {
        var m;
        if (m = /^(\d+):(\d+)$/.exec(input)) {
            var hh = parseInt(m[1], 10);
            var mm = parseInt(m[2], 10);
            return {
                type: 'date',
                format: 'hh:mm',
                value: 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: 'mm:ss.00',
                value: 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: 'hh:mm:ss',
                value: 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: 'hh:mm:ss.00',
                value: 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;
        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 += '#';
        if (m = input.skip(rxcur)) {
            if (has_currency) {
                return null;
            }
            has_currency = true;
            suffix = '"' + m[0] + '"';
        }
        if (!input.eof()) {
            return null;
        }
        if (n[2] || has_currency) {
            format += ',#';
        }
        if (n[3]) {
            format += '.' + repeat('0', n[3].length - 1);
        }
        var value = n[0].replace(new RegExp('\\' + comma, 'g'), '').replace(new RegExp('\\' + dot, 'g'), '.');
        format += suffix;
        if (has_currency) {
            format += ';-' + format;
        }
        return {
            type: 'number',
            format: format,
            value: sign * parseFloat(value)
        };
    });
    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;
    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'
    ];
    function xl(file) {
        if (!/^\//.test(file)) {
            file = 'xl/' + file;
        } else {
            file = file.substr(1);
        }
        return file;
    }
    function readWorkbook(zip, workbook, progress) {
        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);
                    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 (sheet) {
                        name = '\'' + sheet.replace(/\'/g, '\\\'') + '\'!' + name;
                    }
                    workbook.defineName(name, text, bool(attrs.hidden));
                }
            }
        });
        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 Math.floor(fraction) * maximumDigitWidth;
    }
    function toRowHeight(pts) {
        return pts * 1.5625;
    }
    function readSheet(zip, file, sheet, strings, styles) {
        var ref, type, value, formula, formulaRange;
        var nCols = sheet._columns._count;
        var prevCellRef = null;
        var relsFile = file.replace(/worksheets\//, 'worksheets/_rels/');
        var relationships = readRelationships(zip, relsFile);
        parse(zip, xl(file), {
            enter: function (tag, attrs) {
                if (this.is(SEL_CELL)) {
                    value = null;
                    formula = null;
                    formulaRange = null;
                    ref = attrs.r;
                    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);
                        }
                    }
                } 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);
                    }
                }
            },
            leave: function (tag) {
                if (this.is(SEL_CELL)) {
                    if (formula != null) {
                        try {
                            sheet.range(formulaRange || ref).formula(formula);
                        } catch (ex) {
                            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 (tag == 'cols') {
                    sheet._columns._refresh();
                } else if (tag == 'sheetData') {
                    sheet._rows._refresh();
                }
            },
            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;
                    if (attrs.t == 'shared') {
                        formulaRange = attrs.ref;
                    }
                }
            }
        });
    }
    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', '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);
            range._property('fontSize', f.size);
            if (f.bold) {
                range.bold(true);
            }
            if (f.italic) {
                range.italic(true);
            }
        }
        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 (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) && attrs.style) {
                        border[tag] = { style: attrs.style };
                    }
                    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);
                        }
                    }
                }
            },
            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 + ')';
    }
    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;
        var Workbook = kendo.Observable.extend({
            init: function (options, view) {
                kendo.Observable.fn.init.call(this);
                this.options = options;
                this._view = view;
                this._sheets = [];
                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: [
                'change',
                'excelImport',
                'excelExport'
            ],
            _sheetChange: function (e) {
                this.trigger('change', e);
            },
            _sheetCommandRequest: function (e) {
                this.trigger('commandRequest', e);
            },
            _inputForRef: function (ref) {
                return new kendo.spreadsheet.Range(ref, this._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 if (commandOptions.editActiveCell) {
                    command.range(sheet.activeCellSelection());
                } 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);
                    }
                }
                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 = 'Sheet' + 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);
                sheet._workbook = this;
                sheet._name(sheetName);
                sheet.bind('change', this._sheetChange.bind(this));
                sheet.bind('commandRequest', this._sheetCommandRequest.bind(this));
                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;
            },
            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 = {};
                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;
                }
                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].unbind();
                }
                this._sheets = [];
                this._sheetsSearchCache = {};
                this._names = {};
            },
            fromJSON: function (json) {
                if (json.sheets) {
                    this._clearSheets();
                    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
                };
            },
            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) {
                options = $.extend({}, this.options.excel, options);
                var data = this.toJSON();
                if (!this.trigger('excelExport', { workbook: data })) {
                    var workbook = new kendo.ooxml.Workbook(data);
                    kendo.saveAs({
                        dataURI: workbook.toDataURL(),
                        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);
            },
            options: {}
        });
        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 kendo.drawing.exportPDF(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) {
            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 (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 (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) {
            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).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;
            }
            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.each(function (value, r, c) {
                    sheet._value(row + r, col + c, value);
                });
            } else {
                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',
            ':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'
        };
        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'
        };
        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.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.cellContextMenu.element.add(this.rowHeaderContextMenu.element).add(this.colHeaderContextMenu.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) {
                    var closeHandler;
                    if (this.view.editor.isActive()) {
                        this.enableEditor(false);
                        closeHandler = this.enableEditor.bind(this, true, true);
                    }
                    if (result.reason === 'error') {
                        this._lastCommandRequest = null;
                        this.view.showError(result, closeHandler);
                    } else {
                        this.view.openDialog(result.reason, { close: closeHandler });
                    }
                }
                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 '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) {
                    sheet = workbook.insertSheet();
                } else {
                    sheet = workbook.sheetByName(e.name);
                }
                if (workbook.activeSheet().name() !== sheet.name()) {
                    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);
                    editor.value(workbook._inputForRef(sheet.activeCell()));
                }
                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();
            },
            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();
            },
            onAction: function (event, action) {
                this.navigator.moveActiveCell(ACTIONS[action]);
                event.preventDefault();
            },
            onPageUp: function () {
                this.scrollDown(-this._viewPortHeight);
            },
            onPageDown: function () {
                this.scrollDown(this._viewPortHeight);
            },
            onEntryAction: function (event, action) {
                if (event.mod) {
                    var shouldPrevent = true;
                    var key = String.fromCharCode(event.keyCode);
                    switch (key) {
                    case 'A':
                        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 = this._workbook.activeSheet().selection().enable() === false;
                    if (action == 'delete' || action == 'backspace') {
                        if (!disabled) {
                            this._execute({ command: 'ClearContentCommand' });
                        }
                        event.preventDefault();
                    } else if (alphaNumRegExp.test(action) || action === ':edit') {
                        if (disabled) {
                            event.preventDefault();
                            return;
                        }
                        if (action !== ':edit') {
                            this.editor.value('');
                        }
                        this.editor.activate({
                            range: this._workbook.activeSheet()._viewActiveCell(),
                            rect: this.view.activeCellRectangle(),
                            tooltip: this._activeTooltip()
                        }).focus();
                    } 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();
                }
            },
            onMouseDown: function (event) {
                var object = this.objectAt(event);
                if (object.pane) {
                    this.originFrame = object.pane;
                }
                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.editor.deactivate();
                    if (this.editor.isActive()) {
                        event.preventDefault();
                        return;
                    }
                }
                var sheet = this._workbook.activeSheet();
                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);
            },
            onContextMenu: function (event) {
                var sheet = this._workbook.activeSheet();
                if (sheet.resizingInProgress()) {
                    return;
                }
                event.preventDefault();
                this.cellContextMenu.close();
                this.colHeaderContextMenu.close();
                this.rowHeaderContextMenu.close();
                var menu;
                var location = {
                    pageX: event.pageX,
                    pageY: event.pageY
                };
                var object = this.objectAt(location);
                if (object.type === 'columnresizehandle' || object.type === 'rowresizehandle') {
                    return;
                }
                this.navigator.selectForContextMenu(object.ref, SELECTION_MODES[object.type]);
                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 {
                    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;
            },
            onMouseDrag: function (event) {
                if (this._selectionMode === 'sheet') {
                    return;
                }
                var location = {
                    pageX: event.pageX,
                    pageY: event.pageY
                };
                var object = this.objectAt(location);
                var sheet = this._workbook.activeSheet();
                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();
                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.selection()._ref);
                    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;
                }
                this.editor.activate({
                    range: this._workbook.activeSheet()._viewActiveCell(),
                    rect: this.view.activeCellRectangle(),
                    tooltip: this._activeTooltip()
                }).focus();
                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 }
                });
            },
            clipBoardValue: function () {
                return this.clipboardElement.html();
            },
            onPaste: function (e) {
                var html = '';
                var plain = '';
                this.clipboard.menuInvoked = e === undefined;
                if (e) {
                    if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.getData) {
                        e.preventDefault();
                        var hasHTML = false;
                        var hasPlainText = false;
                        if (window.DOMStringList && e.originalEvent.clipboardData.types instanceof window.DOMStringList) {
                            hasHTML = e.originalEvent.clipboardData.types.contains('text/html');
                            hasPlainText = e.originalEvent.clipboardData.types.contains('text/plain');
                        } else {
                            hasHTML = /text\/html/.test(e.originalEvent.clipboardData.types);
                            hasPlainText = /text\/plain/.test(e.originalEvent.clipboardData.types);
                        }
                        if (hasHTML) {
                            html = e.originalEvent.clipboardData.getData('text/html');
                        }
                        if (hasPlainText) {
                            plain = e.originalEvent.clipboardData.getData('text/plain').trim();
                        }
                    } else {
                        var table = this.clipboardElement.find('table.kendo-clipboard-' + this.clipboard._uid).detach();
                        this.clipboardElement.empty();
                        setTimeout(function () {
                            var html = this.clipboardElement.html();
                            var plain = window.clipboardData.getData('Text').trim();
                            if (!html && !plain) {
                                return;
                            }
                            this.clipboard.external({
                                html: html,
                                plain: plain
                            });
                            this.clipboardElement.empty().append(table);
                            this._execute({
                                command: 'PasteCommand',
                                options: { workbook: this.view._workbook }
                            });
                            this.clipboard.menuInvoked = true;
                        }.bind(this));
                        return;
                    }
                } else {
                    if (kendo.support.browser.msie) {
                        this.clipboardElement.focus().select();
                        document.execCommand('paste');
                        return;
                    } else {
                        this.clipboard.menuInvoked = true;
                    }
                }
                if (!html && !plain) {
                    return;
                }
                this.clipboard.external({
                    html: html,
                    plain: plain
                });
                this._execute({
                    command: 'PasteCommand',
                    options: { workbook: this.view._workbook }
                });
            },
            onCopy: function (e) {
                this.clipboard.menuInvoked = e === undefined;
                this._execute({
                    command: 'CopyCommand',
                    options: { workbook: this.view._workbook }
                });
            },
            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;
            },
            objectAt: function (location) {
                var offset = this.container.offset();
                var coordinates = {
                    left: location.pageX - offset.left,
                    top: location.pageY - offset.top
                };
                return this.view.objectAt(coordinates.left, coordinates.top);
            },
            selectToLocation: function (cellLocation) {
                var object = this.objectAt(cellLocation);
                if (object.pane) {
                    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);
            },
            onEditorChange: function (e) {
                this._workbook.activeSheet().isInEditMode(false);
                var result = this._execute({
                    command: 'EditCommand',
                    options: {
                        editActiveCell: true,
                        value: e.value
                    }
                });
                if (result && result.reason === 'error') {
                    e.preventDefault();
                }
            },
            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()._viewActiveCell(),
                    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.editor.deactivate();
                if (!this.editor.isActive()) {
                    this.clipboardElement.focus();
                    this.navigator.navigateInSelection(ENTRY_ACTIONS[action]);
                }
            },
            onEditorAction: function (event, action) {
                var editor = this.editor;
                var sheet = this._workbook.activeSheet();
                if (editor.canInsertRef(true)) {
                    this.navigator.moveActiveCell(ACTIONS[action]);
                    editor.activeEditor().refAtPoint(sheet.selection()._ref);
                    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.selection()._ref);
                    sheet._setFormulaSelections(editor.highlightedRefs());
                    event.preventDefault();
                }
            },
            resetEditorValue: function () {
                this.editor.value(this._workbook._inputForRef(this._workbook.activeSheet()._viewActiveCell()));
            },
            deactivateEditor: function (callback, options) {
                var viewEditor = this.view.editor;
                this._lastCommandRequest = {
                    callback: callback,
                    options: options
                };
                if (!this.isEditorDeactivateBound) {
                    this.isEditorDeactivateBound = true;
                    viewEditor.one('deactivate', function () {
                        this.isEditorDeactivateBound = false;
                        if (this._lastCommandRequest) {
                            this._lastCommandRequest.callback(this._lastCommandRequest.options);
                            this._lastCommandRequest = null;
                        }
                    }.bind(this));
                }
                viewEditor.deactivate();
                this.enableEditor(false);
            },
            enableEditor: function (enable, focusLastActive, event) {
                if (event && event.action === 'revert') {
                    this.resetEditorValue();
                }
                enable = enable === undefined || enable;
                this._enableEditorEvents(enable);
                this.editor.enableEditing(enable);
                this.isEditorDisabled = !enable;
                this.view.enableClipboard(enable);
                if (focusLastActive) {
                    this.editor.focusLastActive();
                }
            },
            executeRequest: function (callback, options) {
                if (this.view.editor.isActive()) {
                    this.deactivateEditor(callback, options);
                } else {
                    callback(options);
                }
            },
            onCommandRequest: function (e) {
                var executeCommand = function (e) {
                    if (e.command) {
                        this._execute(e);
                    } else {
                        this._workbook.undoRedoStack[e.action]();
                    }
                }.bind(this);
                this.executeRequest(executeCommand, e);
            },
            onDialogRequest: function (e) {
                var executeDialog = function (e) {
                    this.enableEditor(false);
                    var additionalOptions = {
                        pdfExport: this._workbook.options.pdf,
                        excelExport: this._workbook.options.excel,
                        close: this.enableEditor.bind(this, true, false)
                    };
                    if (e.options) {
                        $.extend(true, e.options, additionalOptions);
                    } else {
                        e.options = additionalOptions;
                    }
                    this.view.openDialog(e.name, e.options);
                }.bind(this);
                this.executeRequest(executeDialog, e);
            },
            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'
    ], 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 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 k-font-icon',
            iconFilterDefault: 'k-i-arrow-s',
            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'
        };
        kendo.spreadsheet.messages.view = {
            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.',
                filterRangeContainingMerges: 'Cannot create a filter within a range containing merges',
                sortRangeContainingMerges: 'Cannot sort a range containing merges',
                validationError: 'The value that you entered violates the validation rules set on the cell.'
            },
            tabs: {
                home: 'Home',
                insert: 'Insert',
                data: 'Data'
            }
        };
        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 [
                'solid',
                (value.size || 1) + 'px',
                value.color || '#000'
            ].join(' ');
        }
        function asURL(link) {
            if (!/:\/\//.test(link)) {
                link = 'http://' + link;
            }
            return link;
        }
        function drawCell(collection, cell, cls, hBorders, vBorders, 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;
            }
            if (!cls && !kendo.spreadsheet.draw.shouldDrawCell(cell)) {
                return;
            }
            var left = cell.left;
            var top = cell.top;
            var width = cell.width + 1;
            var height = cell.height + 1;
            var style = {};
            var background = cell.background;
            var defaultBorder = null;
            if (background) {
                defaultBorder = background;
                if (showGrid) {
                    defaultBorder = kendo.parseColor(defaultBorder).toHSV();
                    defaultBorder.v *= 0.9;
                    defaultBorder = defaultBorder.toCssRgba();
                }
                defaultBorder = cellBorder({ color: 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.wordBreak = 'break-all';
            }
            if (cell.borderLeft) {
                style.borderLeft = cellBorder(cell.borderLeft);
                if (vBorders) {
                    vBorders[cell.left] = true;
                }
            } else if (defaultBorder && vBorders && !vBorders[cell.left]) {
                style.borderLeft = defaultBorder;
            } else {
                left++;
                width--;
            }
            if (cell.borderTop) {
                style.borderTop = cellBorder(cell.borderTop);
                if (hBorders) {
                    hBorders[cell.top] = true;
                }
            } else if (defaultBorder && hBorders && !hBorders[cell.top]) {
                style.borderTop = defaultBorder;
            } else {
                top++;
                height--;
            }
            if (cell.borderRight) {
                style.borderRight = cellBorder(cell.borderRight);
                if (vBorders) {
                    vBorders[cell.right] = true;
                }
            } else if (defaultBorder && vBorders && !vBorders[cell.right]) {
                style.borderRight = defaultBorder;
            } else {
                width--;
            }
            if (cell.borderBottom) {
                style.borderBottom = cellBorder(cell.borderBottom);
                if (hBorders) {
                    hBorders[cell.bottom] = true;
                }
            } else if (defaultBorder && hBorders && !hBorders[cell.bottom]) {
                style.borderBottom = defaultBorder;
            } else {
                height--;
            }
            style.left = left + 'px';
            style.top = top + 'px';
            style.width = width + 'px';
            style.height = height + 'px';
            var data = cell.value, type = typeof data;
            if (cell.format && data != null) {
                data = kendo.spreadsheet.formatting.format(data, cell.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':
                    style.textAlign = 'right';
                    break;
                case 'boolean':
                    style.textAlign = 'center';
                    break;
                }
            }
            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');
            }
            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._getOptions().messageTemplate;
            }
            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';
                style.wordBreak = 'break-all';
            }
            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;
            if (cell.format && data != null) {
                data = kendo.spreadsheet.formatting.format(data, cell.format);
                if (data.__dataType) {
                    type = data.__dataType;
                }
            }
            if (!style.textAlign) {
                switch (type) {
                case 'number':
                case 'date':
                case 'percent':
                    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._getOptions().messageTemplate;
                }
                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>Cut</li>' + '<li data-action=copy>Copy</li>' + '<li data-action=paste>Paste</li>' + '<li class="k-separator"></li>' + '<li data-action=merge>Merge</li>' + '<li data-action=unmerge>Unmerge</li>' + '</ul>';
        var ROW_HEADER_CONTEXT_MENU = '<ul class="#=classNames.rowHeaderContextMenu#">' + '<li data-action=cut>Cut</li>' + '<li data-action=copy>Copy</li>' + '<li data-action=paste>Paste</li>' + '<li class="k-separator"></li>' + '<li data-action="delete-row">Delete</li>' + '<li data-action="hide-row">Hide</li>' + '<li data-action="unhide-row">Unhide</li>' + '</ul>';
        var COL_HEADER_CONTEXT_MENU = '<ul class="#=classNames.colHeaderContextMenu#">' + '<li data-action=cut>Cut</li>' + '<li data-action=copy>Copy</li>' + '<li data-action=paste>Paste</li>' + '<li class="k-separator"></li>' + '<li data-action="delete-column">Delete</li>' + '<li data-action="hide-column">Hide</li>' + '<li data-action="unhide-column">Unhide</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);
        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 }));
                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);
                var scrollbar = kendo.support.scrollbar();
                $(this.container).css({
                    width: this.wrapper[0].clientWidth - scrollbar,
                    height: this.wrapper[0].clientHeight - scrollbar
                });
            },
            enableClipboard: function (enable) {
                this.isClipboardDeactivated = !enable;
                if (enable) {
                    this.clipboard.attr('contenteditable', enable);
                } else {
                    this.clipboard.removeAttr('contenteditable');
                }
            },
            _resize: function () {
                var outerHeight = kendo._outerHeight;
                var tabstripHeight = this.tabstrip ? outerHeight(this.tabstrip.element) : 0;
                var formulaBarHeight = this.formulaBar ? outerHeight(this.formulaBar.element) : 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);
                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) {
                    this.sheetsbar = new kendo.spreadsheet.SheetsBar(this.element.find(DOT + View.classNames.sheetsBar), $.extend(true, {}, this.options.sheetsbar));
                }
            },
            _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;
                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, ref) {
                var rectangle = this._rectangle(pane, ref);
                x -= this._sheet._grid._headerWidth;
                var handleWidth = RESIZE_HANDLE_WIDTH / 2;
                var right = rectangle.right - this.scroller.scrollLeft;
                return right - handleWidth <= x && x <= right + handleWidth;
            },
            isRowResizer: function (y, pane, ref) {
                var rectangle = this._rectangle(pane, ref);
                y -= this._sheet._grid._headerHeight;
                var handleWidth = RESIZE_HANDLE_WIDTH / 2;
                var bottom = rectangle.bottom - this.scroller.scrollTop;
                return bottom - handleWidth <= y && y <= bottom + handleWidth;
            },
            isFilterIcon: function (x, y, pane, ref) {
                var theGrid = pane._grid;
                var scrollTop = theGrid.rows.frozen ? 0 : this.scroller.scrollTop;
                var scrollLeft = theGrid.columns.frozen ? 0 : this.scroller.scrollLeft;
                x -= this._sheet._grid._headerWidth - scrollLeft;
                y -= this._sheet._grid._headerHeight - scrollTop;
                var result = false;
                this._sheet.forEachFilterHeader(ref, function (ref) {
                    if (!result) {
                        var rect = this._rectangle(pane, ref);
                        result = pane.filterIconRect(rect).intersects(x, y);
                    }
                }.bind(this));
                return result;
            },
            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) {
                var ed = this._sheet.activeCellCustomEditor();
                if (ed) {
                    var r = this.activeCellRectangle();
                    if (x > r.right && x <= r.right + 20 && y >= r.top && y <= r.bottom) {
                        return true;
                    }
                }
            },
            objectAt: function (x, y) {
                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 {
                        var row = pane._grid.rows.index(y, this.scroller.scrollTop);
                        var column = pane._grid.columns.index(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) {
                            ref = new CellRef(row, -Infinity);
                            type = this.isRowResizer(y, pane, ref) ? 'rowresizehandle' : 'rowheader';
                        } else if (!selecting && y < grid._headerHeight) {
                            ref = new CellRef(-Infinity, column);
                            type = this.isColumnResizer(x, pane, ref) ? 'columnresizehandle' : 'columnheader';
                        } else if (this.isEditButton(x, y)) {
                            type = 'editor';
                        }
                        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: {
                                property: parse ? 'input' : 'value',
                                value: value
                            }
                        });
                    }
                });
            },
            openDialog: function (name, options) {
                var sheet = this._sheet;
                var ref = sheet.activeCell();
                var range = new kendo.spreadsheet.Range(ref, sheet);
                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);
                    dialog.open(range);
                    return dialog;
                }
            },
            showError: function (options, callback) {
                var errorMessages = this.options.messages.errors;
                if (kendo.spreadsheet.dialogs.registered(options.type)) {
                    var dialogOptions = { close: callback };
                    if (options.type === 'validationError') {
                        dialogOptions = $.extend(dialogOptions, {
                            title: options.title || 'Error',
                            text: options.body ? options.body : errorMessages[options.type]
                        });
                    }
                    this.openDialog(options.type, dialogOptions);
                } else {
                    this.openDialog('message', {
                        title: options.title || 'Error',
                        text: options.body ? options.body : errorMessages[options.type],
                        activate: function (e) {
                            e.sender.dialog().element.find('.k-button').focus();
                        }.bind(this),
                        close: callback
                    });
                }
            },
            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 () {
                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 scrollTop = this.scroller.scrollTop;
                var scrollLeft = this.scroller.scrollLeft;
                if (scrollTop < 0) {
                    scrollTop = 0;
                }
                if (scrollLeft < 0) {
                    scrollLeft = 0;
                }
                var result = this.panes.map(function (pane) {
                    return pane.render(scrollLeft, scrollTop);
                }, this);
                var merged = [];
                merged = Array.prototype.concat.apply(merged, result);
                var topCorner = kendo.dom.element('div', {
                    style: {
                        width: grid._headerWidth + 'px',
                        height: grid._headerHeight + 'px'
                    },
                    className: View.classNames.topCorner
                });
                merged.push(topCorner);
                if (sheet.resizeHandlePosition() && sheet.resizeHintPosition()) {
                    merged.push(this.renderResizeHint());
                }
                this.tree.render(merged);
                if (this.editor.isActive()) {
                    this.editor.toggleTooltip(this.activeCellRectangle());
                } else if (!sheet.selectionInProgress() && !sheet.resizingInProgress() && !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 = 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 primaryMergedCells = {};
                var secondaryMergedCells = {};
                sheet.forEachMergedCell(selection, function (ref) {
                    var topLeft = ref.topLeft;
                    grid.forEach(ref, function (cellRef) {
                        if (topLeft.eq(cellRef)) {
                            primaryMergedCells[cellRef.print()] = ref;
                        } else {
                            secondaryMergedCells[cellRef.print()] = true;
                        }
                    });
                });
                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;
            }
        });
        var paneClassNames = {
            cell: 'k-spreadsheet-cell',
            vaxis: 'k-spreadsheet-vaxis',
            haxis: 'k-spreadsheet-haxis',
            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 (scrollLeft, scrollTop) {
                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());
                children.push(this.renderSelection());
                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)) {
                    var ref = sheet._grid.normalize(sheet.resizeHandlePosition());
                    if (view.ref.intersects(ref)) {
                        if (!sheet.resizeHintPosition()) {
                            children.push(this.renderResizeHandle());
                        }
                    }
                }
                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 vBorders = {}, hBorders = {};
                layout.cells.forEach(function (cell) {
                    var hb = hBorders[cell.col] || (hBorders[cell.col] = {});
                    var vb = vBorders[cell.row] || (vBorders[cell.row] = {});
                    drawCell(cont.children, cell, null, hb, vb, showGridLines);
                });
                return cont;
            },
            renderResizeHandle: function () {
                var sheet = this._sheet;
                var ref = sheet.resizeHandlePosition();
                var rectangle = this._rectangle(ref);
                var classNames = [Pane.classNames.resizeHandle];
                var style;
                if (ref.col !== -Infinity) {
                    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 {
                    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);
                }
                return 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 () {
                var classNames = Pane.classNames;
                var selections = [];
                var activeCellClasses = [classNames.activeCell];
                var selectionClasses = [classNames.selection];
                var sheet = this._sheet;
                var activeCell = sheet.activeCell().toRangeRef();
                var activeFormulaColor = this._activeFormulaColor();
                var selection = sheet.select();
                activeCellClasses = activeCellClasses.concat(activeFormulaColor, this._directionClasses(activeCell));
                selectionClasses = selectionClasses.concat(activeFormulaColor);
                if (sheet.singleCellSelection()) {
                    activeCellClasses.push(classNames.single);
                }
                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._addTable(selections, activeCell, activeCellClasses.join(' '));
                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 hint = kendo.dom.element('span', { className: 'k-tooltip' }, [kendo.dom.text(this._sheet._autoFillHint)]);
                        var rectangle = this._addDiv(autoFillRectangle, ref, cssClass);
                        if (rectangle) {
                            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;
            },
            _addTable: function (collection, ref, className) {
                var self = this;
                var sheet = self._sheet;
                var view = self._currentView;
                if (view.ref.intersects(ref)) {
                    var rectangle = self._rectangle(ref);
                    var ed = self._sheet.activeCellCustomEditor();
                    sheet.forEach(ref.collapse(), function (row, col, cell) {
                        cell.left = rectangle.left;
                        cell.top = rectangle.top;
                        cell.width = rectangle.width;
                        cell.height = rectangle.height;
                        drawCell(collection, cell, className, null, null, true);
                        if (ed) {
                            var btn = kendo.dom.element('div', {
                                className: 'k-button k-spreadsheet-editor-button',
                                style: {
                                    left: cell.left + 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);
            }
        });
        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 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));
                }
                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 = $('<div/>').kendoStaticList({
                        template: '<div>#:value#</div>',
                        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 matrix = context.validation.from.value;
                var data = [];
                if (matrix) {
                    matrix.each(function (el) {
                        data.push({ value: el });
                    });
                }
                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-s'
            };
        });
    }(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 (left, top, width, height) {
                this.left = left;
                this.width = width;
                this.right = left + width;
                this.top = top;
                this.height = height;
                this.bottom = top + 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) {
                return this.left < x && x < this.left + this.width && this.top < y && y < this.top + this.height;
            },
            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 = ref.topLeft;
                var bottomRight = 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);
                }
            },
            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);
                    if (value === this._value) {
                        continue;
                    }
                    var position = positions[idx];
                    if (position === undefined) {
                        position = values.length;
                        var item = { index: idx };
                        item[field] = value;
                        values.push(item);
                        positions[idx] = position;
                    }
                }
                return values;
            },
            fromJSON: function (field, values) {
                for (var idx = 0; idx < values.length; idx++) {
                    var value = values[idx][field];
                    var index = values[idx].index;
                    if (index === undefined) {
                        index = idx;
                    }
                    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, overflow) {
                var end = this._count - 1;
                if (index === end) {
                    return overflow ? index + 1 : index;
                }
                index += 1;
                var range = this._hidden.intersecting(index, index)[0];
                if (range.value !== 0) {
                    if (range.end === end) {
                        return index - 1;
                    } else {
                        return range.end + 1;
                    }
                } else {
                    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, overflow) {
                if (index === 0) {
                    return overflow ? -1 : 0;
                }
                index -= 1;
                var range = this._hidden.intersecting(index, index)[0];
                if (range.value !== 0) {
                    if (range.start === 0) {
                        return index + 1;
                    } else {
                        return range.start - 1;
                    }
                } else {
                    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;
            },
            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;
            },
            _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);
            },
            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 (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',
                    values: this._values.slice(0)
                };
            }
        });
        kendo.spreadsheet.CustomFilter = Filter.extend({
            _logic: 'and',
            init: function (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 (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 (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'
    ], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    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
                    };
                }
            }
        }
        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(/^(am\/pm|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 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 + ') { ';
            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 + '); ';
        }
        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();
        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') {
                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 += '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 CACHE = Object.create(null);
    var TEXT = compileFormatPart({
        cond: 'text',
        body: [{ type: 'text' }]
    });
    function compile(format) {
        var f = CACHE[format];
        if (!f) {
            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; };';
            f = CACHE[format] = new Function('runtime', code)(runtime);
        }
        return f;
    }
    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 += fraction.toFixed(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 += fraction.toFixed(fraclen).replace(/^0+/, '');
            }
            return ret;
        },
        fill: function (ch) {
            return ch;
        },
        formatInt: function (culture, value, parts, declen, sep) {
            value = value.toFixed(declen).replace(/\..*$/, '');
            if (declen > 0) {
                if (value === '0') {
                    value = '';
                } else if (value === '-0') {
                    value = '-';
                }
            }
            var iv = value.length - 1;
            var result = [];
            var len = 0, str;
            function add(ch) {
                if (sep && len && len % 3 === 0 && /^[0-9]$/.test(ch)) {
                    str = culture.numberFormat[','] + str;
                }
                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 {
                        add(value.charAt(iv--));
                    }
                }
                if (j === 0) {
                    while (iv >= 0) {
                        add(value.charAt(iv--));
                    }
                }
                result.unshift(str);
            }
            return result;
        },
        formatDec: function (value, parts, declen) {
            value = value.toFixed(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;
        }
    };
    function padLeft(val, width, ch) {
        val += '';
        while (val.length < width) {
            val = ch + val;
        }
        return val;
    }
    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);
        }
    };
}, 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 Math.min.apply(Math, numbers);
    }).args([
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length > 0',
                'N/A'
            ]
        ]
    ]);
    defineFunction('max', function (numbers) {
        return Math.max.apply(Math, numbers);
    }).args([
        [
            'numbers',
            [
                'collect',
                'number'
            ]
        ],
        [
            '?',
            [
                'assert',
                '$numbers.length > 0',
                'N/A'
            ]
        ]
    ]);
    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 + 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',
                [
                    'and',
                    'number',
                    [
                        'not',
                        'boolean'
                    ]
                ]
            ]
        ],
        [
            '?',
            [
                '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) {
        var date = new Date(year,month,date);
        return packDate(date.getFullYear(),date.getMonth()-1,date.getDate());
    }).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 = '$#,##0.DECIMALS;($#,##0.DECIMALS)';
        var dec = '';
        while (decimals-- > 0) {
            dec += '0';
        }
        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 format = noCommas ? '0.DECIMALS' : '#,##0.DECIMALS';
        var dec = '';
        while (decimals-- > 0) {
            dec += '0';
        }
        format = format.replace(/DECIMALS/g, dec);
        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',
                'number',
                1
            ]
        ],
        [
            'array2',
            [
                'collect',
                'number',
                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
                ]
            ]
        ],
        [
            '?',
            [
                'assert',
                '$pmt || $fv'
            ]
        ]
    ]);
    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_) {
        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;
    }
}, 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',
            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\'>' + BORDER_PALETTE_MESSAGES.apply + '</button>' + '<button class=\'k-button\' data-bind=\'click: close\'>' + BORDER_PALETTE_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-font-icon k-i-reset-color\'></span>' + BORDER_PALETTE_MESSAGES.reset + '</a>').appendTo(this.element);
            },
            _customColorButton: function () {
                this.customColorButton = $('<a class=\'k-button k-custom-color\' href=\'#\'>' + '<span class=\'k-icon\'></span>' + BORDER_PALETTE_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] + '" href="#" data-border-type="' + type + '" class="k-button k-button-icon">' + '<span class="k-sprite k-font-icon 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',
            colorPicker: {
                reset: 'Reset color',
                customColor: 'Custom color...'
            },
            copy: 'Copy',
            cut: 'Cut',
            deleteColumn: 'Delete column',
            deleteRow: 'Delete row',
            filter: 'Filter',
            fontFamily: 'Font',
            fontSize: 'Font size',
            format: 'Custom format...',
            formatTypes: {
                automatic: 'Automatic',
                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'
            },
            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',
            sortAsc: 'Sort ascending',
            sortDesc: 'Sort descending',
            sortButtons: {
                sortSheetAsc: 'Sort sheet A to Z',
                sortSheetDesc: 'Sort sheet Z to A',
                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',
                '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: 'xlsa'
            },
            exportAs: {
                type: 'exportAsDialog',
                dialogName: 'exportAs',
                overflow: 'never',
                text: '',
                iconClass: 'xlsa'
            },
            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: 'decrease-decimal'
            },
            formatIncreaseDecimal: {
                type: 'button',
                command: 'AdjustDecimalsCommand',
                value: +1,
                iconClass: 'increase-decimal'
            },
            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: 'justify-left'
            },
            backgroundColor: {
                type: 'colorPicker',
                property: 'background',
                iconClass: 'background'
            },
            textColor: {
                type: 'colorPicker',
                property: 'color',
                iconClass: 'text'
            },
            fontFamily: {
                type: 'fontFamily',
                property: 'fontFamily',
                iconClass: 'text'
            },
            fontSize: {
                type: 'fontSize',
                property: 'fontSize',
                iconClass: 'font-size'
            },
            format: {
                type: 'format',
                property: 'format',
                iconClass: 'format-number'
            },
            filter: {
                type: 'filter',
                property: 'hasFilter',
                iconClass: 'filter'
            },
            merge: {
                type: 'merge',
                iconClass: 'merge-cells'
            },
            freeze: {
                type: 'freeze',
                iconClass: 'freeze-panes'
            },
            borders: {
                type: 'borders',
                iconClass: 'all-borders'
            },
            formatCells: {
                type: 'dialog',
                dialogName: 'formatCells',
                overflow: 'never'
            },
            hyperlink: {
                type: 'dialog',
                dialogName: 'hyperlink',
                iconClass: 'hyperlink',
                overflow: 'never',
                text: ''
            },
            toggleGridlines: {
                type: 'button',
                command: 'GridLinesChangeCommand',
                property: 'gridLines',
                value: true,
                iconClass: 'no-borders',
                togglable: true
            },
            addColumnLeft: {
                type: 'button',
                command: 'AddColumnCommand',
                value: 'left',
                iconClass: 'add-column-left'
            },
            addColumnRight: {
                type: 'button',
                command: 'AddColumnCommand',
                value: 'right',
                iconClass: 'add-column-right'
            },
            addRowBelow: {
                type: 'button',
                command: 'AddRowCommand',
                value: 'below',
                iconClass: 'add-row-below'
            },
            addRowAbove: {
                type: 'button',
                command: 'AddRowCommand',
                value: 'above',
                iconClass: 'add-row-above'
            },
            deleteColumn: {
                type: 'button',
                command: 'DeleteColumnCommand',
                iconClass: 'delete-column'
            },
            deleteRow: {
                type: 'button',
                command: 'DeleteRowCommand',
                iconClass: 'delete-row'
            },
            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);
                this.bind({
                    click: handleClick,
                    toggle: handleClick
                });
            },
            _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-font-icon k-i-' + options.iconClass;
                    var type = options.type;
                    var typeDefaults = {
                        splitButton: { spriteCssClass: spriteCssClass },
                        button: { showText: 'overflow' },
                        colorPicker: { toolIcon: spriteCssClass }
                    };
                    var tool = $.extend({
                        name: options.name || toolName,
                        text: MESSAGES[options.name || toolName],
                        spriteCssClass: spriteCssClass,
                        attributes: { title: 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') {
                        toggle = toolbar.options.value === value;
                    }
                    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);
                    }
                }
            },
            _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 />').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) {
                    listWidth += 20;
                } else {
                    listWidth = ddl._listWidth;
                }
                list.css('width', listWidth + kendo.support.scrollbar());
                ddl._listWidth = listWidth;
            },
            _change: function (e) {
                var instance = e.sender;
                var value = instance.value();
                var dataItem = instance.dataItem();
                var popupName = dataItem ? dataItem.popup : undefined;
                if (popupName) {
                    this.toolbar.dialog({ name: popupName });
                } else {
                    this.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-s\'></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.element = $('<button class=\'k-button k-button-icon\' title=\'' + options.attributes.title + '\'>' + '<span class=\'k-icon k-font-icon k-i-xls\' />' + '</button>').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 />').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,
            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-font-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.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._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
                });
            },
            buttons: [
                {
                    property: 'textAlign',
                    value: 'left',
                    iconClass: 'justify-left',
                    text: MESSAGES.alignmentButtons.justtifyLeft
                },
                {
                    property: 'textAlign',
                    value: 'center',
                    iconClass: 'justify-center',
                    text: MESSAGES.alignmentButtons.justifyCenter
                },
                {
                    property: 'textAlign',
                    value: 'right',
                    iconClass: 'justify-right',
                    text: MESSAGES.alignmentButtons.justifyRight
                },
                {
                    property: 'textAlign',
                    value: 'justify',
                    iconClass: 'justify-full',
                    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-font-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._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
                });
            },
            buttons: [
                {
                    value: 'cells',
                    iconClass: 'merge-cells',
                    text: MESSAGES.mergeButtons.mergeCells
                },
                {
                    value: 'horizontally',
                    iconClass: 'merge-horizontally',
                    text: MESSAGES.mergeButtons.mergeHorizontally
                },
                {
                    value: 'vertically',
                    iconClass: 'merge-vertically',
                    text: MESSAGES.mergeButtons.mergeVertically
                },
                {
                    value: 'unmerge',
                    iconClass: 'normal-layout',
                    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-font-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._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
                });
            },
            buttons: [
                {
                    value: 'panes',
                    iconClass: 'freeze-panes',
                    text: MESSAGES.freezeButtons.freezePanes
                },
                {
                    value: 'rows',
                    iconClass: 'freeze-row',
                    text: MESSAGES.freezeButtons.freezeRows
                },
                {
                    value: 'columns',
                    iconClass: 'freeze-col',
                    text: MESSAGES.freezeButtons.freezeColumns
                },
                {
                    value: 'unfreeze',
                    iconClass: 'normal-layout',
                    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-font-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-font-icon k-i-' + options.iconClass + '\' style=\'line-height: 1em; width: 1.35em;\'></span>',
                    template: '<span class=\'k-icon k-font-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-font-icon k-i-folder-open\' />' + '</div>').data('instance', this);
                this._title = options.attributes.title;
                this._reset();
            },
            _reset: function () {
                this.element.remove('input');
                $('<input type=\'file\' autocomplete=\'off\' accept=\'.xlsx\'/>').attr('title', 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-large',
                        action: 'undo'
                    },
                    {
                        title: MESSAGES.quickAccess.redo,
                        iconClass: 'redo-large',
                        action: 'redo'
                    }
                ];
                var buttonTemplate = kendo.template('<a href=\'\\#\' title=\'#= title #\' data-action=\'#= action #\' class=\'k-button k-button-icon\'><span class=\'k-icon k-font-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'
                }
            },
            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...',
                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.' },
            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'
                }
            }
        };
        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 = $.extend(true, {}, this.options, options);
                this.bind(this.events, options);
            },
            events: [
                'close',
                'activate'
            ],
            options: { autoFocus: true },
            dialog: function () {
                if (!this._dialog) {
                    this._dialog = $('<div class=\'k-spreadsheet-window k-action-window\' />').addClass(this.options.className || '').append(kendo.template(this.options.template)({ messages: kendo.spreadsheet.messages.dialogs || MESSAGES })).appendTo(document.body).kendoWindow({
                        autoFocus: this.options.autoFocus,
                        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)
                    }).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();
            },
            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, 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-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>'
            },
            _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 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: close\'>' + '#= messages.retry #' + '</button>' + '<button class=\'k-button\' data-bind=\'click: revert\'>' + '#= messages.revert #' + '</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),
                    revert: this.revert.bind(this)
                });
            },
            activate: function (e) {
                e.sender.dialog().element.find('.k-button').focus();
            },
            revert: function () {
                this._action = 'revert';
                this.dialog().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: 'justify-left',
                            text: messages.buttons.justtifyLeft
                        },
                        {
                            property: 'textAlign',
                            value: 'center',
                            iconClass: 'justify-center',
                            text: messages.buttons.justifyCenter
                        },
                        {
                            property: 'textAlign',
                            value: 'right',
                            iconClass: 'justify-right',
                            text: messages.buttons.justifyRight
                        },
                        {
                            property: 'textAlign',
                            value: 'justify',
                            iconClass: 'justify-full',
                            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-font-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: 'merge-cells',
                            text: messages.buttons.mergeCells
                        },
                        {
                            value: 'horizontally',
                            iconClass: 'merge-horizontally',
                            text: messages.buttons.mergeHorizontally
                        },
                        {
                            value: 'vertically',
                            iconClass: 'merge-vertically',
                            text: messages.buttons.mergeVertically
                        },
                        {
                            value: 'unmerge',
                            iconClass: 'normal-layout',
                            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-font-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: 'freeze-panes',
                            text: messages.buttons.freezePanes
                        },
                        {
                            value: 'rows',
                            iconClass: 'freeze-row',
                            text: messages.buttons.freezeRows
                        },
                        {
                            value: 'columns',
                            iconClass: 'freeze-col',
                            text: messages.buttons.freezeColumns
                        },
                        {
                            value: 'unfreeze',
                            iconClass: 'normal-layout',
                            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-font-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" ' + '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" ' + '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 #" 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 #" 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" ' + '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 #" 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" ' + '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 #" 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 #" 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 #" 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 #" 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="showButton" class="k-checkbox" data-bind="checked: showButton"/>' + '<label for="showButton" 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="showButton" class="k-checkbox" data-bind="checked: showButton"/>' + '<label for="showButton" class="k-checkbox-label">' + ' #: messages.validationDialog.labels.showCalendarButton #' + '</label>' + '</div>' + '</div>' + '<div data-bind="invisible: isAny">' + '<div class="k-edit-field">' + '<input type="checkbox" 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-action-buttons"></div>' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.onInvalidData #:</label></div>' + '<div class="k-edit-field">' + '<input type="radio" 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" 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" 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" 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" 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;
        var ExportAsDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.exportAsDialog || MESSAGES;
                SpreadsheetDialog.fn.init.call(this, $.extend({ title: messages.title }, options));
                this.viewModel = kendo.observable({
                    title: this.options.title,
                    name: this.options.name,
                    extension: this.options.extension,
                    fileFormats: this.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: this.options.pdf.fitWidth,
                        area: this.options.pdf.area,
                        areas: this.options.pdf.areas,
                        paperSize: this.options.pdf.paperSize,
                        paperSizes: this.options.pdf.paperSizes,
                        margin: this.options.pdf.margin,
                        margins: this.options.pdf.margins,
                        landscape: this.options.pdf.landscape,
                        guidelines: this.options.pdf.guidelines,
                        hCenter: this.options.pdf.hCenter,
                        vCenter: this.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: {
                name: 'Workbook',
                extension: '.xlsx',
                fileFormats: [
                    {
                        description: 'Excel Workbook (.xlsx)',
                        extension: '.xlsx'
                    },
                    {
                        description: 'Portable Document Format(.pdf)',
                        extension: '.pdf'
                    }
                ],
                pdf: {
                    fitWidth: true,
                    area: 'workbook',
                    areas: [
                        {
                            area: 'workbook',
                            text: 'Entire Workbook'
                        },
                        {
                            area: 'sheet',
                            text: 'Active Sheet'
                        },
                        {
                            area: 'selection',
                            text: 'Selection'
                        }
                    ],
                    paperSize: 'a4',
                    paperSizes: [
                        {
                            value: 'a2',
                            text: 'A2 (420 mm \xD7 594 mm)     '
                        },
                        {
                            value: 'a3',
                            text: 'A3 (297 mm x 420 mm)     '
                        },
                        {
                            value: 'a4',
                            text: 'A4 (210 mm x 297 mm)     '
                        },
                        {
                            value: 'a5',
                            text: 'A5 (148 mm x 210 mm)     '
                        },
                        {
                            value: 'b3',
                            text: 'B3 (353 mm \xD7 500 mm)     '
                        },
                        {
                            value: 'b4',
                            text: 'B4 (250 mm x 353 mm)     '
                        },
                        {
                            value: 'b5',
                            text: 'B5 (176 mm x 250 mm)     '
                        },
                        {
                            value: 'folio',
                            text: 'Folio (8.5" x 13")       '
                        },
                        {
                            value: 'legal',
                            text: 'Legal (8.5" x 14")       '
                        },
                        {
                            value: 'letter',
                            text: 'Letter (8.5" x 11")      '
                        },
                        {
                            value: 'tabloid',
                            text: 'Tabloid (11" x 17")      '
                        },
                        {
                            value: 'executive',
                            text: 'Executive (7.25" x 10.5")'
                        }
                    ],
                    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: 'Normal'
                        },
                        {
                            value: {
                                bottom: '0.75in',
                                left: '0.25in',
                                right: '0.25in',
                                top: '0.75in'
                            },
                            text: 'Narrow'
                        },
                        {
                            value: {
                                bottom: '1in',
                                left: '1in',
                                right: '1in',
                                top: '1in'
                            },
                            text: '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=\'export-config\' data-bind=\'visible: showPdfOptions\'>' + '<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\'>' + '<input type=\'radio\' id=\'k-orientation-portrait\' name=\'orientation\' data-type=\'boolean\' data-bind=\'checked: pdf.landscape\' value=\'false\' /><label class=\'k-orientation-label k-orientation-portrait-label\' for=\'k-orientation-portrait\'></label>' + '<input type=\'radio\' id=\'k-orientation-landscape\' name=\'orientation\' data-type=\'boolean\' data-bind=\'checked: pdf.landscape\' value=\'true\' /><label class=\'k-orientation-label k-orientation-landscape-label\' for=\'k-orientation-landscape\'></label>' + '</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\' data-bind=\'css: {k-page-landscape: pdf.landscape}\'>' + '<div class=\'k-margins-horizontal\'></div>' + '<div class=\'k-margins-vertical\'></div>' + '</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('overflow', 'overflowDialog.errorMessage');
        basicErrorDialog('unsupportedSelection', 'unsupportedSelectionDialog.errorMessage');
        basicErrorDialog('incompatibleRanges', 'incompatibleRangesDialog.errorMessage');
        basicErrorDialog('noFillDirection', 'noFillDirectionDialog.errorMessage');
        basicErrorDialog('duplicateSheetName', 'duplicateSheetNameDialog.errorMessage');
        var UseKeyboardDialog = MessageDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.useKeyboardDialog || MESSAGES;
                SpreadsheetDialog.fn.init.call(this, $.extend({ title: messages.title }, options));
            },
            options: { 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: {
                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\' /></div>' + '<div class=\'k-action-buttons\'>' + ('<button style=\'float: left\' class=\'k-button\' 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>',
                title: MESSAGES.linkDialog.title,
                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);
    }(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 = $.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('deleteRow', this._sheetDeleteRowHandler).bind('insertRow', 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 values = this.sheet.range(e.ref).values();
                    e.ref.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;
                }
                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;
            },
            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 k-font-icon',
            iconCollapse: 'k-i-collapse-se',
            iconExpand: 'k-i-expand-e',
            iconSearch: 'k-i-search',
            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'
        };
        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 });
            }
        });
        var FILTERMENU_MESSAGES = kendo.spreadsheet.messages.filterMenu = {
            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'
                },
                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'
                }
            }
        };
        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-font-icon k-i-search\' />' + '</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-font-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();
            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 anyVisibleChildren = filter(item.children, itemVisible || query);
                hasVisibleChildren = hasVisibleChildren || anyVisibleChildren || itemVisible;
                item.hidden = !itemVisible && !anyVisibleChildren;
                item.checked = !item.hidden;
            }
            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);
                uncheckAll(dataSource);
                filter(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);
                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 = FILTERMENU_MESSAGES.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: 'All',
                        expanded: true,
                        checked: true,
                        items: this.values(range.resize({ top: 1 }), column)
                    }];
            },
            values: function (range, column) {
                var values = [];
                var messages = FILTERMENU_MESSAGES;
                var columnRange = range.column(column);
                var sheet = range.sheet();
                columnRange.forEachCell(function (row, col, cell) {
                    if (sheet.isHiddenRow(row)) {
                        return;
                    }
                    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 = 'number';
                    }
                    if (dataType === 'date') {
                        value = kendo.spreadsheet.numberToDate(value);
                    }
                    values.push({
                        dataType: dataType,
                        value: value,
                        text: text,
                        checked: true
                    });
                });
                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'
                    },
                    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 = FILTERMENU_MESSAGES;
                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: FILTERMENU_MESSAGES,
                    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('focus', this._focus.bind(this));
                this.cellInput.bind('focus', this._focus.bind(this));
                this.barInput.bind('blur', this._blur.bind(this));
                this.cellInput.bind('blur', this._blur.bind(this));
            },
            events: [
                'activate',
                'deactivate',
                'change',
                'update'
            ],
            _focus: function (e) {
                this.lastActive = e.sender == this.barInput ? 'bar' : 'cell';
            },
            _blur: function () {
            },
            _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.cellInput.position(options.rect);
                this.cellInput.resize(options.rect);
                this.cellInput.tooltip(options.tooltip);
                this.cellInput.activeCell = this.barInput.activeCell = options.range.topLeft;
                this.trigger('activate');
                return this;
            },
            deactivate: function () {
                var cellInput = this.cellInput;
                if (!this._active) {
                    return;
                }
                if (cellInput.value() != this._value) {
                    if (this.trigger('change', { value: cellInput.value() })) {
                        return;
                    }
                }
                this._active = false;
                this._rect = null;
                cellInput.hide();
                this.trigger('deactivate');
            },
            enable: function (enable) {
                this.barInput.enable(enable);
                this.cellInput.enable(enable);
            },
            enableEditing: function (enable) {
                this.barInput.enableEditing(enable);
                this.cellInput.enableEditing(enable);
            },
            barElement: function () {
                return this.barInput.element;
            },
            cellElement: function () {
                return this.cellInput.element;
            },
            focusLastActive: function () {
                this.focus(this.lastActive);
            },
            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) {
                if (value === undefined) {
                    return this.barInput.value();
                }
                if (value === null) {
                    value = '';
                }
                this._value = value;
                this.barInput.value(value);
                this.cellInput.value(value);
            },
            insertNewline: function () {
                this.activeEditor().insertNewline();
                this.scale();
            }
        });
        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();
        var dest = destRange._ref.toRangeRef();
        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);
        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;
                a[descending ? n - j - 1 : j] = f(idx, srcIdx);
            }
        }
        if (!horizontal) {
            fill = transpose(fill);
        }
        return {
            props: fill,
            direction: direction,
            dest: destRange
        };
    };
    Range.prototype.fillFrom = function (srcRange, direction) {
        var x = this._previewFillFrom(srcRange, direction);
        x.dest._properties(x.props);
        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);
                if (values.length == 1 && (begin > 0 || end < data.length || formatType(values[0], properties[begin].format) == 'date')) {
                    values.push(values[0] + 1);
                }
                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 formatType(value, format) {
        if (format != null) {
            return spreadsheet.formatting.type(value, format);
        }
    }
    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 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
                    }
                });
                this.combo = $('<input />').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 drawing = kendo.drawing;
    var formatting = spreadsheet.formatting;
    var geo = kendo.geometry;
    var GUIDELINE_WIDTH = 0.8;
    function distributeCoords(heights, pageHeight) {
        var curr = 0;
        var out = [];
        var threshold = 0.2 * pageHeight;
        var bottom = pageHeight;
        heights.forEach(function (h) {
            if (pageHeight && curr + h > bottom) {
                if (bottom - curr < threshold) {
                    curr = pageHeight * Math.ceil(curr / pageHeight);
                }
                bottom += pageHeight * Math.ceil(h / pageHeight);
            }
            out.push(curr);
            curr += h;
        });
        out.push(curr);
        return out;
    }
    function getMergedCells(sheet, range) {
        var grid = sheet._grid;
        var primary = {};
        var secondary = {};
        sheet.forEachMergedCell(range, function (ref) {
            var topLeft = ref.topLeft;
            grid.forEach(ref, function (cellRef) {
                if (topLeft.eq(cellRef)) {
                    primary[cellRef.print()] = ref;
                } else if (range.contains(cellRef)) {
                    secondary[cellRef.print()] = topLeft;
                }
            });
        });
        return {
            primary: primary,
            secondary: secondary
        };
    }
    function doLayout(sheet, range, options) {
        var cells = [];
        var rowHeights = [];
        var colWidths = [];
        var mergedCells = getMergedCells(sheet, 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 (!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;
            }
            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;
            }
            cell.row = relrow;
            cell.col = relcol;
            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 = 1;
        if (options.fitWidth) {
            var width = colWidths.reduce(sum, 0);
            if (width > pageWidth) {
                scaleFactor = pageWidth / width;
                pageWidth /= scaleFactor;
                pageHeight /= scaleFactor;
            }
        }
        var yCoords = distributeCoords(rowHeights, pageHeight || 0);
        var xCoords = distributeCoords(colWidths, pageWidth || 0);
        var boxWidth = 0;
        var boxHeight = 0;
        cells = cells.filter(function (cell) {
            if (cell.empty && (cell.row > maxRow || cell.col > maxCol)) {
                return false;
            }
            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;
            }
            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.height();
                cell.rowspan = ref.width();
                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;
                    cells.push(cell);
                }
            });
        });
        return {
            width: boxWidth,
            height: boxHeight,
            cells: cells.sort(normalOrder),
            scale: scaleFactor,
            xCoords: xCoords,
            yCoords: yCoords
        };
    }
    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.borderTop != null || cell.borderRight != null || cell.borderBottom != null || cell.borderLeft != null || cell.validation != null && !cell.validation.value;
    }
    function normalOrder(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 drawLayout(layout, group, options) {
        var ncols = Math.ceil(layout.width / options.pageWidth);
        var nrows = Math.ceil(layout.height / options.pageHeight);
        var pageWidth = options.pageWidth / layout.scale;
        var pageHeight = options.pageHeight / layout.scale;
        for (var i = 0; i < ncols; ++i) {
            for (var j = 0; j < nrows; ++j) {
                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;
            var cells = layout.cells.filter(function (cell) {
                if (cell.right <= left || cell.left >= right || cell.bottom <= top || cell.top >= bottom) {
                    return false;
                }
                endbottom = Math.max(cell.bottom, endbottom);
                endright = Math.max(cell.right, endright);
                return true;
            });
            if (cells.length > 0) {
                var page = new drawing.Group();
                group.append(page);
                page.clip(drawing.Path.fromRect(new geo.Rect([
                    0,
                    0
                ], [
                    options.pageWidth,
                    options.pageHeight
                ])));
                var content = new drawing.Group();
                page.append(content);
                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 drawing.Path().moveTo(x, top).lineTo(x, endbottom).close().stroke('#999', 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 drawing.Path().moveTo(left, y).lineTo(endright, y).close().stroke('#999', GUIDELINE_WIDTH));
                        }
                    });
                }
                var borders = new drawing.Group();
                cells.forEach(function (cell) {
                    drawCell(cell, content, borders, options);
                });
                content.append(borders);
            }
        }
    }
    function drawCell(cell, content, borders, options) {
        var g = new drawing.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;
                r2d2.origin.y += GUIDELINE_WIDTH / 2;
                r2d2.size.width -= GUIDELINE_WIDTH;
                r2d2.size.height -= GUIDELINE_WIDTH;
            }
            g.append(new drawing.Rect(r2d2).fill(cell.background || '#fff').stroke(null));
        }
        if (cell.borderLeft) {
            borders.append(new drawing.Path().moveTo(cell.left, cell.top).lineTo(cell.left, cell.bottom).close().stroke(cell.borderLeft.color, cell.borderLeft.size));
        }
        if (cell.borderTop) {
            borders.append(new drawing.Path().moveTo(cell.left, cell.top).lineTo(cell.right, cell.top).close().stroke(cell.borderTop.color, cell.borderTop.size));
        }
        if (cell.borderRight) {
            borders.append(new drawing.Path().moveTo(cell.right, cell.top).lineTo(cell.right, cell.bottom).close().stroke(cell.borderRight.color, cell.borderRight.size));
        }
        if (cell.borderBottom) {
            borders.append(new drawing.Path().moveTo(cell.left, cell.bottom).lineTo(cell.right, cell.bottom).close().stroke(cell.borderBottom.color, cell.borderBottom.size));
        }
        var val = cell.value;
        if (val != null) {
            var type = typeof val == 'number' ? 'number' : null;
            var clip = new drawing.Group();
            clip.clip(drawing.Path.fromRect(rect));
            g.append(clip);
            var f;
            if (cell.format) {
                f = formatting.textAndColor(val, cell.format);
                val = f.text;
                if (f.type) {
                    type = f.type;
                }
            } else {
                val += '';
            }
            if (!cell.textAlign) {
                switch (type) {
                case 'number':
                case 'date':
                case 'percent':
                    cell.textAlign = 'right';
                    break;
                case 'boolean':
                    cell.textAlign = 'center';
                    break;
                }
            }
            drawText(val, f && f.color || cell.color || '#000', cell, clip);
        }
    }
    function drawText(text, color, cell, group) {
        var rect_left = cell.left + 2;
        var rect_top = cell.top + 2;
        var rect_width = cell.width - 4;
        var rect_height = cell.height - 4;
        var font = makeFontDef(cell);
        var style = {
            font: font,
            whiteSpace: 'pre'
        };
        var props = {
            font: font,
            fill: { color: color }
        };
        var lines = [], text_height = 0, top = rect_top;
        if (cell.wrap) {
            paraBreak(text, style, rect_width).forEach(function (line) {
                var tmp = new drawing.Text(line.text, [
                    rect_left,
                    top
                ], props);
                top += line.box.height;
                lines.push({
                    el: tmp,
                    box: line.box
                });
            });
            text_height = top - rect_top;
        } else {
            var tmp = new drawing.Text(text, [
                rect_left,
                top
            ], props);
            var box = kendo.util.measureText(text, style);
            lines.push({
                el: tmp,
                box: box
            });
            text_height = box.height;
        }
        var cont = new drawing.Group();
        group.append(cont);
        var vtrans = 0;
        switch (cell.verticalAlign) {
        case 'center':
            vtrans = rect_height - text_height >> 1;
            break;
        case undefined:
        case null:
        case 'bottom':
            vtrans = rect_height - text_height;
            break;
        }
        if (vtrans < 0) {
            vtrans = 0;
        }
        lines.forEach(function (line) {
            cont.append(line.el);
            var htrans = 0;
            var text_width = line.box.width;
            switch (cell.textAlign) {
            case 'center':
                htrans = (rect_width - text_width) / 2;
                break;
            case 'right':
                htrans = rect_width - text_width;
                break;
            }
            if (htrans < 0) {
                htrans = 0;
            }
            if (htrans || vtrans) {
                line.el.transform(geo.Matrix.translate(htrans, vtrans));
            }
            if (cell.underline) {
                var height = cell.fontSize || 12;
                var width = height / 12;
                var path = new drawing.Path({
                    stroke: {
                        width: width,
                        color: color
                    }
                });
                var pos = line.el.position();
                var bottom = pos.y + height + vtrans + 2 * width;
                path.moveTo(pos.x + htrans, bottom).lineTo(pos.x + htrans + text_width, bottom);
                cont.append(path);
            }
        });
    }
    function lineBreak(text, style, width, lines) {
        var len = text.length;
        var start = 0;
        while (start < len) {
            split(start, len, len);
        }
        function split(min, eol, max) {
            var sub = text.substring(start, eol).trim();
            var box = kendo.util.measureText(sub, style);
            if (box.width <= width) {
                if (eol < max - 1) {
                    split(eol, eol + max >> 1, max);
                } else {
                    lines.push({
                        text: sub,
                        box: box
                    });
                    start = eol;
                }
            } else if (min < eol) {
                split(min, min + eol >> 1, eol);
            }
        }
    }
    function paraBreak(text, style, width) {
        var a = text.split(/\r?\n/);
        var lines = [];
        a.forEach(function (text) {
            lineBreak(text, style, width, lines);
        });
        return lines;
    }
    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,
            emptyCells: true,
            fitWidth: false,
            center: false
        }, options);
        var group = new drawing.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;
            pageHeight -= paper.margin.top + paper.margin.bottom;
        }
        options.pageWidth = pageWidth;
        options.pageHeight = pageHeight;
        var layout = doLayout(sheet, sheet._ref(range), options);
        drawLayout(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);
        }
    };
    spreadsheet.draw = {
        doLayout: doLayout,
        drawLayout: drawLayout,
        shouldDrawCell: shouldDrawCell
    };
}, 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 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.refresh();
                this._resizeHandler = function () {
                    this.resize();
                }.bind(this);
                $(window).on('resize' + NS, this._resizeHandler);
            },
            _resize: function () {
                this.refresh({ layout: true });
            },
            _workbookChange: function (e) {
                if (this._autoRefresh) {
                    this.refresh(e);
                }
                if (e.recalc && e.ref) {
                    var range = new kendo.spreadsheet.Range(e.ref, this.activeSheet());
                    this.trigger('change', { range: range });
                }
            },
            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();
                    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();
                }
            },
            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();
                }
            },
            _bindWorkbookEvents: function () {
                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));
            },
            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
                }
            },
            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);
            },
            events: [
                'pdfExport',
                'excelExport',
                'excelImport',
                'change',
                'render'
            ]
        });
        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)();
}));